Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.spi / src / main / java / org / gvsig / fmap / dal / feature / spi / SQLBuilderBase.java @ 44376

History | View | Annotate | Download (101 KB)

1
package org.gvsig.fmap.dal.feature.spi;
2

    
3
import java.text.MessageFormat;
4
import java.util.ArrayList;
5
import java.util.Collections;
6
import java.util.HashMap;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.Objects;
11
import java.util.Set;
12
import org.apache.commons.lang3.StringUtils;
13
import org.apache.commons.lang3.tuple.ImmutablePair;
14
import org.apache.commons.lang3.tuple.Pair;
15
import org.cresques.cts.IProjection;
16
import org.gvsig.expressionevaluator.ExpressionBuilder;
17
import org.gvsig.expressionevaluator.ExpressionBuilder.AbstractValue;
18
import org.gvsig.expressionevaluator.ExpressionBuilder.ClassVisitorFilter;
19
import static org.gvsig.expressionevaluator.ExpressionBuilder.EMPTY_FORMATTER;
20
import org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType;
21
import org.gvsig.expressionevaluator.ExpressionBuilder.Parameter;
22
import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
23
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
24
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
25
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
26
import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
27
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
28
import org.gvsig.expressionevaluator.Formatter;
29
import org.gvsig.fmap.dal.DataStoreParameters;
30
import org.gvsig.fmap.dal.DataTypes;
31
import org.gvsig.fmap.dal.SQLBuilder;
32
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
33
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
34
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
35
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
36
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
37
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
38
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
41
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
42
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
43
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
44
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
45
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
46
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
47
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
48
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
49
import org.gvsig.fmap.geom.Geometry;
50
import org.slf4j.Logger;
51
import org.slf4j.LoggerFactory;
52

    
53
@SuppressWarnings("UseSpecificCatch")
54
public class SQLBuilderBase implements SQLBuilder {
55

    
56
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
57

    
58
    protected SelectBuilder select;
59
    protected UpdateBuilder update;
60
    protected InsertBuilder insert;
61
    protected DeleteBuilder delete;
62
    protected AlterTableBuilder alter_table;
63
    protected CreateTableBuilder create_table;
64
    protected GrantBuilder grant;
65
    protected DropTableBuilder drop_table;
66
    protected UpdateTableStatisticsBuilder update_table_statistics;
67
    protected CreateIndexBuilder create_index;
68
    protected TableNameBuilder table_name;
69

    
70
    protected abstract class AbstractStatementPart extends AbstractValue {
71

    
72
    }
73

    
74
    protected abstract class AbstractStatement extends AbstractStatementPart {
75

    
76
    }
77

    
78
    protected class ColumnDescriptorBase implements ColumnDescriptor {
79

    
80
        private String name;
81
        private int type;
82
        private int type_p;
83
        private int type_s;
84
        private boolean isPk;
85
        private boolean _allowNulls;
86
        private boolean _isAutomatic;
87
        private Object defaultValue;
88
        private int geom_type;
89
        private int geom_subtype;
90
        private Object geom_srsdbcode;
91
        private boolean _isIndexed;
92
        private DataStoreParameters parameters = null;
93

    
94
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
95
            this.name = name;
96
            this.type = type;
97
            this.type_p = -1;
98
            this.type_s = -1;
99
            this.isPk = false;
100
            this._allowNulls = true;
101
            this._isAutomatic = false;
102
            this.defaultValue = defaultValue;
103
            this.geom_type = Geometry.TYPES.GEOMETRY;
104
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
105
            this.geom_srsdbcode = null;
106
            this._isIndexed = false;
107
        }
108

    
109
        public ColumnDescriptorBase(String name, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
110
            this.name = name;
111
            this.type = type;
112
            this.type_p = type_p;
113
            this.type_s = type_s;
114
            this.isPk = isPk;
115
            this._allowNulls = allowNulls;
116
            this._isAutomatic = isAutomatic;
117
            this.defaultValue = defaultValue;
118
            this.geom_type = Geometry.TYPES.GEOMETRY;
119
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
120
            this.geom_srsdbcode = null;
121
            this._isIndexed = isIndexed;
122
        }
123

    
124
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
125
            this.name = name;
126
            this.type = DataTypes.GEOMETRY;
127
            this.type_p = 0;
128
            this.type_s = 0;
129
            this.isPk = false;
130
            this._allowNulls = allowNulls;
131
            this._isAutomatic = false;
132
            this.defaultValue = null;
133
            this.geom_type = geom_type;
134
            this.geom_subtype = geom_subtype;
135
            this.geom_srsdbcode = srs_id(proj);
136
            this._isIndexed = isIndexed;
137
        }
138

    
139
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
140
            this.name = name;
141
            this.type = DataTypes.GEOMETRY;
142
            this.type_p = 0;
143
            this.type_s = 0;
144
            this.isPk = false;
145
            this._allowNulls = allowNulls;
146
            this._isAutomatic = false;
147
            this.defaultValue = null;
148
            this.geom_type = geom_type;
149
            this.geom_subtype = geom_subtype;
150
            this.geom_srsdbcode = srsdbcode;
151
            this._isIndexed = isIndexed;
152
        }
153

    
154
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
155
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
156
            this.type_p = fad.getPrecision();
157
            this.type_s = fad.getSize();
158
            this.isPk = fad.isPrimaryKey();
159
            this._allowNulls = fad.allowNull();
160
            this._isAutomatic = fad.isAutomatic();
161
            this._isIndexed = fad.isIndexed();
162

    
163
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
164
                this.geom_type = fad.getGeomType().getType();
165
                this.geom_subtype = fad.getGeomType().getSubType();
166
                this.geom_srsdbcode = fad.getSRS();
167
            }
168
        }
169
    
170

    
171
        @Override
172
        public String getName() {
173
            return this.name;
174
        }
175

    
176
        @Override
177
        public void setName(String name) {
178
            this.name = name;
179
        }
180

    
181
        @Override
182
        public int getType() {
183
            return this.type;
184
        }
185

    
186
        @Override
187
        public void setType(int type) {
188
            this.type = type;
189
        }
190

    
191
        @Override
192
        public int getPrecision() {
193
            return type_p;
194
        }
195

    
196
        @Override
197
        public void setPrecision(int precision) {
198
            this.type_p = precision;
199
        }
200

    
201
        @Override
202
        public int getSize() {
203
            return type_s;
204
        }
205

    
206
        @Override
207
        public void setSize(int size) {
208
            this.type_s = size;
209
        }
210

    
211
        @Override
212
        public boolean isPrimaryKey() {
213
            return isPk;
214
        }
215

    
216
        @Override
217
        public void setIsPrimaryKey(boolean isPk) {
218
            this.isPk = isPk;
219
        }
220

    
221
        @Override
222
        public boolean allowNulls() {
223
            return _allowNulls;
224
        }
225

    
226
        @Override
227
        public void setAllowNulls(boolean allowNulls) {
228
            this._allowNulls = allowNulls;
229
        }
230

    
231
        @Override
232
        public boolean isAutomatic() {
233
            return _isAutomatic;
234
        }
235

    
236
        @Override
237
        public boolean isIndexed() {
238
            return _isIndexed;
239
        }
240

    
241
        @Override
242
        public void setIsAutomatic(boolean isAutomatic) {
243
            this._isAutomatic = isAutomatic;
244
        }
245

    
246
        @Override
247
        public Object getDefaultValue() {
248
            return defaultValue;
249
        }
250

    
251
        @Override
252
        public void setDefaultValue(Object defaultValue) {
253
            this.defaultValue = defaultValue;
254
        }
255

    
256
        @Override
257
        public int getGeometryType() {
258
            return geom_type;
259
        }
260

    
261
        @Override
262
        public void setGeometryType(int geom_type) {
263
            this.geom_type = geom_type;
264
        }
265

    
266
        @Override
267
        public int getGeometrySubtype() {
268
            return geom_subtype;
269
        }
270

    
271
        @Override
272
        public void setGeometrySubtype(int geom_subtype) {
273
            this.geom_subtype = geom_subtype;
274
        }
275

    
276
        @Override
277
        public Object getGeometrySRSId() {
278
            return geom_srsdbcode;
279
        }
280

    
281
        @Override
282
        public void setGeometrySRSId(Object geom_srsid) {
283
            this.geom_srsdbcode = geom_srsid;
284
        }
285

    
286
        @Override
287
        public boolean isGeometry() {
288
            return this.type == DataTypes.GEOMETRY;
289
        }
290

    
291
        private void setStoreParameters(DataStoreParameters parameters) {
292
            this.parameters = parameters;
293
        }
294

    
295
        @Override
296
        public DataStoreParameters getStoreParameters() {
297
            return this.parameters;
298
        }
299
    }
300

    
301
    public class ColumnBase extends AbstractValue implements Column {
302

    
303
        private String name;
304
        private TableNameBuilder table;
305

    
306
        public ColumnBase(TableNameBuilder table, String name) {
307
            this.name = name;
308
            this.table = table;
309
        }
310

    
311
        @Override
312
        public String name() {
313
            return this.name;
314
        }
315

    
316
        @Override
317
        public TableNameBuilder table() {
318
            return this.table;
319
        }
320

    
321
        @Override
322
        public TableNameBuilder table(TableNameBuilder table) {
323
            this.table = table;
324
            return this.table;
325
        }
326

    
327
        @Override
328
        public String toString() {
329
            return this.toString(EMPTY_FORMATTER);
330
        }
331
        
332
        @Override
333
        public String toString(Formatter<Value> formatter) {
334
            if( formatter!=null && formatter.canApply(this) ) {
335
                return formatter.format(this);
336
            }
337
            if( this.table==null ) {
338
                return as_identifier(this.name);
339
            }
340
            return this.table.toString(formatter) + "." + as_identifier(this.name);
341
        }
342

    
343
        @Override
344
        public int compareTo(Variable o) {
345
            return this.name.compareTo(o.name());
346
        }
347

    
348
        @Override
349
        public boolean equals(Object obj) {
350
            if (!(obj instanceof Variable)) {
351
                return false;
352
            }
353
            return StringUtils.equals(this.toString(), ((Variable) obj).toString());
354
        }
355

    
356
        @Override
357
        public int hashCode() {
358
            int hash = 7;
359
            hash = 37 * hash + Objects.hashCode(this.toString());
360
            return hash;
361
        }
362
    }
363

    
364
    public class TableNameBuilderBase
365
            extends AbstractStatementPart
366
            implements TableNameBuilder {
367

    
368
        public String tableName;
369
        public String schemaName;
370
        private String databaseName;
371

    
372
        public TableNameBuilderBase() {
373
        }
374

    
375
        @Override
376
        public void accept(Visitor visitor, VisitorFilter filter) {
377
            if (filter.accept(this)) {
378
                visitor.visit(this);
379
            }
380
        }
381

    
382
        @Override
383
        public TableNameBuilder database(String name) {
384
            this.databaseName = name;
385
            return this;
386
        }
387

    
388
        @Override
389
        public TableNameBuilder schema(String name) {
390
            if (support_schemas()) {
391
                this.schemaName = name;
392
            }
393
            return this;
394
        }
395

    
396
        @Override
397
        public TableNameBuilder name(String name) {
398
            this.tableName = name;
399
            return this;
400
        }
401

    
402
        @Override
403
        public String getDatabase() {
404
            return this.databaseName;
405
        }
406

    
407
        @Override
408
        public String getSchema() {
409
            return this.schemaName;
410
        }
411

    
412
        @Override
413
        public String getName() {
414
            return this.tableName;
415
        }
416

    
417
        @Override
418
        public boolean has_schema() {
419
            if (!support_schemas()) {
420
                return false;
421
            }
422
            return !StringUtils.isEmpty(this.schemaName);
423
        }
424

    
425
        @Override
426
        public boolean has_database() {
427
            return !StringUtils.isEmpty(this.databaseName);
428
        }
429

    
430
        @Override
431
        public String toString() {
432
            return this.toString(formatter());
433
        }
434

    
435
        @Override
436
        public String toString(Formatter<Value> formatter) {
437
            if (formatter!=null && formatter.canApply(this)) {
438
                return formatter.format(this);
439
            }
440
            if (this.has_database()) {
441
                if (this.has_schema()) {
442
                    return as_identifier(this.databaseName) + "."
443
                            + as_identifier(this.schemaName) + "."
444
                            + as_identifier(this.tableName);
445
                }
446
            } else {
447
                if (this.has_schema()) {
448
                    return as_identifier(this.schemaName) + "."
449
                            + as_identifier(this.tableName);
450
                }
451
            }
452
            return as_identifier(this.tableName);
453
        }
454

    
455
        @Override
456
        public boolean equals(Object obj) {
457
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
458
                return false;
459
            }
460
            TableNameBuilder other = (TableNameBuilder) obj;
461
            if (this.has_database()) {
462
                if (this.has_schema()) {
463
                    return this.databaseName.equals(other.getDatabase()) &&
464
                           this.schemaName.equals(other.getSchema()) &&
465
                           this.tableName.equals(other.getName());
466
                }
467
            } else {
468
                if (this.has_schema()) {
469
                    return this.schemaName.equals(other.getSchema()) &&
470
                           this.tableName.equals(other.getName());
471
                }
472
            }
473
            return this.tableName.equals(other.getName());
474
        }
475

    
476
        @Override
477
        public int hashCode() {
478
            int hash = 7;
479
            hash = 37 * hash + Objects.hashCode(this.toString());
480
            return hash;
481
        }
482

    
483
    }
484

    
485
    public class CountBuilderBase
486
            extends AbstractStatementPart
487
            implements CountBuilder {
488

    
489
        protected Value value;
490
        protected boolean distinct;
491
        protected boolean all;
492

    
493
        public CountBuilderBase() {
494
            this.value = null;
495
            this.distinct = false;
496
            this.all = false;
497
        }
498

    
499
        @Override
500
        public CountBuilder all() {
501
            this.all = true;
502
            return this;
503
        }
504

    
505
        @Override
506
        public CountBuilder column(Value value) {
507
            this.value = value;
508
            return this;
509
        }
510

    
511
        @Override
512
        public CountBuilder distinct() {
513
            this.distinct = true;
514
            return this;
515
        }
516

    
517
        @Override
518
        public String toString() {
519
            return this.toString(formatter());
520
        }
521

    
522
        @Override
523
        public String toString(Formatter formatter) {
524
            if (formatter!=null && formatter.canApply(this)) {
525
                return formatter.format(this);
526
            }
527
            if (this.all) {
528
                return "COUNT(*)";
529
            }
530
            if (this.distinct) {
531
                return MessageFormat.format(
532
                        "COUNT(DISTINCT {0})",
533
                        value.toString(formatter)
534
                );
535
            }
536
            return MessageFormat.format(
537
                    "COUNT({0})",
538
                    value.toString(formatter)
539
            );
540
        }
541

    
542
    }
543

    
544
    protected class JoinBase 
545
            extends AbstractStatementPart
546
            implements StatementPart 
547
        {
548
        protected String type;
549
        protected TableNameBuilder table;
550
        protected Value expression;
551
        
552
        public JoinBase(String type, TableNameBuilder table, Value expression) {
553
            this.type = type;
554
            this.table = table;
555
            this.expression = expression;
556
        }
557

    
558
        @Override
559
        public String toString() {
560
            return this.toString(formatter());
561
        }
562

    
563
        @Override
564
        public String toString(Formatter<Value> formatter) {
565
            if (formatter!=null && formatter.canApply(this)) {
566
                return formatter.format(this);
567
            }
568
            StringBuilder builder = new StringBuilder();
569
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
570
            builder.append(this.type.toUpperCase());
571
            builder.append(" JOIN ");
572
            builder.append(this.table.toString(formatter));
573
            builder.append(" ON ");
574
            builder.append(this.expression.toString(formatter));
575
            return builder.toString();
576
        }
577
        
578
        
579
    }
580
    
581
    public class FromBuilderBase
582
            extends AbstractStatementPart
583
            implements FromBuilder {
584

    
585
        protected TableNameBuilder tableName;
586
        private String subquery;
587
        private String passthrough;
588
        private List<JoinBase> joins;
589

    
590
        public FromBuilderBase() {
591
            this.tableName = null;
592
            this.subquery = null;
593
            this.passthrough = null;
594
            this.joins = null;
595
        }
596

    
597
        @Override
598
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
599
            JoinBase join = createJoin("LEFT", table, expression);
600
            if( this.joins==null ) {
601
                this.joins = new ArrayList<>();
602
            }
603
            this.joins.add(join);
604
            return this;
605
        }
606
        
607
        @Override
608
        public TableNameBuilder table() {
609
            if (tableName == null) {
610
                this.tableName = createTableNameBuilder();
611
            }
612
            return this.tableName;
613
        }
614

    
615
        @Override
616
        public void accept(Visitor visitor, VisitorFilter filter) {
617
            if (filter.accept(this)) {
618
                visitor.visit(this);
619
            }
620
            if (this.tableName != null) {
621
                this.tableName.accept(visitor, filter);
622
            }
623
        }
624

    
625
        @Override
626
        public FromBuilder custom(String passthrough) {
627
            this.passthrough = passthrough;
628
            return this;
629
        }
630

    
631
        @Override
632
        public FromBuilder subquery(String subquery) {
633
            this.subquery = subquery;
634
            return this;
635
        }
636

    
637
        @Override
638
        public String toString() {
639
            return this.toString(formatter());
640
        }
641

    
642
        @Override
643
        public String toString(Formatter<Value> formatter) {
644
            if (formatter!=null && formatter.canApply(this)) {
645
                return formatter.format(this);
646
            }
647
            if (!StringUtils.isEmpty(passthrough)) {
648
                return passthrough;
649
            }
650
            if (!StringUtils.isEmpty(subquery)) {
651
                return "( " + this.subquery + ") as _subquery_alias_ ";
652
            }
653
            if( this.joins==null || this.joins.isEmpty() ) {
654
                return this.tableName.toString(formatter);
655
            }
656
            StringBuilder builder = new StringBuilder();
657
            builder.append(this.tableName.toString(formatter));
658
            for (JoinBase join : this.joins) {
659
                builder.append(" ");
660
                builder.append(join.toString(formatter));
661
            }
662
            return builder.toString();
663
        }
664

    
665
    }
666

    
667
    public class SelectColumnBuilderBase
668
            extends AbstractStatementPart
669
            implements SelectColumnBuilder {
670

    
671
        private Variable name = null;
672
        private String alias = null;
673
        private Value value = null;
674
        private boolean asGeometry = false;
675
        private TableNameBuilder table;
676

    
677
        @Override
678
        public void accept(Visitor visitor, VisitorFilter filter) {
679
            if (filter.accept(this)) {
680
                visitor.visit(this);
681
            }
682
            if (this.name != null) {
683
                this.name.accept(visitor, filter);
684
            }
685
            if (this.value != null) {
686
                this.value.accept(visitor, filter);
687
            }
688
        }
689

    
690
        @Override
691
        public void replace(Value target, Value replacement) {
692
            if (this.name!=null ) {
693
                if( this.name == target) {
694
                    this.name = (Variable) replacement;
695
                }
696
            }
697
            if( this.value!=null ) {
698
                if (this.value == target) {
699
                    this.value = replacement;
700
                } else {
701
                    this.value.replace(target, replacement);
702
                }
703
            }
704
        }
705
        
706
        @Override
707
        public SelectColumnBuilder name(String name) {
708
            return this.name(null, name);
709
        }
710

    
711
        @Override
712
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
713
            String quote = quote_for_identifiers();
714
            if (name.startsWith(quote)) {
715
                // Remove quotes
716
                name = name.substring(1, name.length() - 1);
717
            }
718
            this.name = expression().variable(name);
719
            this.table = table;
720
            this.value = null;
721
            this.asGeometry = false;
722
            return this;
723
        }
724

    
725
        @Override
726
        public SelectColumnBuilder all() {
727
            this.name = null;
728
            this.value = expression().custom("*");
729
            this.asGeometry = false;
730
            return this;
731
        }
732

    
733
        @Override
734
        public SelectColumnBuilder as_geometry() {
735
            this.asGeometry = true;
736
            return this;
737
        }
738

    
739
        @Override
740
        public SelectColumnBuilder value(Value value) {
741
            this.value = value;
742
            this.name = null;
743
            return this;
744
        }
745

    
746
        @Override
747
        public SelectColumnBuilder as(String alias) {
748
            this.alias = alias;
749
            return this;
750
        }
751

    
752
        @Override
753
        public String getName() {
754
            return this.name.name();
755
        }
756

    
757
        @Override
758
        public String getAlias() {
759
            return this.alias;
760
        }
761

    
762
        @Override
763
        public String getValue() {
764
            return this.alias;
765
        }
766

    
767
        @Override
768
        public String toString() {
769
            return this.toString(formatter());
770
        }
771

    
772
        @Override
773
        public String toString(Formatter<Value> formatter) {
774
            if (formatter!=null && formatter.canApply(this)) {
775
                return formatter.format(this);
776
            }
777
            StringBuilder builder = new StringBuilder();
778
            if (this.asGeometry) {
779
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
780
            } else {
781
                if (this.name != null) {
782
                    if( this.table==null ) {
783
                        builder.append(this.name.toString(formatter));
784
                    } else {
785
                        builder.append(this.table.toString(formatter));
786
                        builder.append(".");
787
                        builder.append(this.name.toString(formatter));
788
                    }
789
                } else {
790
                    builder.append(this.value.toString(formatter));
791
                }
792
            }
793
            if (this.alias != null) {
794
                builder.append(" AS ");
795
                builder.append(as_identifier(this.alias));
796
            }
797
            return builder.toString();
798
        }
799
    }
800

    
801
    public class OrderByBuilderBase
802
            extends AbstractStatementPart
803
            implements OrderByBuilder {
804

    
805
        protected String value;
806
        protected String custom;
807
        protected boolean ascending;
808

    
809
        public OrderByBuilderBase() {
810
            this.ascending = true;
811
        }
812

    
813
        @Override
814
        public void accept(Visitor visitor, VisitorFilter filter) {
815
            if (filter.accept(this)) {
816
                visitor.visit(this);
817
            }
818
        }
819

    
820
        @Override
821
        public OrderByBuilder column(String name) {
822
            this.value = name;
823
            return this;
824
        }
825

    
826
        @Override
827
        public OrderByBuilder custom(String order) {
828
            this.custom = order;
829
            return this;
830
        }
831

    
832
        @Override
833
        public OrderByBuilder ascending() {
834
            this.ascending = true;
835
            return this;
836
        }
837

    
838
        @Override
839
        public OrderByBuilder ascending(boolean asc) {
840
            this.ascending = asc;
841
            return this;
842
        }
843

    
844
        @Override
845
        public OrderByBuilder descending() {
846
            this.ascending = false;
847
            return this;
848
        }
849

    
850
        @Override
851
        public String toString() {
852
            return this.toString(formatter());
853
        }
854

    
855
        @Override
856
        public String toString(Formatter<Value> formatter) {
857
            if (formatter!=null && formatter.canApply(this)) {
858
                return formatter.format(this);
859
            }
860
            if (!StringUtils.isEmpty(this.custom)) {
861
                return this.custom;
862
            }
863
            if (this.ascending) {
864
                return as_identifier(this.value) + " ASC";
865
            }
866
            return as_identifier(this.value) + " DESC";
867
        }
868
    }
869

    
870
    public class SelectBuilderBase
871
            extends AbstractStatement
872
            implements SelectBuilder {
873

    
874
        protected FromBuilder from;
875
        protected ExpressionBuilder where;
876
        protected long limit = -1;
877
        protected long offset = -1;
878
        protected List<SelectColumnBuilder> columns;
879
        protected List<OrderByBuilder> order_by;
880
        protected boolean distinct;
881
        protected List<Variable> groupColumn;
882

    
883
        public SelectBuilderBase() {
884
            this.columns = new ArrayList<>();
885
            this.distinct = false;
886
        }
887

    
888
        @Override
889
        public SelectBuilder group_by(Variable... columns) {
890
            if( this.groupColumn==null ) {
891
                this.groupColumn = new ArrayList<>();
892
            }
893
            for (Variable column : columns) {
894
                this.groupColumn.add(column);
895
            }
896
            return this;
897
        }
898

    
899
        @Override
900
        public void accept(Visitor visitor, VisitorFilter filter) {
901
            if (filter.accept(this)) {
902
                visitor.visit(this);
903
            }
904
            for (SelectColumnBuilder column : columns) {
905
                column.accept(visitor, filter);
906
            }
907
            if (this.has_from()) {
908
                this.from.accept(visitor, filter);
909
            }
910
            if (this.has_where()) {
911
                this.where.accept(visitor, filter);
912
            }
913
            if (this.has_order_by()) {
914
                for (OrderByBuilder order : order_by) {
915
                    order.accept(visitor, filter);
916
                }
917
            }
918
        }
919

    
920
        @Override
921
        public void replace(Value target, Value replacement) {
922
            if( this.columns!=null ) {
923
                for (int i = 0; i < columns.size(); i++) {
924
                    SelectColumnBuilder column = columns.get(i);
925
                    if( column == target ) {
926
                        columns.set(i, (SelectColumnBuilder) replacement);
927
                    } else {
928
                        column.replace(target, replacement);
929
                    }
930
                }
931
            }
932
            if (this.has_from()) {
933
                if( this.from == target ) {
934
                    this.from = (FromBuilder) replacement;
935
                } else {
936
                    this.from.replace(target, replacement);
937
                }
938
            }
939
            if (this.has_where()) {
940
                if( this.where == target ) {
941
                    this.where = (ExpressionBuilder) replacement;
942
                } else if( this.where.value() == target ) {
943
                    this.where.value(replacement);
944
                } else {
945
                    this.where.value().replace(target, replacement);
946
                }
947
            }
948
            if (this.has_order_by()) {
949
                for (int i = 0; i < order_by.size(); i++) {
950
                    OrderByBuilder order = order_by.get(i);
951
                    if( order == target ) {
952
                        order_by.set(i, (OrderByBuilder) replacement);
953
                    } else {
954
                        order.replace(target, replacement);
955
                    }
956
                }
957
            }
958
        }
959

    
960
        @Override
961
        public SelectBuilder distinct() {
962
            this.distinct = true;
963
            return this;
964
        }
965

    
966
        @Override
967
        public SelectColumnBuilder column() {
968
            SelectColumnBuilder builder = createSelectColumnBuilder();
969
            this.columns.add(builder);
970
            return builder;
971
        }
972

    
973
        @Override
974
        public boolean has_column(String name) {
975
            for (SelectColumnBuilder column : columns) {
976
                if (name.equals(column.getName())) {
977
                    return true;
978
                }
979
            }
980
            return false;
981
        }
982

    
983
        @Override
984
        public FromBuilder from() {
985
            if (this.from == null) {
986
                this.from = createFromBuilder();
987
            }
988
            return this.from;
989
        }
990

    
991
        @Override
992
        public boolean has_from() {
993
            return this.from != null;
994
        }
995

    
996
        @Override
997
        public ExpressionBuilder where() {
998
            if (this.where == null) {
999
                this.where = createExpressionBuilder();
1000
            }
1001
            return this.where;
1002
        }
1003

    
1004
        @Override
1005
        public boolean has_where() {
1006
            if (this.where == null) {
1007
                return false;
1008
            }
1009
            return this.where.value() != null;
1010
        }
1011

    
1012
        @Override
1013
        public SelectBuilder limit(long limit) {
1014
            this.limit = limit;
1015
            return this;
1016
        }
1017

    
1018
        @Override
1019
        public SelectBuilder limit(Long limit) {
1020
            if (limit == null) {
1021
                this.limit = 0;
1022
            } else {
1023
                this.limit = limit;
1024
            }
1025
            return this;
1026
        }
1027

    
1028
        @Override
1029
        public boolean has_limit() {
1030
            return this.limit > 0;
1031
        }
1032

    
1033
        @Override
1034
        public SelectBuilder offset(long offset) {
1035
            this.offset = offset;
1036
            return this;
1037
        }
1038

    
1039
        @Override
1040
        public boolean has_offset() {
1041
            return this.offset > 0;
1042
        }
1043

    
1044
        @Override
1045
        public OrderByBuilder order_by() {
1046
            if (this.order_by == null) {
1047
                this.order_by = new ArrayList<>();
1048
            }
1049
            OrderByBuilder order = createOrderByBuilder();
1050
            this.order_by.add(order);
1051
            return order;
1052
        }
1053

    
1054
        @Override
1055
        public boolean has_order_by() {
1056
            if (this.order_by == null) {
1057
                return false;
1058
            }
1059
            return !this.order_by.isEmpty();
1060
        }
1061
        
1062
        @Override
1063
        public boolean has_group_by() {
1064
            if (this.groupColumn == null) {
1065
                return false;
1066
            }
1067
            return !this.groupColumn.isEmpty();
1068
        }
1069
        
1070
        protected boolean isValid(StringBuilder message) {
1071
            if (message == null) {
1072
                message = new StringBuilder();
1073
            }
1074
            if (this.has_offset() && !this.has_order_by()) {
1075
                // Algunos gestores de BBDD requieren que se especifique un
1076
                // orden para poder usar OFFSET. Como eso parece buena idea para
1077
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
1078
                // siempre.
1079
                message.append("Can't use OFFSET without an ORDER BY.");
1080
                return false;
1081
            }
1082
            return true;
1083
        }
1084

    
1085
        @Override
1086
        public String toString() {
1087
            return this.toString(formatter());
1088
        }
1089

    
1090
        @Override
1091
        public String toString(Formatter<Value> formatter) {
1092
            if (formatter!=null && formatter.canApply(this)) {
1093
                return formatter.format(this);
1094
            }
1095
            StringBuilder builder = new StringBuilder();
1096
            if (!this.isValid(builder)) {
1097
                throw new IllegalStateException(builder.toString());
1098
            }
1099
            builder.append("SELECT ");
1100
            if (this.distinct) {
1101
                builder.append("DISTINCT ");
1102
            }
1103
            boolean first = true;
1104
            for (SelectColumnBuilder column : columns) {
1105
                if (first) {
1106
                    first = false;
1107
                } else {
1108
                    builder.append(", ");
1109
                }
1110
                builder.append(column.toString(formatter));
1111
            }
1112

    
1113
            if (this.has_from()) {
1114
                builder.append(" FROM ");
1115
                builder.append(this.from.toString(formatter));
1116
            }
1117
            if( this.has_group_by() ) {
1118
                builder.append(" GROUP BY ");
1119
                builder.append(this.groupColumn.get(0).name());
1120
                for (int i = 1; i < groupColumn.size(); i++) {
1121
                    builder.append(", ");
1122
                    builder.append(this.groupColumn.get(i).name());
1123
                }
1124
            }
1125
            if (this.has_where()) {
1126
                builder.append(" WHERE ");
1127
                builder.append(this.where.toString(formatter));
1128
            }
1129

    
1130
            if (this.has_order_by()) {
1131
                builder.append(" ORDER BY ");
1132
                first = true;
1133
                for (OrderByBuilder item : this.order_by) {
1134
                    if (first) {
1135
                        first = false;
1136
                    } else {
1137
                        builder.append(", ");
1138
                    }
1139
                    builder.append(item.toString(formatter));
1140
                }
1141
            }
1142

    
1143
            if (this.has_limit()) {
1144
                builder.append(" LIMIT ");
1145
                builder.append(this.limit);
1146
            }
1147
            if (this.has_offset()) {
1148
                builder.append(" OFFSET ");
1149
                builder.append(this.offset);
1150
            }
1151
            return builder.toString();
1152

    
1153
        }
1154
    }
1155

    
1156
    public class DropTableBuilderBase
1157
            extends AbstractStatement
1158
            implements DropTableBuilder {
1159

    
1160
        protected TableNameBuilder table;
1161

    
1162
        @Override
1163
        public TableNameBuilder table() {
1164
            if (table == null) {
1165
                table = createTableNameBuilder();
1166
            }
1167
            return table;
1168
        }
1169

    
1170
        @Override
1171
        public void accept(Visitor visitor, VisitorFilter filter) {
1172
            if (filter.accept(this)) {
1173
                visitor.visit(this);
1174
            }
1175
            this.table.accept(visitor, filter);
1176
        }
1177

    
1178
        @Override
1179
        public String toString() {
1180
            return this.toString(formatter());
1181
        }
1182

    
1183
        @Override
1184
        public String toString(Formatter<Value> formatter) {
1185
            if (formatter!=null && formatter.canApply(this)) {
1186
                return formatter.format(this);
1187
            }
1188
            StringBuilder builder = new StringBuilder();
1189
            boolean first = true;
1190
            for (String sql : toStrings(formatter)) {
1191
                if (StringUtils.isEmpty(sql)) {
1192
                    continue;
1193
                }
1194
                if (first) {
1195
                    first = false;
1196
                } else {
1197
                    builder.append("; ");
1198
                }
1199
                builder.append(sql);
1200
            }
1201
            return builder.toString();
1202
        }
1203

    
1204
        @Override
1205
        public List<String> toStrings() {
1206
            return this.toStrings(formatter());
1207
        }
1208

    
1209
        @Override
1210
        public List<String> toStrings(Formatter formatter) {
1211
            List<String> sqls = new ArrayList<>();
1212

    
1213
            sqls.add(
1214
                    MessageFormat.format(
1215
                            STMT_DROP_TABLE_table,
1216
                            this.table.toString(formatter)
1217
                    )
1218
            );
1219
            String sql;
1220
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1221
                if (this.table.has_schema()) {
1222
                    sql = MessageFormat.format(
1223
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1224
                            as_string(this.table.getSchema()),
1225
                            as_string(this.table.getName())
1226
                    );
1227
                } else {
1228
                    sql = MessageFormat.format(
1229
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1230
                            as_identifier(this.table.getName())
1231
                    );
1232
                }
1233
                if (!StringUtils.isEmpty(sql)) {
1234
                    sqls.add(sql);
1235
                }
1236
            }
1237
            return sqls;
1238
        }
1239
    }
1240

    
1241
    public class GrantRoleBuilderBase
1242
            extends AbstractStatementPart
1243
            implements GrantRoleBuilder {
1244

    
1245
        protected TableNameBuilder table;
1246
        protected String role;
1247
        protected Set<Privilege> privileges;
1248

    
1249
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1250
            this.table = table;
1251
            this.role = role;
1252
            this.privileges = new HashSet<>();
1253
        }
1254

    
1255
        @Override
1256
        public GrantRoleBuilder privilege(Privilege privilege) {
1257
            privileges.add(privilege);
1258
            return this;
1259
        }
1260

    
1261
        @Override
1262
        public GrantRoleBuilder select() {
1263
            privileges.add(Privilege.SELECT);
1264
            return this;
1265
        }
1266

    
1267
        @Override
1268
        public GrantRoleBuilder update() {
1269
            privileges.add(Privilege.UPDATE);
1270
            return this;
1271
        }
1272

    
1273
        @Override
1274
        public GrantRoleBuilder insert() {
1275
            privileges.add(Privilege.INSERT);
1276
            return this;
1277
        }
1278

    
1279
        @Override
1280
        public GrantRoleBuilder delete() {
1281
            privileges.add(Privilege.DELETE);
1282
            return this;
1283
        }
1284

    
1285
        @Override
1286
        public GrantRoleBuilder truncate() {
1287
            privileges.add(Privilege.TRUNCATE);
1288
            return this;
1289
        }
1290

    
1291
        @Override
1292
        public GrantRoleBuilder reference() {
1293
            privileges.add(Privilege.REFERENCE);
1294
            return this;
1295
        }
1296

    
1297
        @Override
1298
        public GrantRoleBuilder trigger() {
1299
            privileges.add(Privilege.TRIGGER);
1300
            return this;
1301
        }
1302

    
1303
        @Override
1304
        public GrantRoleBuilder all() {
1305
            privileges.add(Privilege.ALL);
1306
            return this;
1307
        }
1308

    
1309
        protected String getPrivilegeName(Privilege privilege) {
1310
            switch (privilege) {
1311
                case DELETE:
1312
                    return "DELETE";
1313
                case INSERT:
1314
                    return "INSERT";
1315
                case REFERENCE:
1316
                    return "REFERENCE";
1317
                case SELECT:
1318
                    return "SELECT";
1319
                case TRIGGER:
1320
                    return "TRIGGER";
1321
                case TRUNCATE:
1322
                    return "TRUNCATE";
1323
                case UPDATE:
1324
                    return "UPDATE";
1325
                case ALL:
1326
                default:
1327
                    return "ALL";
1328
            }
1329
        }
1330

    
1331
        @Override
1332
        public String toString() {
1333
            return this.toString(formatter());
1334
        }
1335

    
1336
        @Override
1337
        public String toString(Formatter<Value> formatter) {
1338
            if (formatter!=null && formatter.canApply(this)) {
1339
                return formatter.format(this);
1340
            }
1341
            StringBuilder builder = new StringBuilder();
1342
            boolean first = true;
1343
            for (Privilege privilege : privileges) {
1344
                if (first) {
1345
                    first = false;
1346
                } else {
1347
                    builder.append(", ");
1348
                }
1349
                builder.append(this.getPrivilegeName(privilege));
1350
            }
1351
            String sql = MessageFormat.format(
1352
                    STMT_GRANT_privileges_ON_table_TO_role,
1353
                    builder.toString(),
1354
                    table.toString(formatter),
1355
                    role
1356
            );
1357
            return sql;
1358
        }
1359
    }
1360

    
1361
    public class GrantBuilderBase
1362
            extends AbstractStatement
1363
            implements GrantBuilder {
1364

    
1365
        protected TableNameBuilder table;
1366
        protected Map<String, GrantRoleBuilder> roles;
1367

    
1368
        public GrantBuilderBase() {
1369
            this.roles = new HashMap<>();
1370
        }
1371

    
1372
        @Override
1373
        public TableNameBuilder table() {
1374
            if (table == null) {
1375
                table = createTableNameBuilder();
1376
            }
1377
            return table;
1378
        }
1379

    
1380
        @Override
1381
        public void accept(Visitor visitor, VisitorFilter filter) {
1382
            if (filter.accept(this)) {
1383
                visitor.visit(this);
1384
            }
1385
            if (this.table != null) {
1386
                this.table.accept(visitor, filter);
1387
            }
1388
        }
1389

    
1390
        @Override
1391
        public GrantRoleBuilder role(String role) {
1392
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1393
            if (roleBuilder == null) {
1394
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1395
                this.roles.put(role, roleBuilder);
1396
            }
1397
            return roleBuilder;
1398
        }
1399

    
1400
        @Override
1401
        public String toString() {
1402
            return this.toString(formatter());
1403
        }
1404

    
1405
        @Override
1406
        public String toString(Formatter<Value> formatter) {
1407
            if (formatter!=null && formatter.canApply(this)) {
1408
                return formatter.format(this);
1409
            }
1410
            StringBuilder builder = new StringBuilder();
1411
            boolean first = true;
1412
            for (String sql : toStrings(formatter)) {
1413
                if (StringUtils.isEmpty(sql)) {
1414
                    continue;
1415
                }
1416
                if (first) {
1417
                    first = false;
1418
                } else {
1419
                    builder.append("; ");
1420
                }
1421
                builder.append(sql);
1422
            }
1423
            return builder.toString();
1424
        }
1425

    
1426
        @Override
1427
        public List<String> toStrings() {
1428
            return this.toStrings(formatter());
1429
        }
1430

    
1431
        @Override
1432
        public List<String> toStrings(Formatter formatter) {
1433
            List<String> sqls = new ArrayList<>();
1434
            for (GrantRoleBuilder role : roles.values()) {
1435
                sqls.add(role.toString(formatter));
1436
            }
1437
            return sqls;
1438
        }
1439
    }
1440

    
1441
    public class UpdateColumnBuilderBase
1442
            extends InsertColumnBuilderBase
1443
            implements UpdateColumnBuilder {
1444

    
1445
        public UpdateColumnBuilderBase() {
1446
            super();
1447
        }
1448

    
1449
        @Override
1450
        public UpdateColumnBuilder name(String name) {
1451
            return (UpdateColumnBuilder) super.name(name);
1452
        }
1453

    
1454
        @Override
1455
        public UpdateColumnBuilder with_value(Value value) {
1456
            return (UpdateColumnBuilder) super.with_value(value);
1457
        }
1458

    
1459
    }
1460

    
1461
    public class UpdateBuilderBase
1462
            extends AbstractStatement
1463
            implements UpdateBuilder {
1464

    
1465
        protected ExpressionBuilder where;
1466
        protected List<UpdateColumnBuilder> columns;
1467
        protected TableNameBuilder table;
1468

    
1469
        public UpdateBuilderBase() {
1470
            this.columns = new ArrayList<>();
1471
        }
1472

    
1473
        @Override
1474
        public void accept(Visitor visitor, VisitorFilter filter) {
1475
            if (filter.accept(this)) {
1476
                visitor.visit(this);
1477
            }
1478
            if (this.table != null) {
1479
                this.table.accept(visitor, filter);
1480
            }
1481
            for (UpdateColumnBuilder column : columns) {
1482
                column.accept(visitor, filter);
1483
            }
1484
            if (this.has_where()) {
1485
                this.where.accept(visitor, filter);
1486
            }
1487
        }
1488

    
1489
        @Override
1490
        public ExpressionBuilder where() {
1491
            if (this.where == null) {
1492
                this.where = createExpressionBuilder();
1493
            }
1494
            return this.where;
1495
        }
1496

    
1497
        @Override
1498
        public TableNameBuilder table() {
1499
            if (table == null) {
1500
                table = createTableNameBuilder();
1501
            }
1502
            return table;
1503
        }
1504

    
1505
        @Override
1506
        public UpdateColumnBuilder column() {
1507
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1508
            this.columns.add(column);
1509
            return column;
1510
        }
1511

    
1512
        @Override
1513
        public boolean has_where() {
1514
            return this.where != null;
1515
        }
1516

    
1517
        @Override
1518
        public String toString() {
1519
            return this.toString(formatter());
1520
        }
1521

    
1522
        @Override
1523
        public String toString(Formatter<Value> formatter) {
1524
            if (formatter!=null && formatter.canApply(this)) {
1525
                return formatter.format(this);
1526
            }
1527
            /*
1528
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1529
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1530
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1531
             * output_expression [ AS output_name ] [, ...] ]
1532
             */
1533
            StringBuilder columnsAndValues = new StringBuilder();
1534

    
1535
            boolean first = true;
1536
            for (UpdateColumnBuilder column : columns) {
1537
                if (first) {
1538
                    first = false;
1539
                } else {
1540
                    columnsAndValues.append(", ");
1541
                }
1542
                columnsAndValues.append(as_identifier(column.getName()));
1543
                columnsAndValues.append(" = ");
1544
                columnsAndValues.append(column.getValue().toString(formatter));
1545
            }
1546

    
1547
            String sql;
1548
            if (this.has_where()) {
1549
                sql = MessageFormat.format(
1550
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1551
                        this.table.toString(formatter),
1552
                        columnsAndValues.toString(),
1553
                        this.where.toString(formatter)
1554
                );
1555
            } else {
1556
                sql = MessageFormat.format(
1557
                        STMT_UPDATE_table_SET_columnsAndValues,
1558
                        this.table.toString(formatter),
1559
                        columnsAndValues.toString()
1560
                );
1561
            }
1562
            return sql;
1563
        }
1564
    }
1565

    
1566
    public class DeleteBuilderBase
1567
            extends AbstractStatement
1568
            implements DeleteBuilder {
1569

    
1570
        protected ExpressionBuilder where;
1571
        protected TableNameBuilder table;
1572

    
1573
        public DeleteBuilderBase() {
1574
        }
1575

    
1576
        @Override
1577
        public void accept(Visitor visitor, VisitorFilter filter) {
1578
            if (filter.accept(this)) {
1579
                visitor.visit(this);
1580
            }
1581
            if (this.table != null) {
1582
                this.table.accept(visitor, filter);
1583
            }
1584
            if (this.has_where()) {
1585
                this.where.accept(visitor, filter);
1586
            }
1587
        }
1588

    
1589
        @Override
1590
        public ExpressionBuilder where() {
1591
            if (this.where == null) {
1592
                this.where = createExpressionBuilder();
1593
            }
1594
            return this.where;
1595
        }
1596

    
1597
        @Override
1598
        public TableNameBuilder table() {
1599
            if (table == null) {
1600
                table = createTableNameBuilder();
1601
            }
1602
            return table;
1603
        }
1604

    
1605
        @Override
1606
        public boolean has_where() {
1607
            return this.where != null;
1608
        }
1609

    
1610
        @Override
1611
        public String toString() {
1612
            return this.toString(formatter());
1613
        }
1614

    
1615
        @Override
1616
        public String toString(Formatter<Value> formatter) {
1617
            if (formatter!=null && formatter.canApply(this)) {
1618
                return formatter.format(this);
1619
            }
1620
            /*
1621
             * DELETE FROM table_name
1622
             * WHERE some_column=some_value; 
1623
             */
1624
            String sql;
1625
            if (this.has_where()) {
1626
                sql = MessageFormat.format(
1627
                        STMT_DELETE_FROM_table_WHERE_expresion,
1628
                        this.table.toString(formatter),
1629
                        this.where.toString(formatter)
1630
                );
1631
            } else {
1632
                sql = MessageFormat.format(
1633
                        STMT_DELETE_FROM_table,
1634
                        this.table.toString(formatter)
1635
                );
1636
            }
1637
            return sql;
1638
        }
1639
    }
1640

    
1641
    public class CreateIndexBuilderBase
1642
            extends AbstractStatement
1643
            implements CreateIndexBuilder {
1644

    
1645
        protected boolean ifNotExist = false;
1646
        protected boolean isUnique = false;
1647
        protected String indexName;
1648
        protected boolean isSpatial = false;
1649
        protected TableNameBuilder table;
1650
        protected final List<String> columns;
1651

    
1652
        public CreateIndexBuilderBase() {
1653
            this.columns = new ArrayList<>();
1654
        }
1655

    
1656
        @Override
1657
        public CreateIndexBuilder unique() {
1658
            this.isUnique = true;
1659
            return this;
1660
        }
1661

    
1662
        @Override
1663
        public CreateIndexBuilder if_not_exist() {
1664
            this.ifNotExist = true;
1665
            return this;
1666
        }
1667

    
1668
        @Override
1669
        public CreateIndexBuilder name(String name) {
1670
            this.indexName = name;
1671
            return this;
1672
        }
1673

    
1674
        @Override
1675
        public CreateIndexBuilder spatial() {
1676
            this.isSpatial = true;
1677
            return this;
1678
        }
1679

    
1680
        @Override
1681
        public CreateIndexBuilder column(String name) {
1682
            this.columns.add(name);
1683
            return this;
1684
        }
1685

    
1686
        @Override
1687
        public TableNameBuilder table() {
1688
            if (table == null) {
1689
                table = createTableNameBuilder();
1690
            }
1691
            return table;
1692
        }
1693

    
1694
        @Override
1695
        public void accept(Visitor visitor, VisitorFilter filter) {
1696
            if (filter.accept(this)) {
1697
                visitor.visit(this);
1698
            }
1699
            if (this.table != null) {
1700
                this.table.accept(visitor, filter);
1701
            }
1702
        }
1703

    
1704
        @Override
1705
        public String toString() {
1706
            return this.toString(formatter());
1707
        }
1708

    
1709
        @Override
1710
        public String toString(Formatter<Value> formatter) {
1711
            if (formatter!=null && formatter.canApply(this)) {
1712
                return formatter.format(this);
1713
            }
1714
            StringBuilder builder = new StringBuilder();
1715
            boolean first = true;
1716
            for (String sql : toStrings(formatter)) {
1717
                if (StringUtils.isEmpty(sql)) {
1718
                    continue;
1719
                }
1720
                if (first) {
1721
                    first = false;
1722
                } else {
1723
                    builder.append("; ");
1724
                }
1725
                builder.append(sql);
1726
            }
1727
            return builder.toString();
1728
        }
1729

    
1730
        @Override
1731
        public List<String> toStrings() {
1732
            return this.toStrings(formatter());
1733
        }
1734

    
1735
        @Override
1736
        public List<String> toStrings(Formatter formatter) {
1737
            StringBuilder builder = new StringBuilder();
1738
            builder.append("CREATE ");
1739
            if (this.isUnique) {
1740
                builder.append("UNIQUE ");
1741
            }
1742
            builder.append("INDEX ");
1743
            if (this.ifNotExist) {
1744
                builder.append("IF NOT EXISTS ");
1745
            }
1746
            builder.append(as_identifier(this.indexName));
1747
            builder.append(" ON ");
1748
            builder.append(this.table.toString(formatter));
1749
            if (this.isSpatial) {
1750
                builder.append(" USING GIST ");
1751
            }
1752
            builder.append(" ( ");
1753
            boolean is_first_column = true;
1754
            for (String column : this.columns) {
1755
                if (is_first_column) {
1756
                    is_first_column = false;
1757
                } else {
1758
                    builder.append(", ");
1759
                }
1760
                builder.append(column);
1761
            }
1762
            builder.append(" )");
1763

    
1764
            List<String> sqls = new ArrayList<>();
1765
            sqls.add(builder.toString());
1766
            return sqls;
1767
        }
1768

    
1769
    }
1770

    
1771
    public class AlterTableBuilderBase
1772
            extends AbstractStatement
1773
            implements AlterTableBuilder {
1774

    
1775
        protected TableNameBuilder table;
1776
        protected List<String> drops;
1777
        protected List<ColumnDescriptor> adds;
1778
        protected List<ColumnDescriptor> alters;
1779
        protected List<Pair<String, String>> renames;
1780

    
1781
        public AlterTableBuilderBase() {
1782
            this.drops = new ArrayList<>();
1783
            this.adds = new ArrayList<>();
1784
            this.alters = new ArrayList<>();
1785
            this.renames = new ArrayList<>();
1786
        }
1787

    
1788
        @Override
1789
        public boolean isEmpty() {
1790
            return this.drops.isEmpty()
1791
                    && this.adds.isEmpty()
1792
                    && this.alters.isEmpty()
1793
                    && this.renames.isEmpty();
1794
        }
1795

    
1796
        @Override
1797
        public void accept(Visitor visitor, VisitorFilter filter) {
1798
            if (filter.accept(this)) {
1799
                visitor.visit(this);
1800
            }
1801
            if (this.table != null) {
1802
                this.table.accept(visitor, filter);
1803
            }
1804
        }
1805

    
1806
        @Override
1807
        public TableNameBuilder table() {
1808
            if (table == null) {
1809
                table = createTableNameBuilder();
1810
            }
1811
            return table;
1812
        }
1813

    
1814
        @Override
1815
        public AlterTableBuilder drop_column(String columnName) {
1816
            this.drops.add(columnName);
1817
            return this;
1818
        }
1819

    
1820
        @Override
1821
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1822
            this.adds.add(new ColumnDescriptorBase(fad));
1823
            return this;
1824
        }
1825

    
1826
        @Override
1827
        public AlterTableBuilder add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1828
            if (isPk || isAutomatic) {
1829
                allowNulls = false;
1830
            }
1831
            this.adds.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1832
            return this;
1833
        }
1834

    
1835
        @Override
1836
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1837
            if (StringUtils.isEmpty(columnName)) {
1838
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1839
            }
1840
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1841
            return this;
1842
        }
1843

    
1844
        @Override
1845
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1846
            if (StringUtils.isEmpty(columnName)) {
1847
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1848
            }
1849
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1850
            return this;
1851
        }
1852

    
1853
        @Override
1854
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1855
            this.alters.add(new ColumnDescriptorBase(fad));
1856
            return this;
1857
        }
1858

    
1859
        @Override
1860
        public AlterTableBuilder alter_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1861
            if (isPk || isAutomatic) {
1862
                allowNulls = false;
1863
            }
1864
            this.alters.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1865
            return this;
1866
        }
1867

    
1868
        @Override
1869
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1870
            if (StringUtils.isEmpty(columnName)) {
1871
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1872
            }
1873
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1874
            return this;
1875
        }
1876

    
1877
        @Override
1878
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1879
            if (StringUtils.isEmpty(columnName)) {
1880
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1881
            }
1882
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1883
            return this;
1884
        }
1885

    
1886
        @Override
1887
        public AlterTableBuilder rename_column(String source, String target) {
1888
            this.renames.add(new ImmutablePair(source, target));
1889
            return this;
1890
        }
1891

    
1892
        @Override
1893
        public String toString() {
1894
            return this.toString(formatter());
1895
        }
1896

    
1897
        @Override
1898
        public String toString(Formatter<Value> formatter) {
1899
            if (formatter!=null && formatter.canApply(this)) {
1900
                return formatter.format(this);
1901
            }
1902
            StringBuilder builder = new StringBuilder();
1903
            boolean first = true;
1904
            for (String sql : toStrings(formatter)) {
1905
                if (StringUtils.isEmpty(sql)) {
1906
                    continue;
1907
                }
1908
                if (first) {
1909
                    first = false;
1910
                } else {
1911
                    builder.append("; ");
1912
                }
1913
                builder.append(sql);
1914
            }
1915
            return builder.toString();
1916
        }
1917

    
1918
        @Override
1919
        public List<String> toStrings() {
1920
            return this.toStrings(formatter());
1921
        }
1922

    
1923
        @Override
1924
        public List<String> toStrings(Formatter formatter) {
1925
            List<String> sqls = new ArrayList<>();
1926
            if (this.isEmpty()) {
1927
                return sqls;
1928
            }
1929
            for (String column : drops) {
1930
                StringBuilder builder = new StringBuilder();
1931
                builder.append("ALTER TABLE ");
1932
                builder.append(this.table.toString(formatter));
1933
                builder.append(" DROP COLUMN IF EXISTS ");
1934
                builder.append(as_identifier(column));
1935
                sqls.add(builder.toString());
1936
            }
1937
            for (ColumnDescriptor column : adds) {
1938
                StringBuilder builder = new StringBuilder();
1939
                builder.append("ALTER TABLE ");
1940
                builder.append(this.table.toString(formatter));
1941
                builder.append(" ADD COLUMN ");
1942
                builder.append(as_identifier(column.getName()));
1943
                builder.append(" ");
1944
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1945
                    builder.append(" SERIAL");
1946
                } else {
1947
                    builder.append(
1948
                            sqltype(
1949
                                    column.getType(),
1950
                                    column.getPrecision(),
1951
                                    column.getSize(),
1952
                                    column.getGeometryType(),
1953
                                    column.getGeometrySubtype()
1954
                            )
1955
                    );
1956
                }
1957
                if (column.getDefaultValue() == null) {
1958
                    if (column.allowNulls()) {
1959
                        builder.append(" DEFAULT NULL");
1960
                    }
1961
                } else {
1962
                    builder.append(" DEFAULT '");
1963
                    builder.append(Objects.toString(column.getDefaultValue(),""));
1964
                    builder.append("'");
1965
                }
1966
                if (column.allowNulls()) {
1967
                    builder.append(" NULL");
1968
                } else {
1969
                    builder.append(" NOT NULL");
1970
                }
1971
                if (column.isPrimaryKey()) {
1972
                    builder.append(" PRIMARY KEY");
1973
                }
1974
                sqls.add(builder.toString());
1975
            }
1976
            for (ColumnDescriptor column : alters) {
1977
                StringBuilder builder = new StringBuilder();
1978
                builder.append("ALTER TABLE ");
1979
                builder.append(this.table.toString(formatter));
1980
                builder.append(" ALTER COLUMN ");
1981
                builder.append(as_identifier(column.getName()));
1982
                builder.append(" SET DATA TYPE ");
1983
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1984
                    builder.append(" SERIAL");
1985
                } else {
1986
                    builder.append(
1987
                            sqltype(
1988
                                    column.getType(),
1989
                                    column.getPrecision(),
1990
                                    column.getSize(),
1991
                                    column.getGeometryType(),
1992
                                    column.getGeometrySubtype()
1993
                            )
1994
                    );
1995
                }
1996
                if (column.getDefaultValue() == null) {
1997
                    if (column.allowNulls()) {
1998
                        builder.append(" DEFAULT NULL");
1999
                    } else {
2000
                        builder.append(" DROP DEFAULT");
2001
                    }
2002
                } else {
2003
                    builder.append(" DEFAULT '");
2004
                    builder.append(column.getDefaultValue().toString());
2005
                    builder.append("'");
2006
                }
2007
                sqls.add(builder.toString());
2008
            }
2009
            for (Pair<String, String> pair : renames) {
2010
                StringBuilder builder = new StringBuilder();
2011
                builder.append("ALTER TABLE ");
2012
                builder.append(this.table.toString(formatter));
2013
                builder.append(" RENAME COLUMN ");
2014
                builder.append(as_identifier(pair.getLeft()));
2015
                builder.append(" TO ");
2016
                builder.append(as_identifier(pair.getRight()));
2017
                sqls.add(builder.toString());
2018
            }
2019
            return sqls;
2020
        }
2021

    
2022
    }
2023

    
2024
    public class CreateTableBuilderBase
2025
            extends AbstractStatement
2026
            implements CreateTableBuilder {
2027

    
2028
        protected TableNameBuilder table;
2029
        protected List<ColumnDescriptor> columns;
2030

    
2031
        public CreateTableBuilderBase() {
2032
            this.columns = new ArrayList<>();
2033
        }
2034

    
2035
        @Override
2036
        public void accept(Visitor visitor, VisitorFilter filter) {
2037
            if (filter.accept(this)) {
2038
                visitor.visit(this);
2039
            }
2040
            if (this.table != null) {
2041
                this.table.accept(visitor, filter);
2042
            }
2043
        }
2044

    
2045
        @Override
2046
        public TableNameBuilder table() {
2047
            if (table == null) {
2048
                table = createTableNameBuilder();
2049
            }
2050
            return table;
2051
        }
2052

    
2053
        @Override
2054
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2055
            this.columns.add(new ColumnDescriptorBase(fad));
2056
            return this;
2057
        }
2058

    
2059
        @Override
2060
        public CreateTableBuilderBase add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2061
            if (StringUtils.isEmpty(columnName)) {
2062
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2063
            }
2064
            if (isPk || isAutomatic) {
2065
                allowNulls = false;
2066
            }
2067
            this.columns.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2068
            return this;
2069
        }
2070

    
2071
        @Override
2072
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2073
            if (StringUtils.isEmpty(columnName)) {
2074
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2075
            }
2076
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2077
            return this;
2078
        }
2079

    
2080
        @Override
2081
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2082
            if (StringUtils.isEmpty(columnName)) {
2083
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2084
            }
2085
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2086
            return this;
2087
        }
2088

    
2089
        @Override
2090
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2091
            if (StringUtils.isEmpty(columnName)) {
2092
                return null;
2093
            }
2094
            for (ColumnDescriptor column : columns) {
2095
                if (columnName.equals(column.getName())) {
2096
                    return column;
2097
                }
2098
            }
2099
            return null;
2100
        }
2101

    
2102
        @Override
2103
        public String toString() {
2104
            return this.toString(formatter());
2105
        }
2106

    
2107
        @Override
2108
        public String toString(Formatter<Value> formatter) {
2109
            if (formatter!=null && formatter.canApply(this)) {
2110
                return formatter.format(this);
2111
            }
2112
            StringBuilder builder = new StringBuilder();
2113
            boolean first = true;
2114
            for (String sql : toStrings(formatter)) {
2115
                if (StringUtils.isEmpty(sql)) {
2116
                    continue;
2117
                }
2118
                if (first) {
2119
                    first = false;
2120
                } else {
2121
                    builder.append("; ");
2122
                }
2123
                builder.append(sql);
2124
            }
2125
            return builder.toString();
2126
        }
2127

    
2128
        @Override
2129
        public List<String> toStrings() {
2130
            return this.toStrings(formatter());
2131
        }
2132

    
2133
        @Override
2134
        public List<String> toStrings(Formatter formatter) {
2135
            List<String> sqls = new ArrayList<>();
2136
            /**
2137
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2138
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2139
             * column_constraint [ ... ] ] | table_constraint | LIKE
2140
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2141
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2142
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2143
             *
2144
             * where column_constraint is:
2145
             *
2146
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2147
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2148
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2149
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2150
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2151
             *
2152
             * and table_constraint is:
2153
             *
2154
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2155
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2156
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2157
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2158
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2159
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2160
             */
2161
            StringBuilder builder = new StringBuilder();
2162

    
2163
            builder.append("CREATE TABLE ");
2164
            builder.append(this.table.toString(formatter));
2165
            builder.append(" (");
2166
            boolean first = true;
2167
            for (ColumnDescriptor column : columns) {
2168
                if (first) {
2169
                    first = false;
2170
                } else {
2171
                    builder.append(", ");
2172
                }
2173
                builder.append(as_identifier(column.getName()));
2174
                builder.append(" ");
2175
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2176
                    builder.append("SERIAL");
2177
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2178
                    builder.append("BIGSERIAL");
2179
                } else {
2180
                    builder.append(sqltype(
2181
                            column.getType(),
2182
                            column.getPrecision(),
2183
                            column.getSize(),
2184
                            column.getGeometryType(),
2185
                            column.getGeometrySubtype()
2186
                    )
2187
                    );
2188
                }
2189
                if (column.getDefaultValue() == null) {
2190
                    if (column.allowNulls()) {
2191
                        builder.append(" DEFAULT NULL");
2192
                    }
2193
                } else {
2194
                    builder.append(" DEFAULT '");
2195
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2196
                    builder.append("'");
2197
                }
2198
                if (column.allowNulls()) {
2199
                    builder.append(" NULL");
2200
                } else {
2201
                    builder.append(" NOT NULL");
2202
                }
2203
                if (column.isPrimaryKey()) {
2204
                    builder.append(" PRIMARY KEY");
2205
                }
2206
            }
2207
            builder.append(" )");
2208
            sqls.add(builder.toString());
2209
            return sqls;
2210
        }
2211
    }
2212

    
2213
    public class InsertColumnBuilderBase
2214
            extends AbstractStatement
2215
            implements InsertColumnBuilder {
2216

    
2217
        protected Variable name;
2218
        protected Value value;
2219

    
2220
        public InsertColumnBuilderBase() {
2221
        }
2222

    
2223
        @Override
2224
        public void accept(Visitor visitor, VisitorFilter filter) {
2225
            if (filter.accept(this)) {
2226
                visitor.visit(this);
2227
            }
2228
            if (this.name != null) {
2229
                this.name.accept(visitor, filter);
2230
            }
2231
            if (this.value != null) {
2232
                this.value.accept(visitor, filter);
2233
            }
2234
        }
2235

    
2236
        @Override
2237
        public InsertColumnBuilder name(String name) {
2238
            this.name = expression().variable(name);
2239
            return this;
2240
        }
2241

    
2242
        @Override
2243
        public InsertColumnBuilder with_value(Value value) {
2244
            this.value = value;
2245
            return this;
2246
        }
2247

    
2248
        @Override
2249
        public String getName() {
2250
            return this.name.name();
2251
        }
2252

    
2253
        @Override
2254
        public Value getValue() {
2255
            return this.value;
2256
        }
2257

    
2258
        @Override
2259
        public String toString() {
2260
            return this.toString(formatter());
2261
        }
2262

    
2263
        @Override
2264
        public String toString(Formatter<Value> formatter) {
2265
            if (formatter!=null && formatter.canApply(this)) {
2266
                return formatter.format(this);
2267
            }
2268
            return this.value.toString(formatter);
2269
        }
2270
    }
2271

    
2272
    public class InsertBuilderBase
2273
            extends AbstractStatement
2274
            implements InsertBuilder {
2275

    
2276
        protected List<InsertColumnBuilder> columns;
2277
        protected TableNameBuilder table;
2278

    
2279
        public InsertBuilderBase() {
2280
            this.columns = new ArrayList<>();
2281
        }
2282

    
2283
        @Override
2284
        public void accept(Visitor visitor, VisitorFilter filter) {
2285
            if (filter.accept(this)) {
2286
                visitor.visit(this);
2287
            }
2288
            if (this.table != null) {
2289
                this.table.accept(visitor, filter);
2290
            }
2291
            for (InsertColumnBuilder column : columns) {
2292
                column.accept(visitor, filter);
2293
            }
2294
        }
2295

    
2296
        @Override
2297
        public TableNameBuilder table() {
2298
            if (table == null) {
2299
                table = createTableNameBuilder();
2300
            }
2301
            return table;
2302
        }
2303

    
2304
        @Override
2305
        public InsertColumnBuilder column() {
2306
            InsertColumnBuilder column = createInsertColumnBuilder();
2307
            this.columns.add(column);
2308
            return column;
2309
        }
2310

    
2311
        @Override
2312
        public String toString() {
2313
            return this.toString(formatter());
2314
        }
2315

    
2316
        @Override
2317
        public String toString(Formatter<Value> formatter) {
2318
            if (formatter!=null && formatter.canApply(this)) {
2319
                return formatter.format(this);
2320
            }
2321
            /*
2322
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2323
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2324
             * output_expression [ AS output_name ] [, ...] ]
2325
             */
2326
            StringBuilder builderColumns = new StringBuilder();
2327
            StringBuilder builderValues = new StringBuilder();
2328

    
2329
            boolean first = true;
2330
            for (InsertColumnBuilder column : columns) {
2331
                if (first) {
2332
                    first = false;
2333
                } else {
2334
                    builderColumns.append(", ");
2335
                }
2336
                builderColumns.append(as_identifier(column.getName()));
2337
            }
2338
            first = true;
2339
            for (InsertColumnBuilder column : columns) {
2340
                if (first) {
2341
                    first = false;
2342
                } else {
2343
                    builderValues.append(", ");
2344
                }
2345
                builderValues.append(column.toString(formatter));
2346
            }
2347

    
2348
            String sql = MessageFormat.format(
2349
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2350
                    this.table.toString(formatter),
2351
                    builderColumns.toString(),
2352
                    builderValues.toString()
2353
            );
2354
            return sql;
2355

    
2356
        }
2357
    }
2358

    
2359
    public class UpdateTableStatisticsBuilderBase
2360
            extends AbstractStatement
2361
            implements UpdateTableStatisticsBuilder {
2362

    
2363
        protected TableNameBuilder table;
2364

    
2365
        @Override
2366
        public void accept(Visitor visitor, VisitorFilter filter) {
2367
            if (filter.accept(this)) {
2368
                visitor.visit(this);
2369
            }
2370
            if (this.table != null) {
2371
                this.table.accept(visitor, filter);
2372
            }
2373
        }
2374

    
2375
        @Override
2376
        public TableNameBuilder table() {
2377
            if (table == null) {
2378
                table = createTableNameBuilder();
2379
            }
2380
            return table;
2381
        }
2382

    
2383
        @Override
2384
        public String toString() {
2385
            return this.toString(formatter());
2386
        }
2387

    
2388
        @Override
2389
        public String toString(Formatter<Value> formatter) {
2390
            if (formatter!=null && formatter.canApply(this)) {
2391
                return formatter.format(this);
2392
            }
2393
            StringBuilder builder = new StringBuilder();
2394
            boolean first = true;
2395
            for (String sql : toStrings(formatter)) {
2396
                if (StringUtils.isEmpty(sql)) {
2397
                    continue;
2398
                }
2399
                if (first) {
2400
                    first = false;
2401
                } else {
2402
                    builder.append("; ");
2403
                }
2404
                builder.append(sql);
2405
            }
2406
            return builder.toString();
2407
        }
2408

    
2409
        @Override
2410
        public List<String> toStrings() {
2411
            return this.toStrings(formatter());
2412
        }
2413

    
2414
        @Override
2415
        public List<String> toStrings(Formatter formatter) {
2416
            List<String> sqls = new ArrayList<>();
2417

    
2418
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2419
                String sql = MessageFormat.format(
2420
                        STMT_UPDATE_TABLE_STATISTICS_table,
2421
                        table.toString(formatter)
2422
                );
2423
                if (!StringUtils.isEmpty(sql)) {
2424
                    sqls.add(sql);
2425
                }
2426
            }
2427
            return sqls;
2428
        }
2429
    }
2430

    
2431
    protected ExpressionBuilder expressionBuilder;
2432

    
2433
    protected String defaultSchema;
2434
    protected boolean supportSchemas;
2435
    protected boolean hasSpatialFunctions;
2436
    protected GeometrySupportType geometrySupportType;
2437
    protected boolean allowAutomaticValues;
2438

    
2439
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2440

    
2441
    protected String constant_true = "(1=1)";
2442
    protected String constant_false = "(1<>1)";
2443

    
2444
    protected String type_boolean = "BOOLEAN";
2445
    protected String type_byte = "TINYINT";
2446
    protected String type_bytearray = "BYTEA";
2447
    protected String type_geometry = "TEXT";
2448
    protected String type_char = "CHARACTER(1)";
2449
    protected String type_date = "DATE";
2450
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2451
    protected String type_numeric_p = "NUMERIC({0,Number,#######})";
2452
    protected String type_numeric_ps = "NUMERIC({0,Number,#######},{1,Number,#######})";
2453
    protected String type_bigdecimal = "NUMERIC({0,Number,#######},{1,Number,#######})";
2454
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2455
    protected String type_int = "INT";
2456
    protected String type_long = "BIGINT";
2457
    protected String type_string = "TEXT";
2458
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2459
    protected String type_time = "TIME";
2460
    protected String type_timestamp = "TIMESTAMP";
2461
    protected String type_version = "VARCHAR(30)";
2462
    protected String type_URI = "TEXT";
2463
    protected String type_URL = "TEXT";
2464
    protected String type_FILE = "TEXT";
2465
    protected String type_FOLDER = "TEXT";
2466

    
2467
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2468
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2469
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2470
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2471
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2472
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2473
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2474
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2475
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2476
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2477

    
2478
    public SQLBuilderBase() {
2479
        this.expressionBuilder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2480

    
2481
        this.hasSpatialFunctions = false;
2482
        this.supportSchemas = true;
2483
        this.geometrySupportType = GeometrySupportType.WKT;
2484

    
2485
        this.defaultSchema = "public";
2486
        this.allowAutomaticValues = true;
2487

    
2488
    }
2489
    
2490
    @Override
2491
    public void setProperties(Class filter, final Object... values) {
2492
        this.accept(new Visitor() {
2493
            @Override
2494
            public void visit(Visitable v) {
2495
                for (int i = 0; i < values.length; i+=2) {
2496
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2497
                }
2498
            }
2499
        }, new ClassVisitorFilter(filter) );
2500
    }
2501

    
2502
    public String quote_for_identifiers() {
2503
        return "\"";
2504
    }
2505

    
2506
    public String quote_for_strings() {
2507
        return "'";
2508
    }
2509

    
2510
    @Override
2511
    public String as_identifier(String id) {
2512
        String quote = this.quote_for_identifiers();
2513
//        No se porque no esta disponible wrapIfMissing
2514
//        return StringUtils.wrapIfMissing(id,quote);
2515
        if (id.startsWith(quote)) {
2516
            return id;
2517
        }
2518
        return quote + id + quote;
2519

    
2520
    }
2521

    
2522
    @Override
2523
    public String as_string(String s) {
2524
        String quote = this.quote_for_strings();
2525
//        No se porque no esta disponible wrapIfMissing
2526
//        return StringUtils.wrapIfMissing(id,quote);
2527
        if (s.startsWith(quote)) {
2528
            return s;
2529
        }
2530
        return quote + s + quote;
2531

    
2532
    }
2533

    
2534
    @Override
2535
    public String as_string(byte[] data) {
2536
        return this.expressionBuilder.bytearray_0x(data);
2537
//        return this.expressionBuilder.bytearray_hex(data);
2538
//        return this.expressionBuilder.bytearray_x(data);
2539
    }
2540
    
2541
    @Override
2542
    public String as_string(boolean value) {
2543
        return value? "TRUE" : "FALSE";
2544
    }
2545

    
2546
    @Override
2547
    public String as_string(Number value) {
2548
        return Objects.toString(value);
2549
    }
2550
    
2551
    @Override
2552
    public String as_string(Object value) {
2553
        if( value == null ) {
2554
            return "NULL";
2555
        }
2556
        if( value instanceof CharSequence ) {
2557
            return as_string(value.toString());
2558
        }
2559
        if( value instanceof Number ) {
2560
            return as_string((Number)value);
2561
        }
2562
        if( value instanceof Boolean ) {
2563
            return as_string((boolean)value);
2564
        }
2565
        if( value instanceof byte[] ) {
2566
            return as_string((byte[])value);
2567
        }
2568
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2569
    }
2570
    
2571
    @Override
2572
    public ExpressionBuilder expression() {
2573
        return this.expressionBuilder;
2574
    }
2575

    
2576
    @Override
2577
    public boolean has_spatial_functions() {
2578
        return this.hasSpatialFunctions;
2579
    }
2580

    
2581
    @Override
2582
    public GeometrySupportType geometry_support_type() {
2583
        return this.geometrySupportType;
2584
    }
2585

    
2586
    protected ExpressionBuilder createExpressionBuilder() {
2587
        return ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2588
    }
2589

    
2590
    @Override
2591
    public Object srs_id(IProjection projection) {
2592
        String abrev = projection.getAbrev();
2593
        return abrev.split(":")[1].trim();
2594
    }
2595

    
2596
    @Override
2597
    public String default_schema() {
2598
        return this.defaultSchema;
2599
    }
2600

    
2601
    @Override
2602
    public boolean support_schemas() {
2603
        return this.supportSchemas;
2604
    }
2605

    
2606
    @Override
2607
    public String sqltype(int type, int p, int s, int geomType, int geomSubtype) {
2608
        switch (type) {
2609
            case DataTypes.BOOLEAN:
2610
                return type_boolean;
2611
            case DataTypes.BYTE:
2612
                return type_byte;
2613
            case DataTypes.BYTEARRAY:
2614
                return type_bytearray;
2615
            case DataTypes.GEOMETRY:
2616
                return type_geometry;
2617
            case DataTypes.CHAR:
2618
                return type_char;
2619
            case DataTypes.DATE:
2620
                return type_date;
2621
            case DataTypes.DOUBLE:
2622
                // FIXME: Si cargamos la capa "country" al exportarla a
2623
                // SQLServer falla por:
2624
                //  Error de desbordamiento aritm?tico al convertir float al tipo de datos numeric.
2625
                // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
2626
                // Algeria intenta asignarle un valor de 2320972.0 y falla.
2627
                // Habria que repasar el proveedor de shape.
2628

    
2629
//                if (p > 1) {
2630
//                    if (s < 0) {
2631
//                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
2632
//                    }
2633
//                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
2634
//                }
2635
                return MessageFormat.format(type_double, p, s);
2636
            case DataTypes.BIGDECIMAL:
2637
                if (p < 1) {
2638
                    p = 20;
2639
                }
2640
                if (s < 0) {
2641
                    s = 10;
2642
                }
2643
                return MessageFormat.format(type_bigdecimal, p, s);
2644
            case DataTypes.FLOAT:
2645
                return MessageFormat.format(type_float, p, s);
2646
            case DataTypes.INT:
2647
                return MessageFormat.format(type_int, p, s);
2648
            case DataTypes.LONG:
2649
                return MessageFormat.format(type_long, p, s);
2650
            case DataTypes.STRING:
2651
                if (p < 0) {
2652
                    return type_string;
2653
                } else if (p < 4096) {
2654
                    return MessageFormat.format(type_string_p, p);
2655
                }
2656
                return type_string;
2657
            case DataTypes.TIME:
2658
                return type_time;
2659
            case DataTypes.TIMESTAMP:
2660
                return type_timestamp;
2661
            case DataTypes.VERSION:
2662
                return type_version;
2663
            case DataTypes.URI:
2664
                return type_URI;
2665
            case DataTypes.URL:
2666
                return type_URL;
2667
            case DataTypes.FILE:
2668
                return type_FILE;
2669
            case DataTypes.FOLDER:
2670
                return type_FOLDER;
2671
            default:
2672
                return null;
2673
        }
2674
    }
2675

    
2676
    @Override
2677
    public Object sqlgeometrytype(int type, int subtype) {
2678
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2679
        // identificadores numericos para el tipo y otros strings.
2680
        // Por defecto vamos a devolver strings.
2681
        if (sqlgeometrytypes == null) {
2682
            sqlgeometrytypes = new HashMap<>();
2683
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2684
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2685
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2686
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2687

    
2688
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2689
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2690
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2691
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2692

    
2693
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2694
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2695
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2696
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2697

    
2698
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2699
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2700
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2701
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2702

    
2703
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2704
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2705
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2706
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2707

    
2708
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2709
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2710
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2711
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2712

    
2713
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2714
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2715
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2716
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2717

    
2718
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2719
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2720
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2721
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2722

    
2723
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2724
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2725
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2726
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2727
        }
2728
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2729
    }
2730

    
2731
    @Override
2732
    public Object sqlgeometrydimension(int type, int subtype) {
2733
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2734
        // identificadores numericos para las dimensiones y otros strings.
2735
        // Por defecto vamos a devolver enteros.
2736
        switch (subtype) {
2737
            case Geometry.SUBTYPES.GEOM3D:
2738
                return 3;
2739
            case Geometry.SUBTYPES.GEOM2DM:
2740
                return 3;
2741
            case Geometry.SUBTYPES.GEOM3DM:
2742
                return 4;
2743
            case Geometry.SUBTYPES.GEOM2D:
2744
            default:
2745
                return 2;
2746
        }
2747
    }
2748

    
2749
    @Override
2750
    public TableNameBuilder createTableNameBuilder() {
2751
        return new TableNameBuilderBase();
2752
    }
2753

    
2754
    protected SelectColumnBuilder createSelectColumnBuilder() {
2755
        return new SelectColumnBuilderBase();
2756
    }
2757

    
2758
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2759
        return new UpdateColumnBuilderBase();
2760
    }
2761

    
2762
    protected InsertColumnBuilder createInsertColumnBuilder() {
2763
        return new InsertColumnBuilderBase();
2764
    }
2765

    
2766
    protected OrderByBuilder createOrderByBuilder() {
2767
        return new OrderByBuilderBase();
2768
    }
2769

    
2770
    protected FromBuilder createFromBuilder() {
2771
        return new FromBuilderBase();
2772
    }
2773

    
2774
    protected SelectBuilder createSelectBuilder() {
2775
        return new SelectBuilderBase();
2776
    }
2777

    
2778
    protected UpdateBuilder createUpdateBuilder() {
2779
        return new UpdateBuilderBase();
2780
    }
2781

    
2782
    protected DeleteBuilder createDeleteBuilder() {
2783
        return new DeleteBuilderBase();
2784
    }
2785

    
2786
    protected GrantBuilder createGrantBuilder() {
2787
        return new GrantBuilderBase();
2788
    }
2789

    
2790
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2791
        return new GrantRoleBuilderBase(table, role);
2792
    }
2793

    
2794
    protected DropTableBuilder createDropTableBuilder() {
2795
        return new DropTableBuilderBase();
2796
    }
2797

    
2798
    protected CreateTableBuilder createCreateTableBuilder() {
2799
        return new CreateTableBuilderBase();
2800
    }
2801

    
2802
    protected AlterTableBuilder createAlterTableBuilder() {
2803
        return new AlterTableBuilderBase();
2804
    }
2805

    
2806
    protected InsertBuilder createInsertBuilder() {
2807
        return new InsertBuilderBase();
2808
    }
2809

    
2810
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2811
        return new UpdateTableStatisticsBuilderBase();
2812
    }
2813

    
2814
    protected CreateIndexBuilder createCreateIndexBuilder() {
2815
        return new CreateIndexBuilderBase();
2816
    }
2817

    
2818
    @Override
2819
    public SelectBuilder select() {
2820
        if (this.select == null) {
2821
            this.select = this.createSelectBuilder();
2822
        }
2823
        return this.select;
2824
    }
2825

    
2826
    @Override
2827
    public UpdateBuilder update() {
2828
        if (this.update == null) {
2829
            this.update = this.createUpdateBuilder();
2830
        }
2831
        return this.update;
2832
    }
2833

    
2834
    @Override
2835
    public UpdateTableStatisticsBuilder update_table_statistics() {
2836
        if (this.update_table_statistics == null) {
2837
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2838
        }
2839
        return this.update_table_statistics;
2840
    }
2841

    
2842
    @Override
2843
    public DropTableBuilder drop_table() {
2844
        if (this.drop_table == null) {
2845
            this.drop_table = this.createDropTableBuilder();
2846
        }
2847
        return this.drop_table;
2848
    }
2849

    
2850
    @Override
2851
    public CreateIndexBuilder create_index() {
2852
        if (this.create_index == null) {
2853
            this.create_index = this.createCreateIndexBuilder();
2854
        }
2855
        return this.create_index;
2856
    }
2857

    
2858
    @Override
2859
    public DeleteBuilder delete() {
2860
        if (this.delete == null) {
2861
            this.delete = this.createDeleteBuilder();
2862
        }
2863
        return this.delete;
2864
    }
2865

    
2866
    @Override
2867
    public InsertBuilder insert() {
2868
        if (this.insert == null) {
2869
            this.insert = this.createInsertBuilder();
2870
        }
2871
        return this.insert;
2872
    }
2873

    
2874
    @Override
2875
    public TableNameBuilder table_name() {
2876
        if (this.table_name == null) {
2877
            this.table_name = this.createTableNameBuilder();
2878
        }
2879
        return this.table_name;
2880
    }
2881

    
2882
    
2883
    @Override
2884
    public AlterTableBuilder alter_table() {
2885
        if (this.alter_table == null) {
2886
            this.alter_table = this.createAlterTableBuilder();
2887
        }
2888
        return this.alter_table;
2889
    }
2890

    
2891
    @Override
2892
    public CreateTableBuilder create_table() {
2893
        if (this.create_table == null) {
2894
            this.create_table = this.createCreateTableBuilder();
2895
        }
2896
        return this.create_table;
2897
    }
2898

    
2899
    @Override
2900
    public GrantBuilder grant() {
2901
        if (this.grant == null) {
2902
            this.grant = this.createGrantBuilder();
2903
        }
2904
        return this.grant;
2905
    }
2906
    
2907
    @Override
2908
    public Column column(String name) {
2909
        ColumnBase col = new ColumnBase(null, name);
2910
        return col;
2911
    }
2912

    
2913
    @Override
2914
    public Column column(TableNameBuilder table, String name) {
2915
        ColumnBase col = new ColumnBase(table, name);
2916
        return col;
2917
    }
2918
    
2919
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2920
        return new JoinBase(type, table, expression);
2921
    }
2922

    
2923
    public void accept(Visitor visitor, VisitorFilter filter) {
2924
        if (this.select != null) {
2925
            this.select.accept(visitor, filter);
2926
        }
2927
        if (this.update != null) {
2928
            this.update.accept(visitor, filter);
2929
        }
2930
        if (this.insert != null) {
2931
            this.insert.accept(visitor, filter);
2932
        }
2933
        if (this.delete != null) {
2934
            this.delete.accept(visitor, filter);
2935
        }
2936
        if (this.alter_table != null) {
2937
            this.alter_table.accept(visitor, filter);
2938
        }
2939
        if (this.create_table != null) {
2940
            this.create_table.accept(visitor, filter);
2941
        }
2942
        if (this.drop_table != null) {
2943
            this.drop_table.accept(visitor, filter);
2944
        }
2945
        if (this.table_name != null) {
2946
            this.table_name.accept(visitor, filter);
2947
        }
2948
    }
2949

    
2950
    protected Formatter formatter() {
2951
        return ExpressionBuilder.EMPTY_FORMATTER;
2952
    }
2953

    
2954
    @Override
2955
    public String toString() {
2956
        return this.toString(formatter());
2957
    }
2958

    
2959
    @Override
2960
    public String toString(Formatter formatter) {
2961
        if (this.select != null) {
2962
            return this.select.toString(formatter);
2963
        }
2964
        if (this.update != null) {
2965
            return this.update.toString(formatter);
2966
        }
2967
        if (this.insert != null) {
2968
            return this.insert.toString(formatter);
2969
        }
2970
        if (this.delete != null) {
2971
            return this.delete.toString(formatter);
2972
        }
2973
        if (this.alter_table != null) {
2974
            return this.alter_table.toString(formatter);
2975
        }
2976
        if (this.create_table != null) {
2977
            return this.create_table.toString(formatter);
2978
        }
2979
        if (this.drop_table != null) {
2980
            return this.drop_table.toString(formatter);
2981
        }
2982
        if (this.update_table_statistics != null) {
2983
            return this.update_table_statistics.toString(formatter);
2984
        }
2985
        if (this.table_name != null) {
2986
            return this.table_name.toString(formatter);
2987
        }
2988
        return "";
2989
    }
2990

    
2991
    @Override
2992
    public CountBuilder count() {
2993
        return new CountBuilderBase();
2994
    }
2995

    
2996
    @Override
2997
    public List<Parameter> parameters() {
2998
        final List<Parameter> params = new ArrayList<>();
2999
        this.accept(new Visitor() {
3000
            @Override
3001
            public void visit(Visitable value) {
3002
                params.add((Parameter) value);
3003
            }
3004
        }, new ClassVisitorFilter(Parameter.class));
3005
        return params;
3006
    }
3007

    
3008
    @Override
3009
    public List<Variable> variables() {
3010
        final List<Variable> vars = new ArrayList<>();
3011
        this.accept(new Visitor() {
3012
            @Override
3013
            public void visit(Visitable value) {
3014
                if (!vars.contains((Variable) value)) {
3015
                    vars.add((Variable) value);
3016
                }
3017
            }
3018
        }, new ClassVisitorFilter(Variable.class));
3019
        return vars;
3020
    }
3021

    
3022
    @Override
3023
    public List<String> parameters_names() {
3024
        List<String> params = new ArrayList<>();
3025
        for (Parameter param : parameters()) {
3026
            String s;
3027
            switch (param.type()) {
3028
                case Constant:
3029
                    Object theValue = param.value();
3030
                    if (theValue == null) {
3031
                        s = "null";
3032
                    } else if (theValue instanceof String) {
3033
                        s = "'" + (String) theValue + "'";
3034
                    } else {
3035
                        s = theValue.toString();
3036
                    }
3037
                    break;
3038
                case Geometry:
3039
                case Variable:
3040
                default:
3041
                    s = "\"" + param.name() + "\"";
3042
            }
3043
            params.add(s);
3044
        }
3045
        return params;
3046
    }
3047

    
3048
    @Override
3049
    public List<String> variables_names() {
3050
        List<String> vars = new ArrayList<>();
3051
        for (Variable var : this.variables()) {
3052
            vars.add(var.name());
3053
        }
3054
        Collections.sort(vars);
3055
        return vars;
3056
    }
3057
}