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 @ 44678

History | View | Annotate | Download (102 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 static org.gvsig.expressionevaluator.ExpressionBuilder.PARAMETER_TYPE_CONSTANT;
21
import static org.gvsig.expressionevaluator.ExpressionBuilder.PARAMETER_TYPE_VARIABLE;
22
import org.gvsig.expressionevaluator.ExpressionBuilder.Parameter;
23
import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
24
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
25
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
26
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
27
import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
28
import org.gvsig.expressionevaluator.Formatter;
29
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
30
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
31
import org.gvsig.expressionevaluator.GeometryExpressionEvaluatorLocator;
32
import org.gvsig.fmap.dal.DataStoreParameters;
33
import org.gvsig.fmap.dal.DataTypes;
34
import org.gvsig.fmap.dal.SQLBuilder;
35
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
36
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
37
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
38
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
41
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
42
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
43
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
44
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
45
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
46
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
47
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
48
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
49
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
50
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
51
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
52
import org.gvsig.fmap.geom.Geometry;
53
import org.gvsig.tools.dataTypes.DataType;
54
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
56

    
57
@SuppressWarnings("UseSpecificCatch")
58
public class SQLBuilderBase implements SQLBuilder {
59

    
60
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
61

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

    
74
    protected abstract class AbstractStatementPart extends AbstractValue {
75

    
76
    }
77

    
78
    protected abstract class AbstractStatement extends AbstractStatementPart {
79

    
80
    }
81

    
82
    protected class ColumnDescriptorBase implements ColumnDescriptor {
83

    
84
        private String name;
85
        private int type;
86
        private int size;
87
        private int precision;
88
        private int scale;
89
        private boolean isPk;
90
        private boolean _allowNulls;
91
        private boolean _isAutomatic;
92
        private Object defaultValue;
93
        private int geom_type;
94
        private int geom_subtype;
95
        private Object geom_srsdbcode;
96
        private boolean _isIndexed;
97
        private DataStoreParameters parameters = null;
98

    
99
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
100
            this.name = name;
101
            this.type = type;
102
            this.size = -1;
103
            this.precision = -1;
104
            this.scale = -1;
105
            this.isPk = false;
106
            this._allowNulls = true;
107
            this._isAutomatic = false;
108
            this.defaultValue = defaultValue;
109
            this.geom_type = Geometry.TYPES.GEOMETRY;
110
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
111
            this.geom_srsdbcode = null;
112
            this._isIndexed = false;
113
        }
114

    
115
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
116
            this.name = name;
117
            this.type = type;
118
            this.size = size;
119
            this.precision = precision;
120
            this.scale = scale;
121
            this.isPk = isPk;
122
            this._allowNulls = allowNulls;
123
            this._isAutomatic = isAutomatic;
124
            this.defaultValue = defaultValue;
125
            this.geom_type = Geometry.TYPES.GEOMETRY;
126
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
127
            this.geom_srsdbcode = null;
128
            this._isIndexed = isIndexed;
129
        }
130

    
131
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
132
            this.name = name;
133
            this.type = DataTypes.GEOMETRY;
134
            this.size = 0;
135
            this.precision = 0;
136
            this.scale = 0;
137
            this.isPk = false;
138
            this._allowNulls = allowNulls;
139
            this._isAutomatic = false;
140
            this.defaultValue = null;
141
            this.geom_type = geom_type;
142
            this.geom_subtype = geom_subtype;
143
            this.geom_srsdbcode = srs_id(proj);
144
            this._isIndexed = isIndexed;
145
        }
146

    
147
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
148
            this.name = name;
149
            this.type = DataTypes.GEOMETRY;
150
            this.size = 0;
151
            this.precision = 0;
152
            this.scale = 0;
153
            this.isPk = false;
154
            this._allowNulls = allowNulls;
155
            this._isAutomatic = false;
156
            this.defaultValue = null;
157
            this.geom_type = geom_type;
158
            this.geom_subtype = geom_subtype;
159
            this.geom_srsdbcode = srsdbcode;
160
            this._isIndexed = isIndexed;
161
        }
162

    
163
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
164
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
165
            this.precision = fad.getPrecision();
166
            this.size = fad.getSize();
167
            this.scale = fad.getScale();
168
            this.isPk = fad.isPrimaryKey();
169
            this._allowNulls = fad.allowNull();
170
            this._isAutomatic = fad.isAutomatic();
171
            this._isIndexed = fad.isIndexed();
172

    
173
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
174
                this.geom_type = fad.getGeomType().getType();
175
                this.geom_subtype = fad.getGeomType().getSubType();
176
                this.geom_srsdbcode = fad.getSRS();
177
            }
178
        }
179
    
180

    
181
        @Override
182
        public String getName() {
183
            return this.name;
184
        }
185

    
186
        @Override
187
        public void setName(String name) {
188
            this.name = name;
189
        }
190

    
191
        @Override
192
        public int getType() {
193
            return this.type;
194
        }
195

    
196
        @Override
197
        public void setType(int type) {
198
            this.type = type;
199
        }
200

    
201
        @Override
202
        public int getPrecision() {
203
            return precision;
204
        }
205

    
206
        @Override
207
        public void setPrecision(int precision) {
208
            this.precision = precision;
209
        }
210

    
211
        @Override
212
        public int getScale() {
213
            return scale;
214
        }
215

    
216
        @Override
217
        public void setScale(int scale) {
218
            this.scale = scale;
219
        }
220

    
221
        @Override
222
        public int getSize() {
223
            return size;
224
        }
225

    
226
        @Override
227
        public void setSize(int size) {
228
            this.size = size;
229
        }
230

    
231
        @Override
232
        public boolean isPrimaryKey() {
233
            return isPk;
234
        }
235

    
236
        @Override
237
        public void setIsPrimaryKey(boolean isPk) {
238
            this.isPk = isPk;
239
        }
240

    
241
        @Override
242
        public boolean allowNulls() {
243
            return _allowNulls;
244
        }
245

    
246
        @Override
247
        public void setAllowNulls(boolean allowNulls) {
248
            this._allowNulls = allowNulls;
249
        }
250

    
251
        @Override
252
        public boolean isAutomatic() {
253
            return _isAutomatic;
254
        }
255

    
256
        @Override
257
        public boolean isIndexed() {
258
            return _isIndexed;
259
        }
260

    
261
        @Override
262
        public void setIsAutomatic(boolean isAutomatic) {
263
            this._isAutomatic = isAutomatic;
264
        }
265

    
266
        @Override
267
        public Object getDefaultValue() {
268
            return defaultValue;
269
        }
270

    
271
        @Override
272
        public void setDefaultValue(Object defaultValue) {
273
            this.defaultValue = defaultValue;
274
        }
275

    
276
        @Override
277
        public int getGeometryType() {
278
            return geom_type;
279
        }
280

    
281
        @Override
282
        public void setGeometryType(int geom_type) {
283
            this.geom_type = geom_type;
284
        }
285

    
286
        @Override
287
        public int getGeometrySubtype() {
288
            return geom_subtype;
289
        }
290

    
291
        @Override
292
        public void setGeometrySubtype(int geom_subtype) {
293
            this.geom_subtype = geom_subtype;
294
        }
295

    
296
        @Override
297
        public Object getGeometrySRSId() {
298
            return geom_srsdbcode;
299
        }
300

    
301
        @Override
302
        public void setGeometrySRSId(Object geom_srsid) {
303
            this.geom_srsdbcode = geom_srsid;
304
        }
305

    
306
        @Override
307
        public boolean isGeometry() {
308
            return this.type == DataTypes.GEOMETRY;
309
        }
310

    
311
        private void setStoreParameters(DataStoreParameters parameters) {
312
            this.parameters = parameters;
313
        }
314

    
315
        @Override
316
        public DataStoreParameters getStoreParameters() {
317
            return this.parameters;
318
        }
319
    }
320

    
321
    public class ColumnBase extends AbstractValue implements Column {
322

    
323
        private final String name;
324
        private TableNameBuilder table;
325

    
326
        public ColumnBase(TableNameBuilder table, String name) {
327
            this.name = name;
328
            this.table = table;
329
        }
330

    
331
        @Override
332
        public String name() {
333
            return this.name;
334
        }
335

    
336
        @Override
337
        public TableNameBuilder table() {
338
            return this.table;
339
        }
340

    
341
        @Override
342
        public TableNameBuilder table(TableNameBuilder table) {
343
            this.table = table;
344
            return this.table;
345
        }
346

    
347
        @Override
348
        public String toString() {
349
            return this.toString(EMPTY_FORMATTER);
350
        }
351
        
352
        @Override
353
        public String toString(Formatter<Value> formatter) {
354
            if( formatter!=null && formatter.canApply(this) ) {
355
                return formatter.format(this);
356
            }
357
            if( this.table==null ) {
358
                return as_identifier(this.name);
359
            }
360
            return this.table.toString(formatter) + "." + as_identifier(this.name);
361
        }
362

    
363
        @Override
364
        public int compareTo(Variable o) {
365
            return this.name.compareTo(o.name());
366
        }
367

    
368
        @Override
369
        public boolean equals(Object obj) {
370
            if (!(obj instanceof Variable)) {
371
                return false;
372
            }
373
            return StringUtils.equals(this.toString(), ((Variable) obj).toString());
374
        }
375

    
376
        @Override
377
        public int hashCode() {
378
            int hash = 7;
379
            hash = 37 * hash + Objects.hashCode(this.toString());
380
            return hash;
381
        }
382
    }
383

    
384
    public class TableNameBuilderBase
385
            extends AbstractStatementPart
386
            implements TableNameBuilder {
387

    
388
        public String tableName;
389
        public String schemaName;
390
        private String databaseName;
391

    
392
        public TableNameBuilderBase() {
393
        }
394

    
395
        @Override
396
        public void accept(Visitor visitor, VisitorFilter filter) {
397
            if (filter.accept(this)) {
398
                visitor.visit(this);
399
            }
400
        }
401

    
402
        @Override
403
        public TableNameBuilder database(String name) {
404
            this.databaseName = name;
405
            return this;
406
        }
407

    
408
        @Override
409
        public TableNameBuilder schema(String name) {
410
            if (support_schemas()) {
411
                this.schemaName = name;
412
            }
413
            return this;
414
        }
415

    
416
        @Override
417
        public TableNameBuilder name(String name) {
418
            this.tableName = name;
419
            return this;
420
        }
421

    
422
        @Override
423
        public String getDatabase() {
424
            return this.databaseName;
425
        }
426

    
427
        @Override
428
        public String getSchema() {
429
            return this.schemaName;
430
        }
431

    
432
        @Override
433
        public String getName() {
434
            return this.tableName;
435
        }
436

    
437
        @Override
438
        public boolean has_schema() {
439
            if (!support_schemas()) {
440
                return false;
441
            }
442
            return !StringUtils.isEmpty(this.schemaName);
443
        }
444

    
445
        @Override
446
        public boolean has_database() {
447
            return !StringUtils.isEmpty(this.databaseName);
448
        }
449

    
450
        @Override
451
        public String toString() {
452
            return this.toString(formatter());
453
        }
454

    
455
        @Override
456
        public String toString(Formatter<Value> formatter) {
457
            if (formatter!=null && formatter.canApply(this)) {
458
                return formatter.format(this);
459
            }
460
            if (this.has_database()) {
461
                if (this.has_schema()) {
462
                    return as_identifier(this.databaseName) + "."
463
                            + as_identifier(this.schemaName) + "."
464
                            + as_identifier(this.tableName);
465
                }
466
            } else {
467
                if (this.has_schema()) {
468
                    return as_identifier(this.schemaName) + "."
469
                            + as_identifier(this.tableName);
470
                }
471
            }
472
            return as_identifier(this.tableName);
473
        }
474

    
475
        @Override
476
        public boolean equals(Object obj) {
477
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
478
                return false;
479
            }
480
            TableNameBuilder other = (TableNameBuilder) obj;
481
            if (this.has_database()) {
482
                if (this.has_schema()) {
483
                    return this.databaseName.equals(other.getDatabase()) &&
484
                           this.schemaName.equals(other.getSchema()) &&
485
                           this.tableName.equals(other.getName());
486
                }
487
            } else {
488
                if (this.has_schema()) {
489
                    return this.schemaName.equals(other.getSchema()) &&
490
                           this.tableName.equals(other.getName());
491
                }
492
            }
493
            return this.tableName.equals(other.getName());
494
        }
495

    
496
        @Override
497
        public int hashCode() {
498
            int hash = 7;
499
            hash = 37 * hash + Objects.hashCode(this.toString());
500
            return hash;
501
        }
502

    
503
    }
504

    
505
    public class CountBuilderBase
506
            extends AbstractStatementPart
507
            implements CountBuilder {
508

    
509
        protected Value value;
510
        protected boolean distinct;
511
        protected boolean all;
512

    
513
        public CountBuilderBase() {
514
            this.value = null;
515
            this.distinct = false;
516
            this.all = false;
517
        }
518

    
519
        @Override
520
        public CountBuilder all() {
521
            this.all = true;
522
            return this;
523
        }
524

    
525
        @Override
526
        public CountBuilder column(Value value) {
527
            this.value = value;
528
            return this;
529
        }
530

    
531
        @Override
532
        public CountBuilder distinct() {
533
            this.distinct = true;
534
            return this;
535
        }
536

    
537
        @Override
538
        public String toString() {
539
            return this.toString(formatter());
540
        }
541

    
542
        @Override
543
        public String toString(Formatter formatter) {
544
            if (formatter!=null && formatter.canApply(this)) {
545
                return formatter.format(this);
546
            }
547
            if (this.all) {
548
                return "COUNT(*)";
549
            }
550
            if (this.distinct) {
551
                return MessageFormat.format(
552
                        "COUNT(DISTINCT {0})",
553
                        value.toString(formatter)
554
                );
555
            }
556
            return MessageFormat.format(
557
                    "COUNT({0})",
558
                    value.toString(formatter)
559
            );
560
        }
561

    
562
    }
563

    
564
    protected class JoinBase 
565
            extends AbstractStatementPart
566
            implements StatementPart 
567
        {
568
        protected String type;
569
        protected TableNameBuilder table;
570
        protected Value expression;
571
        
572
        public JoinBase(String type, TableNameBuilder table, Value expression) {
573
            this.type = type;
574
            this.table = table;
575
            this.expression = expression;
576
        }
577

    
578
        @Override
579
        public String toString() {
580
            return this.toString(formatter());
581
        }
582

    
583
        @Override
584
        public String toString(Formatter<Value> formatter) {
585
            if (formatter!=null && formatter.canApply(this)) {
586
                return formatter.format(this);
587
            }
588
            StringBuilder builder = new StringBuilder();
589
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
590
            builder.append(this.type.toUpperCase());
591
            builder.append(" JOIN ");
592
            builder.append(this.table.toString(formatter));
593
            builder.append(" ON ");
594
            builder.append(this.expression.toString(formatter));
595
            return builder.toString();
596
        }
597
        
598
        
599
    }
600
    
601
    public class FromBuilderBase
602
            extends AbstractStatementPart
603
            implements FromBuilder {
604

    
605
        protected TableNameBuilder tableName;
606
        private String subquery;
607
        private String passthrough;
608
        private List<JoinBase> joins;
609

    
610
        public FromBuilderBase() {
611
            this.tableName = null;
612
            this.subquery = null;
613
            this.passthrough = null;
614
            this.joins = null;
615
        }
616

    
617
        @Override
618
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
619
            JoinBase join = createJoin("LEFT", table, expression);
620
            if( this.joins==null ) {
621
                this.joins = new ArrayList<>();
622
            }
623
            this.joins.add(join);
624
            return this;
625
        }
626
        
627
        @Override
628
        public TableNameBuilder table() {
629
            if (tableName == null) {
630
                this.tableName = createTableNameBuilder();
631
            }
632
            return this.tableName;
633
        }
634

    
635
        @Override
636
        public void accept(Visitor visitor, VisitorFilter filter) {
637
            if (filter.accept(this)) {
638
                visitor.visit(this);
639
            }
640
            if (this.tableName != null) {
641
                this.tableName.accept(visitor, filter);
642
            }
643
        }
644

    
645
        @Override
646
        public FromBuilder custom(String passthrough) {
647
            this.passthrough = passthrough;
648
            return this;
649
        }
650

    
651
        @Override
652
        public FromBuilder subquery(String subquery) {
653
            this.subquery = subquery;
654
            return this;
655
        }
656

    
657
        @Override
658
        public String toString() {
659
            return this.toString(formatter());
660
        }
661

    
662
        @Override
663
        public String toString(Formatter<Value> formatter) {
664
            if (formatter!=null && formatter.canApply(this)) {
665
                return formatter.format(this);
666
            }
667
            if (!StringUtils.isEmpty(passthrough)) {
668
                return passthrough;
669
            }
670
            if (!StringUtils.isEmpty(subquery)) {
671
                return "( " + this.subquery + ") as _subquery_alias_ ";
672
            }
673
            if( this.joins==null || this.joins.isEmpty() ) {
674
                return this.tableName.toString(formatter);
675
            }
676
            StringBuilder builder = new StringBuilder();
677
            builder.append(this.tableName.toString(formatter));
678
            for (JoinBase join : this.joins) {
679
                builder.append(" ");
680
                builder.append(join.toString(formatter));
681
            }
682
            return builder.toString();
683
        }
684

    
685
    }
686

    
687
    public class SelectColumnBuilderBase
688
            extends AbstractStatementPart
689
            implements SelectColumnBuilder {
690

    
691
        private Variable name = null;
692
        private String alias = null;
693
        private Value value = null;
694
        private boolean asGeometry = false;
695
        private TableNameBuilder table;
696

    
697
        @Override
698
        public void accept(Visitor visitor, VisitorFilter filter) {
699
            if (filter.accept(this)) {
700
                visitor.visit(this);
701
            }
702
            if (this.name != null) {
703
                this.name.accept(visitor, filter);
704
            }
705
            if (this.value != null) {
706
                this.value.accept(visitor, filter);
707
            }
708
        }
709

    
710
        @Override
711
        public void replace(Value target, Value replacement) {
712
            if (this.name!=null ) {
713
                if( this.name == target) {
714
                    this.name = (Variable) replacement;
715
                }
716
            }
717
            if( this.value!=null ) {
718
                if (this.value == target) {
719
                    this.value = replacement;
720
                } else {
721
                    this.value.replace(target, replacement);
722
                }
723
            }
724
        }
725
        
726
        @Override
727
        public SelectColumnBuilder name(String name) {
728
            return this.name(null, name);
729
        }
730

    
731
        @Override
732
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
733
            String quote = quote_for_identifiers();
734
            if (name.startsWith(quote)) {
735
                // Remove quotes
736
                name = name.substring(1, name.length() - 1);
737
            }
738
            this.name = expression().variable(name);
739
            this.table = table;
740
            this.value = null;
741
            this.asGeometry = false;
742
            return this;
743
        }
744

    
745
        @Override
746
        public SelectColumnBuilder all() {
747
            this.name = null;
748
            this.value = expression().custom("*");
749
            this.asGeometry = false;
750
            return this;
751
        }
752

    
753
        @Override
754
        public SelectColumnBuilder as_geometry() {
755
            this.asGeometry = true;
756
            return this;
757
        }
758

    
759
        @Override
760
        public SelectColumnBuilder value(Value value) {
761
            this.value = value;
762
            this.name = null;
763
            return this;
764
        }
765

    
766
        @Override
767
        public SelectColumnBuilder as(String alias) {
768
            this.alias = alias;
769
            return this;
770
        }
771

    
772
        @Override
773
        public String getName() {
774
            return this.name.name();
775
        }
776

    
777
        @Override
778
        public String getAlias() {
779
            return this.alias;
780
        }
781

    
782
        @Override
783
        public String getValue() {
784
            return this.alias;
785
        }
786

    
787
        @Override
788
        public String toString() {
789
            return this.toString(formatter());
790
        }
791

    
792
        @Override
793
        public String toString(Formatter<Value> formatter) {
794
            if (formatter!=null && formatter.canApply(this)) {
795
                return formatter.format(this);
796
            }
797
            StringBuilder builder = new StringBuilder();
798
            if (this.asGeometry) {
799
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
800
            } else {
801
                if (this.name != null) {
802
                    if( this.table==null ) {
803
                        builder.append(this.name.toString(formatter));
804
                    } else {
805
                        builder.append(this.table.toString(formatter));
806
                        builder.append(".");
807
                        builder.append(this.name.toString(formatter));
808
                    }
809
                } else {
810
                    builder.append(this.value.toString(formatter));
811
                }
812
            }
813
            if (this.alias != null) {
814
                builder.append(" AS ");
815
                builder.append(as_identifier(this.alias));
816
            }
817
            return builder.toString();
818
        }
819
    }
820

    
821
    public class OrderByBuilderBase
822
            extends AbstractStatementPart
823
            implements OrderByBuilder {
824

    
825
        protected String value;
826
        protected String custom;
827
        protected boolean ascending;
828

    
829
        public OrderByBuilderBase() {
830
            this.ascending = true;
831
        }
832

    
833
        @Override
834
        public void accept(Visitor visitor, VisitorFilter filter) {
835
            if (filter.accept(this)) {
836
                visitor.visit(this);
837
            }
838
        }
839

    
840
        @Override
841
        public OrderByBuilder column(String name) {
842
            this.value = name;
843
            return this;
844
        }
845

    
846
        @Override
847
        public OrderByBuilder custom(String order) {
848
            this.custom = order;
849
            return this;
850
        }
851

    
852
        @Override
853
        public OrderByBuilder ascending() {
854
            this.ascending = true;
855
            return this;
856
        }
857

    
858
        @Override
859
        public OrderByBuilder ascending(boolean asc) {
860
            this.ascending = asc;
861
            return this;
862
        }
863

    
864
        @Override
865
        public OrderByBuilder descending() {
866
            this.ascending = false;
867
            return this;
868
        }
869

    
870
        @Override
871
        public String toString() {
872
            return this.toString(formatter());
873
        }
874

    
875
        @Override
876
        public String toString(Formatter<Value> formatter) {
877
            if (formatter!=null && formatter.canApply(this)) {
878
                return formatter.format(this);
879
            }
880
            if (!StringUtils.isEmpty(this.custom)) {
881
                return this.custom;
882
            }
883
            if (this.ascending) {
884
                return as_identifier(this.value) + " ASC";
885
            }
886
            return as_identifier(this.value) + " DESC";
887
        }
888
    }
889

    
890
    public class SelectBuilderBase
891
            extends AbstractStatement
892
            implements SelectBuilder {
893

    
894
        protected FromBuilder from;
895
        protected GeometryExpressionBuilder where;
896
        protected long limit = -1;
897
        protected long offset = -1;
898
        protected List<SelectColumnBuilder> columns;
899
        protected List<OrderByBuilder> order_by;
900
        protected boolean distinct;
901
        protected List<Variable> groupColumn;
902

    
903
        public SelectBuilderBase() {
904
            this.columns = new ArrayList<>();
905
            this.distinct = false;
906
        }
907

    
908
        @Override
909
        public SelectBuilder group_by(Variable... columns) {
910
            if( this.groupColumn==null ) {
911
                this.groupColumn = new ArrayList<>();
912
            }
913
            for (Variable column : columns) {
914
                this.groupColumn.add(column);
915
            }
916
            return this;
917
        }
918

    
919
        @Override
920
        public void accept(Visitor visitor, VisitorFilter filter) {
921
            if (filter.accept(this)) {
922
                visitor.visit(this);
923
            }
924
            for (SelectColumnBuilder column : columns) {
925
                column.accept(visitor, filter);
926
            }
927
            if (this.has_from()) {
928
                this.from.accept(visitor, filter);
929
            }
930
            if (this.has_where()) {
931
                this.where.accept(visitor, filter);
932
            }
933
            if (this.has_order_by()) {
934
                for (OrderByBuilder order : order_by) {
935
                    order.accept(visitor, filter);
936
                }
937
            }
938
        }
939

    
940
        @Override
941
        public void replace(Value target, Value replacement) {
942
            if( this.columns!=null ) {
943
                for (int i = 0; i < columns.size(); i++) {
944
                    SelectColumnBuilder column = columns.get(i);
945
                    if( column == target ) {
946
                        columns.set(i, (SelectColumnBuilder) replacement);
947
                    } else {
948
                        column.replace(target, replacement);
949
                    }
950
                }
951
            }
952
            if (this.has_from()) {
953
                if( this.from == target ) {
954
                    this.from = (FromBuilder) replacement;
955
                } else {
956
                    this.from.replace(target, replacement);
957
                }
958
            }
959
            if (this.has_where()) {
960
                if( this.where == target ) {
961
                    this.where = (GeometryExpressionBuilder) replacement;
962
                } else if( this.where.value() == target ) {
963
                    this.where.value(replacement);
964
                } else {
965
                    this.where.value().replace(target, replacement);
966
                }
967
            }
968
            if (this.has_order_by()) {
969
                for (int i = 0; i < order_by.size(); i++) {
970
                    OrderByBuilder order = order_by.get(i);
971
                    if( order == target ) {
972
                        order_by.set(i, (OrderByBuilder) replacement);
973
                    } else {
974
                        order.replace(target, replacement);
975
                    }
976
                }
977
            }
978
        }
979

    
980
        @Override
981
        public SelectBuilder distinct() {
982
            this.distinct = true;
983
            return this;
984
        }
985

    
986
        @Override
987
        public SelectColumnBuilder column() {
988
            SelectColumnBuilder builder = createSelectColumnBuilder();
989
            this.columns.add(builder);
990
            return builder;
991
        }
992

    
993
        @Override
994
        public SelectBuilder remove_all_columns() {
995
            this.columns = new ArrayList<>();
996
            return this;
997
        }
998
        
999
        @Override
1000
        public boolean has_column(String name) {
1001
            for (SelectColumnBuilder column : columns) {
1002
                if (name.equals(column.getName())) {
1003
                    return true;
1004
                }
1005
            }
1006
            return false;
1007
        }
1008

    
1009
        @Override
1010
        public FromBuilder from() {
1011
            if (this.from == null) {
1012
                this.from = createFromBuilder();
1013
            }
1014
            return this.from;
1015
        }
1016

    
1017
        @Override
1018
        public boolean has_from() {
1019
            return this.from != null;
1020
        }
1021

    
1022
        @Override
1023
        public GeometryExpressionBuilder where() {
1024
            if (this.where == null) {
1025
                this.where = createExpressionBuilder();
1026
            }
1027
            return this.where;
1028
        }
1029

    
1030
        @Override
1031
        public boolean has_where() {
1032
            if (this.where == null) {
1033
                return false;
1034
            }
1035
            return this.where.value() != null;
1036
        }
1037

    
1038
        @Override
1039
        public SelectBuilder limit(long limit) {
1040
            this.limit = limit;
1041
            return this;
1042
        }
1043

    
1044
        @Override
1045
        public SelectBuilder limit(Long limit) {
1046
            if (limit == null) {
1047
                this.limit = 0;
1048
            } else {
1049
                this.limit = limit;
1050
            }
1051
            return this;
1052
        }
1053

    
1054
        @Override
1055
        public boolean has_limit() {
1056
            return this.limit > 0;
1057
        }
1058

    
1059
        @Override
1060
        public SelectBuilder offset(long offset) {
1061
            this.offset = offset;
1062
            return this;
1063
        }
1064

    
1065
        @Override
1066
        public boolean has_offset() {
1067
            return this.offset > 0;
1068
        }
1069

    
1070
        @Override
1071
        public OrderByBuilder order_by() {
1072
            if (this.order_by == null) {
1073
                this.order_by = new ArrayList<>();
1074
            }
1075
            OrderByBuilder order = createOrderByBuilder();
1076
            this.order_by.add(order);
1077
            return order;
1078
        }
1079

    
1080
        @Override
1081
        public boolean has_order_by() {
1082
            if (this.order_by == null) {
1083
                return false;
1084
            }
1085
            return !this.order_by.isEmpty();
1086
        }
1087
        
1088
        @Override
1089
        public boolean has_group_by() {
1090
            if (this.groupColumn == null) {
1091
                return false;
1092
            }
1093
            return !this.groupColumn.isEmpty();
1094
        }
1095
        
1096
        protected boolean isValid(StringBuilder message) {
1097
            if (message == null) {
1098
                message = new StringBuilder();
1099
            }
1100
            if (this.has_offset() && !this.has_order_by()) {
1101
                // Algunos gestores de BBDD requieren que se especifique un
1102
                // orden para poder usar OFFSET. Como eso parece buena idea para
1103
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
1104
                // siempre.
1105
                message.append("Can't use OFFSET without an ORDER BY.");
1106
                return false;
1107
            }
1108
            return true;
1109
        }
1110

    
1111
        @Override
1112
        public String toString() {
1113
            return this.toString(formatter());
1114
        }
1115

    
1116
        @Override
1117
        public String toString(Formatter<Value> formatter) {
1118
            if (formatter!=null && formatter.canApply(this)) {
1119
                return formatter.format(this);
1120
            }
1121
            StringBuilder builder = new StringBuilder();
1122
            if (!this.isValid(builder)) {
1123
                throw new IllegalStateException(builder.toString());
1124
            }
1125
            builder.append("SELECT ");
1126
            if (this.distinct) {
1127
                builder.append("DISTINCT ");
1128
            }
1129
            boolean first = true;
1130
            for (SelectColumnBuilder column : columns) {
1131
                if (first) {
1132
                    first = false;
1133
                } else {
1134
                    builder.append(", ");
1135
                }
1136
                builder.append(column.toString(formatter));
1137
            }
1138

    
1139
            if (this.has_from()) {
1140
                builder.append(" FROM ");
1141
                builder.append(this.from.toString(formatter));
1142
            }
1143
            if( this.has_group_by() ) {
1144
                builder.append(" GROUP BY ");
1145
                builder.append(this.groupColumn.get(0).toString(formatter));
1146
                for (int i = 1; i < groupColumn.size(); i++) {
1147
                    builder.append(", ");
1148
                    builder.append(this.groupColumn.get(i).toString(formatter));
1149
                }
1150
            }
1151
            if (this.has_where()) {
1152
                builder.append(" WHERE ");
1153
                builder.append(this.where.toString(formatter));
1154
            }
1155

    
1156
            if (this.has_order_by()) {
1157
                builder.append(" ORDER BY ");
1158
                first = true;
1159
                for (OrderByBuilder item : this.order_by) {
1160
                    if (first) {
1161
                        first = false;
1162
                    } else {
1163
                        builder.append(", ");
1164
                    }
1165
                    builder.append(item.toString(formatter));
1166
                }
1167
            }
1168

    
1169
            if (this.has_limit()) {
1170
                builder.append(" LIMIT ");
1171
                builder.append(this.limit);
1172
            }
1173
            if (this.has_offset()) {
1174
                builder.append(" OFFSET ");
1175
                builder.append(this.offset);
1176
            }
1177
            return builder.toString();
1178

    
1179
        }
1180
    }
1181

    
1182
    public class DropTableBuilderBase
1183
            extends AbstractStatement
1184
            implements DropTableBuilder {
1185

    
1186
        protected TableNameBuilder table;
1187

    
1188
        @Override
1189
        public TableNameBuilder table() {
1190
            if (table == null) {
1191
                table = createTableNameBuilder();
1192
            }
1193
            return table;
1194
        }
1195

    
1196
        @Override
1197
        public void accept(Visitor visitor, VisitorFilter filter) {
1198
            if (filter.accept(this)) {
1199
                visitor.visit(this);
1200
            }
1201
            this.table.accept(visitor, filter);
1202
        }
1203

    
1204
        @Override
1205
        public String toString() {
1206
            return this.toString(formatter());
1207
        }
1208

    
1209
        @Override
1210
        public String toString(Formatter<Value> formatter) {
1211
            if (formatter!=null && formatter.canApply(this)) {
1212
                return formatter.format(this);
1213
            }
1214
            StringBuilder builder = new StringBuilder();
1215
            boolean first = true;
1216
            for (String sql : toStrings(formatter)) {
1217
                if (StringUtils.isEmpty(sql)) {
1218
                    continue;
1219
                }
1220
                if (first) {
1221
                    first = false;
1222
                } else {
1223
                    builder.append("; ");
1224
                }
1225
                builder.append(sql);
1226
            }
1227
            return builder.toString();
1228
        }
1229

    
1230
        @Override
1231
        public List<String> toStrings() {
1232
            return this.toStrings(formatter());
1233
        }
1234

    
1235
        @Override
1236
        public List<String> toStrings(Formatter formatter) {
1237
            List<String> sqls = new ArrayList<>();
1238

    
1239
            sqls.add(
1240
                    MessageFormat.format(
1241
                            STMT_DROP_TABLE_table,
1242
                            this.table.toString(formatter)
1243
                    )
1244
            );
1245
            String sql;
1246
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1247
                if (this.table.has_schema()) {
1248
                    sql = MessageFormat.format(
1249
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1250
                            as_string(this.table.getSchema()),
1251
                            as_string(this.table.getName())
1252
                    );
1253
                } else {
1254
                    sql = MessageFormat.format(
1255
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1256
                            as_identifier(this.table.getName())
1257
                    );
1258
                }
1259
                if (!StringUtils.isEmpty(sql)) {
1260
                    sqls.add(sql);
1261
                }
1262
            }
1263
            return sqls;
1264
        }
1265
    }
1266

    
1267
    public class GrantRoleBuilderBase
1268
            extends AbstractStatementPart
1269
            implements GrantRoleBuilder {
1270

    
1271
        protected TableNameBuilder table;
1272
        protected String role;
1273
        protected Set<Privilege> privileges;
1274

    
1275
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1276
            this.table = table;
1277
            this.role = role;
1278
            this.privileges = new HashSet<>();
1279
        }
1280

    
1281
        @Override
1282
        public GrantRoleBuilder privilege(Privilege privilege) {
1283
            privileges.add(privilege);
1284
            return this;
1285
        }
1286

    
1287
        @Override
1288
        public GrantRoleBuilder select() {
1289
            privileges.add(Privilege.SELECT);
1290
            return this;
1291
        }
1292

    
1293
        @Override
1294
        public GrantRoleBuilder update() {
1295
            privileges.add(Privilege.UPDATE);
1296
            return this;
1297
        }
1298

    
1299
        @Override
1300
        public GrantRoleBuilder insert() {
1301
            privileges.add(Privilege.INSERT);
1302
            return this;
1303
        }
1304

    
1305
        @Override
1306
        public GrantRoleBuilder delete() {
1307
            privileges.add(Privilege.DELETE);
1308
            return this;
1309
        }
1310

    
1311
        @Override
1312
        public GrantRoleBuilder truncate() {
1313
            privileges.add(Privilege.TRUNCATE);
1314
            return this;
1315
        }
1316

    
1317
        @Override
1318
        public GrantRoleBuilder reference() {
1319
            privileges.add(Privilege.REFERENCE);
1320
            return this;
1321
        }
1322

    
1323
        @Override
1324
        public GrantRoleBuilder trigger() {
1325
            privileges.add(Privilege.TRIGGER);
1326
            return this;
1327
        }
1328

    
1329
        @Override
1330
        public GrantRoleBuilder all() {
1331
            privileges.add(Privilege.ALL);
1332
            return this;
1333
        }
1334

    
1335
        protected String getPrivilegeName(Privilege privilege) {
1336
            switch (privilege) {
1337
                case DELETE:
1338
                    return "DELETE";
1339
                case INSERT:
1340
                    return "INSERT";
1341
                case REFERENCE:
1342
                    return "REFERENCE";
1343
                case SELECT:
1344
                    return "SELECT";
1345
                case TRIGGER:
1346
                    return "TRIGGER";
1347
                case TRUNCATE:
1348
                    return "TRUNCATE";
1349
                case UPDATE:
1350
                    return "UPDATE";
1351
                case ALL:
1352
                default:
1353
                    return "ALL";
1354
            }
1355
        }
1356

    
1357
        @Override
1358
        public String toString() {
1359
            return this.toString(formatter());
1360
        }
1361

    
1362
        @Override
1363
        public String toString(Formatter<Value> formatter) {
1364
            if (formatter!=null && formatter.canApply(this)) {
1365
                return formatter.format(this);
1366
            }
1367
            StringBuilder builder = new StringBuilder();
1368
            boolean first = true;
1369
            for (Privilege privilege : privileges) {
1370
                if (first) {
1371
                    first = false;
1372
                } else {
1373
                    builder.append(", ");
1374
                }
1375
                builder.append(this.getPrivilegeName(privilege));
1376
            }
1377
            String sql = MessageFormat.format(
1378
                    STMT_GRANT_privileges_ON_table_TO_role,
1379
                    builder.toString(),
1380
                    table.toString(formatter),
1381
                    role
1382
            );
1383
            return sql;
1384
        }
1385
    }
1386

    
1387
    public class GrantBuilderBase
1388
            extends AbstractStatement
1389
            implements GrantBuilder {
1390

    
1391
        protected TableNameBuilder table;
1392
        protected Map<String, GrantRoleBuilder> roles;
1393

    
1394
        public GrantBuilderBase() {
1395
            this.roles = new HashMap<>();
1396
        }
1397

    
1398
        @Override
1399
        public TableNameBuilder table() {
1400
            if (table == null) {
1401
                table = createTableNameBuilder();
1402
            }
1403
            return table;
1404
        }
1405

    
1406
        @Override
1407
        public void accept(Visitor visitor, VisitorFilter filter) {
1408
            if (filter.accept(this)) {
1409
                visitor.visit(this);
1410
            }
1411
            if (this.table != null) {
1412
                this.table.accept(visitor, filter);
1413
            }
1414
        }
1415

    
1416
        @Override
1417
        public GrantRoleBuilder role(String role) {
1418
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1419
            if (roleBuilder == null) {
1420
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1421
                this.roles.put(role, roleBuilder);
1422
            }
1423
            return roleBuilder;
1424
        }
1425

    
1426
        @Override
1427
        public String toString() {
1428
            return this.toString(formatter());
1429
        }
1430

    
1431
        @Override
1432
        public String toString(Formatter<Value> formatter) {
1433
            if (formatter!=null && formatter.canApply(this)) {
1434
                return formatter.format(this);
1435
            }
1436
            StringBuilder builder = new StringBuilder();
1437
            boolean first = true;
1438
            for (String sql : toStrings(formatter)) {
1439
                if (StringUtils.isEmpty(sql)) {
1440
                    continue;
1441
                }
1442
                if (first) {
1443
                    first = false;
1444
                } else {
1445
                    builder.append("; ");
1446
                }
1447
                builder.append(sql);
1448
            }
1449
            return builder.toString();
1450
        }
1451

    
1452
        @Override
1453
        public List<String> toStrings() {
1454
            return this.toStrings(formatter());
1455
        }
1456

    
1457
        @Override
1458
        public List<String> toStrings(Formatter formatter) {
1459
            List<String> sqls = new ArrayList<>();
1460
            for (GrantRoleBuilder role : roles.values()) {
1461
                sqls.add(role.toString(formatter));
1462
            }
1463
            return sqls;
1464
        }
1465
    }
1466

    
1467
    public class UpdateColumnBuilderBase
1468
            extends InsertColumnBuilderBase
1469
            implements UpdateColumnBuilder {
1470

    
1471
        public UpdateColumnBuilderBase() {
1472
            super();
1473
        }
1474

    
1475
        @Override
1476
        public UpdateColumnBuilder name(String name) {
1477
            return (UpdateColumnBuilder) super.name(name);
1478
        }
1479

    
1480
        @Override
1481
        public UpdateColumnBuilder with_value(Value value) {
1482
            return (UpdateColumnBuilder) super.with_value(value);
1483
        }
1484

    
1485
    }
1486

    
1487
    public class UpdateBuilderBase
1488
            extends AbstractStatement
1489
            implements UpdateBuilder {
1490

    
1491
        protected GeometryExpressionBuilder where;
1492
        protected List<UpdateColumnBuilder> columns;
1493
        protected TableNameBuilder table;
1494

    
1495
        public UpdateBuilderBase() {
1496
            this.columns = new ArrayList<>();
1497
        }
1498

    
1499
        @Override
1500
        public void accept(Visitor visitor, VisitorFilter filter) {
1501
            if (filter.accept(this)) {
1502
                visitor.visit(this);
1503
            }
1504
            if (this.table != null) {
1505
                this.table.accept(visitor, filter);
1506
            }
1507
            for (UpdateColumnBuilder column : columns) {
1508
                column.accept(visitor, filter);
1509
            }
1510
            if (this.has_where()) {
1511
                this.where.accept(visitor, filter);
1512
            }
1513
        }
1514

    
1515
        @Override
1516
        public GeometryExpressionBuilder where() {
1517
            if (this.where == null) {
1518
                this.where = createExpressionBuilder();
1519
            }
1520
            return this.where;
1521
        }
1522

    
1523
        @Override
1524
        public TableNameBuilder table() {
1525
            if (table == null) {
1526
                table = createTableNameBuilder();
1527
            }
1528
            return table;
1529
        }
1530

    
1531
        @Override
1532
        public UpdateColumnBuilder column() {
1533
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1534
            this.columns.add(column);
1535
            return column;
1536
        }
1537

    
1538
        @Override
1539
        public boolean has_where() {
1540
            return this.where != null;
1541
        }
1542

    
1543
        @Override
1544
        public String toString() {
1545
            return this.toString(formatter());
1546
        }
1547

    
1548
        @Override
1549
        public String toString(Formatter<Value> formatter) {
1550
            if (formatter!=null && formatter.canApply(this)) {
1551
                return formatter.format(this);
1552
            }
1553
            /*
1554
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1555
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1556
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1557
             * output_expression [ AS output_name ] [, ...] ]
1558
             */
1559
            StringBuilder columnsAndValues = new StringBuilder();
1560

    
1561
            boolean first = true;
1562
            for (UpdateColumnBuilder column : columns) {
1563
                if (first) {
1564
                    first = false;
1565
                } else {
1566
                    columnsAndValues.append(", ");
1567
                }
1568
                columnsAndValues.append(as_identifier(column.getName()));
1569
                columnsAndValues.append(" = ");
1570
                columnsAndValues.append(column.getValue().toString(formatter));
1571
            }
1572

    
1573
            String sql;
1574
            if (this.has_where()) {
1575
                sql = MessageFormat.format(
1576
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1577
                        this.table.toString(formatter),
1578
                        columnsAndValues.toString(),
1579
                        this.where.toString(formatter)
1580
                );
1581
            } else {
1582
                sql = MessageFormat.format(
1583
                        STMT_UPDATE_table_SET_columnsAndValues,
1584
                        this.table.toString(formatter),
1585
                        columnsAndValues.toString()
1586
                );
1587
            }
1588
            return sql;
1589
        }
1590
    }
1591

    
1592
    public class DeleteBuilderBase
1593
            extends AbstractStatement
1594
            implements DeleteBuilder {
1595

    
1596
        protected GeometryExpressionBuilder where;
1597
        protected TableNameBuilder table;
1598

    
1599
        public DeleteBuilderBase() {
1600
        }
1601

    
1602
        @Override
1603
        public void accept(Visitor visitor, VisitorFilter filter) {
1604
            if (filter.accept(this)) {
1605
                visitor.visit(this);
1606
            }
1607
            if (this.table != null) {
1608
                this.table.accept(visitor, filter);
1609
            }
1610
            if (this.has_where()) {
1611
                this.where.accept(visitor, filter);
1612
            }
1613
        }
1614

    
1615
        @Override
1616
        public GeometryExpressionBuilder where() {
1617
            if (this.where == null) {
1618
                this.where = createExpressionBuilder();
1619
            }
1620
            return this.where;
1621
        }
1622

    
1623
        @Override
1624
        public TableNameBuilder table() {
1625
            if (table == null) {
1626
                table = createTableNameBuilder();
1627
            }
1628
            return table;
1629
        }
1630

    
1631
        @Override
1632
        public boolean has_where() {
1633
            return this.where != null;
1634
        }
1635

    
1636
        @Override
1637
        public String toString() {
1638
            return this.toString(formatter());
1639
        }
1640

    
1641
        @Override
1642
        public String toString(Formatter<Value> formatter) {
1643
            if (formatter!=null && formatter.canApply(this)) {
1644
                return formatter.format(this);
1645
            }
1646
            /*
1647
             * DELETE FROM table_name
1648
             * WHERE some_column=some_value; 
1649
             */
1650
            String sql;
1651
            if (this.has_where()) {
1652
                sql = MessageFormat.format(
1653
                        STMT_DELETE_FROM_table_WHERE_expresion,
1654
                        this.table.toString(formatter),
1655
                        this.where.toString(formatter)
1656
                );
1657
            } else {
1658
                sql = MessageFormat.format(
1659
                        STMT_DELETE_FROM_table,
1660
                        this.table.toString(formatter)
1661
                );
1662
            }
1663
            return sql;
1664
        }
1665
    }
1666

    
1667
    public class CreateIndexBuilderBase
1668
            extends AbstractStatement
1669
            implements CreateIndexBuilder {
1670

    
1671
        protected boolean ifNotExist = false;
1672
        protected boolean isUnique = false;
1673
        protected String indexName;
1674
        protected boolean isSpatial = false;
1675
        protected TableNameBuilder table;
1676
        protected final List<String> columns;
1677

    
1678
        public CreateIndexBuilderBase() {
1679
            this.columns = new ArrayList<>();
1680
        }
1681

    
1682
        @Override
1683
        public CreateIndexBuilder unique() {
1684
            this.isUnique = true;
1685
            return this;
1686
        }
1687

    
1688
        @Override
1689
        public CreateIndexBuilder if_not_exist() {
1690
            this.ifNotExist = true;
1691
            return this;
1692
        }
1693

    
1694
        @Override
1695
        public CreateIndexBuilder name(String name) {
1696
            this.indexName = name;
1697
            return this;
1698
        }
1699

    
1700
        @Override
1701
        public CreateIndexBuilder spatial() {
1702
            this.isSpatial = true;
1703
            return this;
1704
        }
1705

    
1706
        @Override
1707
        public CreateIndexBuilder column(String name) {
1708
            this.columns.add(name);
1709
            return this;
1710
        }
1711

    
1712
        @Override
1713
        public TableNameBuilder table() {
1714
            if (table == null) {
1715
                table = createTableNameBuilder();
1716
            }
1717
            return table;
1718
        }
1719

    
1720
        @Override
1721
        public void accept(Visitor visitor, VisitorFilter filter) {
1722
            if (filter.accept(this)) {
1723
                visitor.visit(this);
1724
            }
1725
            if (this.table != null) {
1726
                this.table.accept(visitor, filter);
1727
            }
1728
        }
1729

    
1730
        @Override
1731
        public String toString() {
1732
            return this.toString(formatter());
1733
        }
1734

    
1735
        @Override
1736
        public String toString(Formatter<Value> formatter) {
1737
            if (formatter!=null && formatter.canApply(this)) {
1738
                return formatter.format(this);
1739
            }
1740
            StringBuilder builder = new StringBuilder();
1741
            boolean first = true;
1742
            for (String sql : toStrings(formatter)) {
1743
                if (StringUtils.isEmpty(sql)) {
1744
                    continue;
1745
                }
1746
                if (first) {
1747
                    first = false;
1748
                } else {
1749
                    builder.append("; ");
1750
                }
1751
                builder.append(sql);
1752
            }
1753
            return builder.toString();
1754
        }
1755

    
1756
        @Override
1757
        public List<String> toStrings() {
1758
            return this.toStrings(formatter());
1759
        }
1760

    
1761
        @Override
1762
        public List<String> toStrings(Formatter formatter) {
1763
            StringBuilder builder = new StringBuilder();
1764
            builder.append("CREATE ");
1765
            if (this.isUnique) {
1766
                builder.append("UNIQUE ");
1767
            }
1768
            builder.append("INDEX ");
1769
            if (this.ifNotExist) {
1770
                builder.append("IF NOT EXISTS ");
1771
            }
1772
            builder.append(as_identifier(this.indexName));
1773
            builder.append(" ON ");
1774
            builder.append(this.table.toString(formatter));
1775
            if (this.isSpatial) {
1776
                builder.append(" USING GIST ");
1777
            }
1778
            builder.append(" ( ");
1779
            boolean is_first_column = true;
1780
            for (String column : this.columns) {
1781
                if (is_first_column) {
1782
                    is_first_column = false;
1783
                } else {
1784
                    builder.append(", ");
1785
                }
1786
                builder.append(column);
1787
            }
1788
            builder.append(" )");
1789

    
1790
            List<String> sqls = new ArrayList<>();
1791
            sqls.add(builder.toString());
1792
            return sqls;
1793
        }
1794

    
1795
    }
1796

    
1797
    public class AlterTableBuilderBase
1798
            extends AbstractStatement
1799
            implements AlterTableBuilder {
1800

    
1801
        protected TableNameBuilder table;
1802
        protected List<String> drops;
1803
        protected List<ColumnDescriptor> adds;
1804
        protected List<ColumnDescriptor> alters;
1805
        protected List<Pair<String, String>> renames;
1806

    
1807
        public AlterTableBuilderBase() {
1808
            this.drops = new ArrayList<>();
1809
            this.adds = new ArrayList<>();
1810
            this.alters = new ArrayList<>();
1811
            this.renames = new ArrayList<>();
1812
        }
1813

    
1814
        @Override
1815
        public boolean isEmpty() {
1816
            return this.drops.isEmpty()
1817
                    && this.adds.isEmpty()
1818
                    && this.alters.isEmpty()
1819
                    && this.renames.isEmpty();
1820
        }
1821

    
1822
        @Override
1823
        public void accept(Visitor visitor, VisitorFilter filter) {
1824
            if (filter.accept(this)) {
1825
                visitor.visit(this);
1826
            }
1827
            if (this.table != null) {
1828
                this.table.accept(visitor, filter);
1829
            }
1830
        }
1831

    
1832
        @Override
1833
        public TableNameBuilder table() {
1834
            if (table == null) {
1835
                table = createTableNameBuilder();
1836
            }
1837
            return table;
1838
        }
1839

    
1840
        @Override
1841
        public AlterTableBuilder drop_column(String columnName) {
1842
            this.drops.add(columnName);
1843
            return this;
1844
        }
1845

    
1846
        @Override
1847
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1848
            this.adds.add(new ColumnDescriptorBase(fad));
1849
            return this;
1850
        }
1851

    
1852
        @Override
1853
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1854
            if (isPk || isAutomatic) {
1855
                allowNulls = false;
1856
            }
1857
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1858
            return this;
1859
        }
1860

    
1861
        @Override
1862
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1863
            if (StringUtils.isEmpty(columnName)) {
1864
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1865
            }
1866
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1867
            return this;
1868
        }
1869

    
1870
        @Override
1871
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1872
            if (StringUtils.isEmpty(columnName)) {
1873
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1874
            }
1875
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1876
            return this;
1877
        }
1878

    
1879
        @Override
1880
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1881
            this.alters.add(new ColumnDescriptorBase(fad));
1882
            return this;
1883
        }
1884

    
1885
        @Override
1886
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1887
            if (isPk || isAutomatic) {
1888
                allowNulls = false;
1889
            }
1890
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1891
            return this;
1892
        }
1893

    
1894
        @Override
1895
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1896
            if (StringUtils.isEmpty(columnName)) {
1897
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1898
            }
1899
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1900
            return this;
1901
        }
1902

    
1903
        @Override
1904
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1905
            if (StringUtils.isEmpty(columnName)) {
1906
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1907
            }
1908
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1909
            return this;
1910
        }
1911

    
1912
        @Override
1913
        public AlterTableBuilder rename_column(String source, String target) {
1914
            this.renames.add(new ImmutablePair(source, target));
1915
            return this;
1916
        }
1917

    
1918
        @Override
1919
        public String toString() {
1920
            return this.toString(formatter());
1921
        }
1922

    
1923
        @Override
1924
        public String toString(Formatter<Value> formatter) {
1925
            if (formatter!=null && formatter.canApply(this)) {
1926
                return formatter.format(this);
1927
            }
1928
            StringBuilder builder = new StringBuilder();
1929
            boolean first = true;
1930
            for (String sql : toStrings(formatter)) {
1931
                if (StringUtils.isEmpty(sql)) {
1932
                    continue;
1933
                }
1934
                if (first) {
1935
                    first = false;
1936
                } else {
1937
                    builder.append("; ");
1938
                }
1939
                builder.append(sql);
1940
            }
1941
            return builder.toString();
1942
        }
1943

    
1944
        @Override
1945
        public List<String> toStrings() {
1946
            return this.toStrings(formatter());
1947
        }
1948

    
1949
        @Override
1950
        public List<String> toStrings(Formatter formatter) {
1951
            List<String> sqls = new ArrayList<>();
1952
            if (this.isEmpty()) {
1953
                return sqls;
1954
            }
1955
            for (String column : drops) {
1956
                StringBuilder builder = new StringBuilder();
1957
                builder.append("ALTER TABLE ");
1958
                builder.append(this.table.toString(formatter));
1959
                builder.append(" DROP COLUMN IF EXISTS ");
1960
                builder.append(as_identifier(column));
1961
                sqls.add(builder.toString());
1962
            }
1963
            for (ColumnDescriptor column : adds) {
1964
                StringBuilder builder = new StringBuilder();
1965
                builder.append("ALTER TABLE ");
1966
                builder.append(this.table.toString(formatter));
1967
                builder.append(" ADD COLUMN ");
1968
                builder.append(as_identifier(column.getName()));
1969
                builder.append(" ");
1970
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1971
                    builder.append(" SERIAL");
1972
                } else {
1973
                    builder.append(
1974
                            sqltype(
1975
                                    column.getType(),
1976
                                    column.getSize(),
1977
                                    column.getPrecision(),
1978
                                    column.getScale(),
1979
                                    column.getGeometryType(),
1980
                                    column.getGeometrySubtype()
1981
                            )
1982
                    );
1983
                }
1984
                if (column.getDefaultValue() == null) {
1985
                    if (column.allowNulls()) {
1986
                        builder.append(" DEFAULT NULL");
1987
                    }
1988
                } else {
1989
                    builder.append(" DEFAULT '");
1990
                    builder.append(Objects.toString(column.getDefaultValue(),""));
1991
                    builder.append("'");
1992
                }
1993
                if (column.allowNulls()) {
1994
                    builder.append(" NULL");
1995
                } else {
1996
                    builder.append(" NOT NULL");
1997
                }
1998
                if (column.isPrimaryKey()) {
1999
                    builder.append(" PRIMARY KEY");
2000
                }
2001
                sqls.add(builder.toString());
2002
            }
2003
            for (ColumnDescriptor column : alters) {
2004
                StringBuilder builder = new StringBuilder();
2005
                builder.append("ALTER TABLE ");
2006
                builder.append(this.table.toString(formatter));
2007
                builder.append(" ALTER COLUMN ");
2008
                builder.append(as_identifier(column.getName()));
2009
                builder.append(" SET DATA TYPE ");
2010
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2011
                    builder.append(" SERIAL");
2012
                } else {
2013
                    builder.append(
2014
                            sqltype(
2015
                                    column.getType(),
2016
                                    column.getSize(),
2017
                                    column.getPrecision(),
2018
                                    column.getScale(),
2019
                                    column.getGeometryType(),
2020
                                    column.getGeometrySubtype()
2021
                            )
2022
                    );
2023
                }
2024
                if (column.getDefaultValue() == null) {
2025
                    if (column.allowNulls()) {
2026
                        builder.append(" DEFAULT NULL");
2027
                    } else {
2028
                        builder.append(" DROP DEFAULT");
2029
                    }
2030
                } else {
2031
                    builder.append(" DEFAULT '");
2032
                    builder.append(column.getDefaultValue().toString());
2033
                    builder.append("'");
2034
                }
2035
                sqls.add(builder.toString());
2036
            }
2037
            for (Pair<String, String> pair : renames) {
2038
                StringBuilder builder = new StringBuilder();
2039
                builder.append("ALTER TABLE ");
2040
                builder.append(this.table.toString(formatter));
2041
                builder.append(" RENAME COLUMN ");
2042
                builder.append(as_identifier(pair.getLeft()));
2043
                builder.append(" TO ");
2044
                builder.append(as_identifier(pair.getRight()));
2045
                sqls.add(builder.toString());
2046
            }
2047
            return sqls;
2048
        }
2049

    
2050
    }
2051

    
2052
    public class CreateTableBuilderBase
2053
            extends AbstractStatement
2054
            implements CreateTableBuilder {
2055

    
2056
        protected TableNameBuilder table;
2057
        protected List<ColumnDescriptor> columns;
2058

    
2059
        public CreateTableBuilderBase() {
2060
            this.columns = new ArrayList<>();
2061
        }
2062

    
2063
        @Override
2064
        public void accept(Visitor visitor, VisitorFilter filter) {
2065
            if (filter.accept(this)) {
2066
                visitor.visit(this);
2067
            }
2068
            if (this.table != null) {
2069
                this.table.accept(visitor, filter);
2070
            }
2071
        }
2072

    
2073
        @Override
2074
        public TableNameBuilder table() {
2075
            if (table == null) {
2076
                table = createTableNameBuilder();
2077
            }
2078
            return table;
2079
        }
2080

    
2081
        @Override
2082
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2083
            this.columns.add(new ColumnDescriptorBase(fad));
2084
            return this;
2085
        }
2086

    
2087
        @Override
2088
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2089
            if (StringUtils.isEmpty(columnName)) {
2090
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2091
            }
2092
            if (isPk || isAutomatic) {
2093
                allowNulls = false;
2094
            }
2095
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2096
            return this;
2097
        }
2098

    
2099
        @Override
2100
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2101
            if (StringUtils.isEmpty(columnName)) {
2102
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2103
            }
2104
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2105
            return this;
2106
        }
2107

    
2108
        @Override
2109
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2110
            if (StringUtils.isEmpty(columnName)) {
2111
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2112
            }
2113
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2114
            return this;
2115
        }
2116

    
2117
        @Override
2118
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2119
            if (StringUtils.isEmpty(columnName)) {
2120
                return null;
2121
            }
2122
            for (ColumnDescriptor column : columns) {
2123
                if (columnName.equals(column.getName())) {
2124
                    return column;
2125
                }
2126
            }
2127
            return null;
2128
        }
2129

    
2130
        @Override
2131
        public String toString() {
2132
            return this.toString(formatter());
2133
        }
2134

    
2135
        @Override
2136
        public String toString(Formatter<Value> formatter) {
2137
            if (formatter!=null && formatter.canApply(this)) {
2138
                return formatter.format(this);
2139
            }
2140
            StringBuilder builder = new StringBuilder();
2141
            boolean first = true;
2142
            for (String sql : toStrings(formatter)) {
2143
                if (StringUtils.isEmpty(sql)) {
2144
                    continue;
2145
                }
2146
                if (first) {
2147
                    first = false;
2148
                } else {
2149
                    builder.append("; ");
2150
                }
2151
                builder.append(sql);
2152
            }
2153
            return builder.toString();
2154
        }
2155

    
2156
        @Override
2157
        public List<String> toStrings() {
2158
            return this.toStrings(formatter());
2159
        }
2160

    
2161
        @Override
2162
        public List<String> toStrings(Formatter formatter) {
2163
            List<String> sqls = new ArrayList<>();
2164
            /**
2165
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2166
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2167
             * column_constraint [ ... ] ] | table_constraint | LIKE
2168
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2169
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2170
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2171
             *
2172
             * where column_constraint is:
2173
             *
2174
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2175
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2176
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2177
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2178
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2179
             *
2180
             * and table_constraint is:
2181
             *
2182
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2183
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2184
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2185
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2186
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2187
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2188
             */
2189
            StringBuilder builder = new StringBuilder();
2190

    
2191
            builder.append("CREATE TABLE ");
2192
            builder.append(this.table.toString(formatter));
2193
            builder.append(" (");
2194
            boolean first = true;
2195
            for (ColumnDescriptor column : columns) {
2196
                if (first) {
2197
                    first = false;
2198
                } else {
2199
                    builder.append(", ");
2200
                }
2201
                builder.append(as_identifier(column.getName()));
2202
                builder.append(" ");
2203
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2204
                    builder.append("SERIAL");
2205
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2206
                    builder.append("BIGSERIAL");
2207
                } else {
2208
                    builder.append(sqltype(
2209
                            column.getType(),
2210
                            column.getSize(),
2211
                            column.getPrecision(),
2212
                            column.getScale(),
2213
                            column.getGeometryType(),
2214
                            column.getGeometrySubtype()
2215
                    )
2216
                    );
2217
                }
2218
                if (column.getDefaultValue() == null) {
2219
                    if (column.allowNulls()) {
2220
                        builder.append(" DEFAULT NULL");
2221
                    }
2222
                } else {
2223
                    builder.append(" DEFAULT '");
2224
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2225
                    builder.append("'");
2226
                }
2227
                if (column.allowNulls()) {
2228
                    builder.append(" NULL");
2229
                } else {
2230
                    builder.append(" NOT NULL");
2231
                }
2232
                if (column.isPrimaryKey()) {
2233
                    builder.append(" PRIMARY KEY");
2234
                }
2235
            }
2236
            builder.append(" )");
2237
            sqls.add(builder.toString());
2238
            return sqls;
2239
        }
2240
    }
2241

    
2242
    public class InsertColumnBuilderBase
2243
            extends AbstractStatement
2244
            implements InsertColumnBuilder {
2245

    
2246
        protected Variable name;
2247
        protected Value value;
2248

    
2249
        public InsertColumnBuilderBase() {
2250
        }
2251

    
2252
        @Override
2253
        public void accept(Visitor visitor, VisitorFilter filter) {
2254
            if (filter.accept(this)) {
2255
                visitor.visit(this);
2256
            }
2257
            if (this.name != null) {
2258
                this.name.accept(visitor, filter);
2259
            }
2260
            if (this.value != null) {
2261
                this.value.accept(visitor, filter);
2262
            }
2263
        }
2264

    
2265
        @Override
2266
        public InsertColumnBuilder name(String name) {
2267
            this.name = expression().variable(name);
2268
            return this;
2269
        }
2270

    
2271
        @Override
2272
        public InsertColumnBuilder with_value(Value value) {
2273
            this.value = value;
2274
            return this;
2275
        }
2276

    
2277
        @Override
2278
        public String getName() {
2279
            return this.name.name();
2280
        }
2281

    
2282
        @Override
2283
        public Value getValue() {
2284
            return this.value;
2285
        }
2286

    
2287
        @Override
2288
        public String toString() {
2289
            return this.toString(formatter());
2290
        }
2291

    
2292
        @Override
2293
        public String toString(Formatter<Value> formatter) {
2294
            if (formatter!=null && formatter.canApply(this)) {
2295
                return formatter.format(this);
2296
            }
2297
            return this.value.toString(formatter);
2298
        }
2299
    }
2300

    
2301
    public class InsertBuilderBase
2302
            extends AbstractStatement
2303
            implements InsertBuilder {
2304

    
2305
        protected List<InsertColumnBuilder> columns;
2306
        protected TableNameBuilder table;
2307

    
2308
        public InsertBuilderBase() {
2309
            this.columns = new ArrayList<>();
2310
        }
2311

    
2312
        @Override
2313
        public void accept(Visitor visitor, VisitorFilter filter) {
2314
            if (filter.accept(this)) {
2315
                visitor.visit(this);
2316
            }
2317
            if (this.table != null) {
2318
                this.table.accept(visitor, filter);
2319
            }
2320
            for (InsertColumnBuilder column : columns) {
2321
                column.accept(visitor, filter);
2322
            }
2323
        }
2324

    
2325
        @Override
2326
        public TableNameBuilder table() {
2327
            if (table == null) {
2328
                table = createTableNameBuilder();
2329
            }
2330
            return table;
2331
        }
2332

    
2333
        @Override
2334
        public InsertColumnBuilder column() {
2335
            InsertColumnBuilder column = createInsertColumnBuilder();
2336
            this.columns.add(column);
2337
            return column;
2338
        }
2339

    
2340
        @Override
2341
        public String toString() {
2342
            return this.toString(formatter());
2343
        }
2344

    
2345
        @Override
2346
        public String toString(Formatter<Value> formatter) {
2347
            if (formatter!=null && formatter.canApply(this)) {
2348
                return formatter.format(this);
2349
            }
2350
            /*
2351
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2352
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2353
             * output_expression [ AS output_name ] [, ...] ]
2354
             */
2355
            StringBuilder builderColumns = new StringBuilder();
2356
            StringBuilder builderValues = new StringBuilder();
2357

    
2358
            boolean first = true;
2359
            for (InsertColumnBuilder column : columns) {
2360
                if (first) {
2361
                    first = false;
2362
                } else {
2363
                    builderColumns.append(", ");
2364
                }
2365
                builderColumns.append(as_identifier(column.getName()));
2366
            }
2367
            first = true;
2368
            for (InsertColumnBuilder column : columns) {
2369
                if (first) {
2370
                    first = false;
2371
                } else {
2372
                    builderValues.append(", ");
2373
                }
2374
                builderValues.append(column.toString(formatter));
2375
            }
2376

    
2377
            String sql = MessageFormat.format(
2378
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2379
                    this.table.toString(formatter),
2380
                    builderColumns.toString(),
2381
                    builderValues.toString()
2382
            );
2383
            return sql;
2384

    
2385
        }
2386
    }
2387

    
2388
    public class UpdateTableStatisticsBuilderBase
2389
            extends AbstractStatement
2390
            implements UpdateTableStatisticsBuilder {
2391

    
2392
        protected TableNameBuilder table;
2393

    
2394
        @Override
2395
        public void accept(Visitor visitor, VisitorFilter filter) {
2396
            if (filter.accept(this)) {
2397
                visitor.visit(this);
2398
            }
2399
            if (this.table != null) {
2400
                this.table.accept(visitor, filter);
2401
            }
2402
        }
2403

    
2404
        @Override
2405
        public TableNameBuilder table() {
2406
            if (table == null) {
2407
                table = createTableNameBuilder();
2408
            }
2409
            return table;
2410
        }
2411

    
2412
        @Override
2413
        public String toString() {
2414
            return this.toString(formatter());
2415
        }
2416

    
2417
        @Override
2418
        public String toString(Formatter<Value> formatter) {
2419
            if (formatter!=null && formatter.canApply(this)) {
2420
                return formatter.format(this);
2421
            }
2422
            StringBuilder builder = new StringBuilder();
2423
            boolean first = true;
2424
            for (String sql : toStrings(formatter)) {
2425
                if (StringUtils.isEmpty(sql)) {
2426
                    continue;
2427
                }
2428
                if (first) {
2429
                    first = false;
2430
                } else {
2431
                    builder.append("; ");
2432
                }
2433
                builder.append(sql);
2434
            }
2435
            return builder.toString();
2436
        }
2437

    
2438
        @Override
2439
        public List<String> toStrings() {
2440
            return this.toStrings(formatter());
2441
        }
2442

    
2443
        @Override
2444
        public List<String> toStrings(Formatter formatter) {
2445
            List<String> sqls = new ArrayList<>();
2446

    
2447
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2448
                String sql = MessageFormat.format(
2449
                        STMT_UPDATE_TABLE_STATISTICS_table,
2450
                        table.toString(formatter)
2451
                );
2452
                if (!StringUtils.isEmpty(sql)) {
2453
                    sqls.add(sql);
2454
                }
2455
            }
2456
            return sqls;
2457
        }
2458
    }
2459

    
2460
    protected GeometryExpressionBuilder expressionBuilder;
2461

    
2462
    protected String defaultSchema;
2463
    protected boolean supportSchemas;
2464
    protected boolean hasSpatialFunctions;
2465
    protected GeometrySupportType geometrySupportType;
2466
    protected boolean allowAutomaticValues;
2467

    
2468
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2469

    
2470
    protected String constant_true = "(1=1)";
2471
    protected String constant_false = "(1<>1)";
2472

    
2473
    protected String type_boolean = "BOOLEAN";
2474
    protected String type_byte = "TINYINT";
2475
    protected String type_bytearray = "BYTEA";
2476
    protected String type_geometry = "TEXT";
2477
    protected String type_char = "CHARACTER(1)";
2478
    protected String type_date = "DATE";
2479
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2480
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2481
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2482
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2483
    protected String type_int = "INT";
2484
    protected String type_long = "BIGINT";
2485
    protected String type_string = "TEXT";
2486
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2487
    protected String type_time = "TIME";
2488
    protected String type_timestamp = "TIMESTAMP";
2489
    protected String type_version = "VARCHAR(30)";
2490
    protected String type_URI = "TEXT";
2491
    protected String type_URL = "TEXT";
2492
    protected String type_FILE = "TEXT";
2493
    protected String type_FOLDER = "TEXT";
2494

    
2495
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2496
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2497
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2498
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2499
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2500
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2501
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2502
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2503
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2504
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2505

    
2506
    public SQLBuilderBase() {
2507
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2508

    
2509
        this.hasSpatialFunctions = false;
2510
        this.supportSchemas = true;
2511
        this.geometrySupportType = GeometrySupportType.WKT;
2512

    
2513
        this.defaultSchema = "public";
2514
        this.allowAutomaticValues = true;
2515

    
2516
    }
2517
    
2518
    @Override
2519
    public void setProperties(Class filter, final Object... values) {
2520
        this.accept(new Visitor() {
2521
            @Override
2522
            public void visit(Visitable v) {
2523
                for (int i = 0; i < values.length; i+=2) {
2524
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2525
                }
2526
            }
2527
        }, new ClassVisitorFilter(filter) );
2528
    }
2529

    
2530
    public String quote_for_identifiers() {
2531
        return "\"";
2532
    }
2533

    
2534
    public String quote_for_strings() {
2535
        return "'";
2536
    }
2537

    
2538
    @Override
2539
    public String as_identifier(String id) {
2540
        String quote = this.quote_for_identifiers();
2541
//        No se porque no esta disponible wrapIfMissing
2542
//        return StringUtils.wrapIfMissing(id,quote);
2543
        if (id.startsWith(quote)) {
2544
            return id;
2545
        }
2546
        return quote + id + quote;
2547

    
2548
    }
2549

    
2550
    @Override
2551
    public String as_string(String s) {
2552
        String quote = this.quote_for_strings();
2553
//        No se porque no esta disponible wrapIfMissing
2554
//        return StringUtils.wrapIfMissing(id,quote);
2555
        if (s.startsWith(quote)) {
2556
            return s;
2557
        }
2558
        return quote + s + quote;
2559

    
2560
    }
2561

    
2562
    @Override
2563
    public String as_string(byte[] data) {
2564
        return this.expressionBuilder.bytearray_0x(data);
2565
//        return this.expressionBuilder.bytearray_hex(data);
2566
//        return this.expressionBuilder.bytearray_x(data);
2567
    }
2568
    
2569
    @Override
2570
    public String as_string(boolean value) {
2571
        return value? "TRUE" : "FALSE";
2572
    }
2573

    
2574
    @Override
2575
    public String as_string(Number value) {
2576
        return Objects.toString(value);
2577
    }
2578
    
2579
    @Override
2580
    public String as_string(Object value) {
2581
        if( value == null ) {
2582
            return "NULL";
2583
        }
2584
        if( value instanceof CharSequence ) {
2585
            return as_string(value.toString());
2586
        }
2587
        if( value instanceof Number ) {
2588
            return as_string((Number)value);
2589
        }
2590
        if( value instanceof Boolean ) {
2591
            return as_string((boolean)value);
2592
        }
2593
        if( value instanceof byte[] ) {
2594
            return as_string((byte[])value);
2595
        }
2596
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2597
    }
2598
    
2599
    @Override
2600
    public GeometryExpressionBuilder expression() {
2601
        return this.expressionBuilder;
2602
    }
2603

    
2604
    @Override
2605
    public boolean has_spatial_functions() {
2606
        return this.hasSpatialFunctions;
2607
    }
2608

    
2609
    @Override
2610
    public GeometrySupportType geometry_support_type() {
2611
        return this.geometrySupportType;
2612
    }
2613

    
2614
    protected GeometryExpressionBuilder createExpressionBuilder() {
2615
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2616
    }
2617

    
2618
    @Override
2619
    public Object srs_id(IProjection projection) {
2620
        String abrev = projection.getAbrev();
2621
        return abrev.split(":")[1].trim();
2622
    }
2623

    
2624
    @Override
2625
    public String default_schema() {
2626
        return this.defaultSchema;
2627
    }
2628

    
2629
    @Override
2630
    public boolean support_schemas() {
2631
        return this.supportSchemas;
2632
    }
2633

    
2634
    @Override
2635
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2636
        switch (type) {
2637
            case DataTypes.BOOLEAN:
2638
                return type_boolean;
2639
            case DataTypes.CHAR:
2640
                return type_char;
2641

    
2642

    
2643
            case DataTypes.BYTE:
2644
                return type_byte;
2645
            case DataTypes.INT:
2646
                return type_int;
2647
            case DataTypes.LONG:
2648
                return type_long;
2649

    
2650
            case DataTypes.FLOAT:
2651
                return type_float;
2652
            case DataTypes.DOUBLE:
2653
                return type_double;
2654
            case DataTypes.DECIMAL:
2655
                if (precision < 1) {
2656
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2657
                }
2658
                if (scale < 1) {
2659
                  return MessageFormat.format(type_decimal_p, precision);
2660
                }
2661
                return MessageFormat.format(type_decimal_ps, precision, scale);
2662

    
2663
                
2664
            case DataTypes.STRING:
2665
                if (size < 0) {
2666
                    return type_string;
2667
                } else if (size < 4096) {
2668
                    return MessageFormat.format(type_string_p, size);
2669
                }
2670
                return type_string;
2671

    
2672
                
2673
            case DataTypes.DATE:
2674
                return type_date;
2675
            case DataTypes.TIME:
2676
                return type_time;
2677
            case DataTypes.TIMESTAMP:
2678
                return type_timestamp;
2679

    
2680
            case DataTypes.BYTEARRAY:
2681
                return type_bytearray;
2682

    
2683
            case DataTypes.GEOMETRY:
2684
                return type_geometry;
2685

    
2686
            case DataTypes.VERSION:
2687
                return type_version;
2688
            case DataTypes.URI:
2689
                return type_URI;
2690
            case DataTypes.URL:
2691
                return type_URL;
2692
            case DataTypes.FILE:
2693
                return type_FILE;
2694
            case DataTypes.FOLDER:
2695
                return type_FOLDER;
2696
            default:
2697
                return null;
2698
        }
2699
    }
2700

    
2701
    @Override
2702
    public Object sqlgeometrytype(int type, int subtype) {
2703
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2704
        // identificadores numericos para el tipo y otros strings.
2705
        // Por defecto vamos a devolver strings.
2706
        if (sqlgeometrytypes == null) {
2707
            sqlgeometrytypes = new HashMap<>();
2708
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2709
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2710
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2711
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2712

    
2713
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2714
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2715
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2716
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2717

    
2718
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2719
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2720
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2721
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2722

    
2723
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2724
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2725
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2726
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2727

    
2728
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2729
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2730
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2731
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2732

    
2733
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2734
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2735
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2736
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2737

    
2738
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2739
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2740
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2741
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2742

    
2743
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2744
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2745
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2746
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2747

    
2748
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2749
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2750
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2751
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2752
        }
2753
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2754
    }
2755

    
2756
    @Override
2757
    public Object sqlgeometrydimension(int type, int subtype) {
2758
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2759
        // identificadores numericos para las dimensiones y otros strings.
2760
        // Por defecto vamos a devolver enteros.
2761
        switch (subtype) {
2762
            case Geometry.SUBTYPES.GEOM3D:
2763
                return 3;
2764
            case Geometry.SUBTYPES.GEOM2DM:
2765
                return 3;
2766
            case Geometry.SUBTYPES.GEOM3DM:
2767
                return 4;
2768
            case Geometry.SUBTYPES.GEOM2D:
2769
            default:
2770
                return 2;
2771
        }
2772
    }
2773

    
2774
    @Override
2775
    public TableNameBuilder createTableNameBuilder() {
2776
        return new TableNameBuilderBase();
2777
    }
2778

    
2779
    protected SelectColumnBuilder createSelectColumnBuilder() {
2780
        return new SelectColumnBuilderBase();
2781
    }
2782

    
2783
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2784
        return new UpdateColumnBuilderBase();
2785
    }
2786

    
2787
    protected InsertColumnBuilder createInsertColumnBuilder() {
2788
        return new InsertColumnBuilderBase();
2789
    }
2790

    
2791
    protected OrderByBuilder createOrderByBuilder() {
2792
        return new OrderByBuilderBase();
2793
    }
2794

    
2795
    protected FromBuilder createFromBuilder() {
2796
        return new FromBuilderBase();
2797
    }
2798

    
2799
    protected SelectBuilder createSelectBuilder() {
2800
        return new SelectBuilderBase();
2801
    }
2802

    
2803
    protected UpdateBuilder createUpdateBuilder() {
2804
        return new UpdateBuilderBase();
2805
    }
2806

    
2807
    protected DeleteBuilder createDeleteBuilder() {
2808
        return new DeleteBuilderBase();
2809
    }
2810

    
2811
    protected GrantBuilder createGrantBuilder() {
2812
        return new GrantBuilderBase();
2813
    }
2814

    
2815
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2816
        return new GrantRoleBuilderBase(table, role);
2817
    }
2818

    
2819
    protected DropTableBuilder createDropTableBuilder() {
2820
        return new DropTableBuilderBase();
2821
    }
2822

    
2823
    protected CreateTableBuilder createCreateTableBuilder() {
2824
        return new CreateTableBuilderBase();
2825
    }
2826

    
2827
    protected AlterTableBuilder createAlterTableBuilder() {
2828
        return new AlterTableBuilderBase();
2829
    }
2830

    
2831
    protected InsertBuilder createInsertBuilder() {
2832
        return new InsertBuilderBase();
2833
    }
2834

    
2835
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2836
        return new UpdateTableStatisticsBuilderBase();
2837
    }
2838

    
2839
    protected CreateIndexBuilder createCreateIndexBuilder() {
2840
        return new CreateIndexBuilderBase();
2841
    }
2842

    
2843
    @Override
2844
    public SelectBuilder select() {
2845
        if (this.select == null) {
2846
            this.select = this.createSelectBuilder();
2847
        }
2848
        return this.select;
2849
    }
2850

    
2851
    @Override
2852
    public UpdateBuilder update() {
2853
        if (this.update == null) {
2854
            this.update = this.createUpdateBuilder();
2855
        }
2856
        return this.update;
2857
    }
2858

    
2859
    @Override
2860
    public UpdateTableStatisticsBuilder update_table_statistics() {
2861
        if (this.update_table_statistics == null) {
2862
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2863
        }
2864
        return this.update_table_statistics;
2865
    }
2866

    
2867
    @Override
2868
    public DropTableBuilder drop_table() {
2869
        if (this.drop_table == null) {
2870
            this.drop_table = this.createDropTableBuilder();
2871
        }
2872
        return this.drop_table;
2873
    }
2874

    
2875
    @Override
2876
    public CreateIndexBuilder create_index() {
2877
        if (this.create_index == null) {
2878
            this.create_index = this.createCreateIndexBuilder();
2879
        }
2880
        return this.create_index;
2881
    }
2882

    
2883
    @Override
2884
    public DeleteBuilder delete() {
2885
        if (this.delete == null) {
2886
            this.delete = this.createDeleteBuilder();
2887
        }
2888
        return this.delete;
2889
    }
2890

    
2891
    @Override
2892
    public InsertBuilder insert() {
2893
        if (this.insert == null) {
2894
            this.insert = this.createInsertBuilder();
2895
        }
2896
        return this.insert;
2897
    }
2898

    
2899
    @Override
2900
    public TableNameBuilder table_name() {
2901
        if (this.table_name == null) {
2902
            this.table_name = this.createTableNameBuilder();
2903
        }
2904
        return this.table_name;
2905
    }
2906

    
2907
    
2908
    @Override
2909
    public AlterTableBuilder alter_table() {
2910
        if (this.alter_table == null) {
2911
            this.alter_table = this.createAlterTableBuilder();
2912
        }
2913
        return this.alter_table;
2914
    }
2915

    
2916
    @Override
2917
    public CreateTableBuilder create_table() {
2918
        if (this.create_table == null) {
2919
            this.create_table = this.createCreateTableBuilder();
2920
        }
2921
        return this.create_table;
2922
    }
2923

    
2924
    @Override
2925
    public GrantBuilder grant() {
2926
        if (this.grant == null) {
2927
            this.grant = this.createGrantBuilder();
2928
        }
2929
        return this.grant;
2930
    }
2931
    
2932
    @Override
2933
    public Column column(String name) {
2934
        ColumnBase col = new ColumnBase(null, name);
2935
        return col;
2936
    }
2937

    
2938
    @Override
2939
    public Column column(TableNameBuilder table, String name) {
2940
        ColumnBase col = new ColumnBase(table, name);
2941
        return col;
2942
    }
2943
    
2944
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2945
        return new JoinBase(type, table, expression);
2946
    }
2947

    
2948
    public void accept(Visitor visitor, VisitorFilter filter) {
2949
        if (this.select != null) {
2950
            this.select.accept(visitor, filter);
2951
        }
2952
        if (this.update != null) {
2953
            this.update.accept(visitor, filter);
2954
        }
2955
        if (this.insert != null) {
2956
            this.insert.accept(visitor, filter);
2957
        }
2958
        if (this.delete != null) {
2959
            this.delete.accept(visitor, filter);
2960
        }
2961
        if (this.alter_table != null) {
2962
            this.alter_table.accept(visitor, filter);
2963
        }
2964
        if (this.create_table != null) {
2965
            this.create_table.accept(visitor, filter);
2966
        }
2967
        if (this.drop_table != null) {
2968
            this.drop_table.accept(visitor, filter);
2969
        }
2970
        if (this.table_name != null) {
2971
            this.table_name.accept(visitor, filter);
2972
        }
2973
    }
2974

    
2975
    protected Formatter formatter() {
2976
        return ExpressionBuilder.EMPTY_FORMATTER;
2977
    }
2978

    
2979
    @Override
2980
    public String toString() {
2981
        return this.toString(formatter());
2982
    }
2983

    
2984
    @Override
2985
    public String toString(Formatter formatter) {
2986
        if (this.select != null) {
2987
            return this.select.toString(formatter);
2988
        }
2989
        if (this.update != null) {
2990
            return this.update.toString(formatter);
2991
        }
2992
        if (this.insert != null) {
2993
            return this.insert.toString(formatter);
2994
        }
2995
        if (this.delete != null) {
2996
            return this.delete.toString(formatter);
2997
        }
2998
        if (this.alter_table != null) {
2999
            return this.alter_table.toString(formatter);
3000
        }
3001
        if (this.create_table != null) {
3002
            return this.create_table.toString(formatter);
3003
        }
3004
        if (this.drop_table != null) {
3005
            return this.drop_table.toString(formatter);
3006
        }
3007
        if (this.update_table_statistics != null) {
3008
            return this.update_table_statistics.toString(formatter);
3009
        }
3010
        if (this.table_name != null) {
3011
            return this.table_name.toString(formatter);
3012
        }
3013
        return "";
3014
    }
3015

    
3016
    @Override
3017
    public CountBuilder count() {
3018
        return new CountBuilderBase();
3019
    }
3020

    
3021
    @Override
3022
    public List<Parameter> parameters() {
3023
        final List<Parameter> params = new ArrayList<>();
3024
        this.accept(new Visitor() {
3025
            @Override
3026
            public void visit(Visitable value) {
3027
                params.add((Parameter) value);
3028
            }
3029
        }, new ClassVisitorFilter(Parameter.class));
3030
        return params;
3031
    }
3032

    
3033
    @Override
3034
    public List<Variable> variables() {
3035
        final List<Variable> vars = new ArrayList<>();
3036
        this.accept(new Visitor() {
3037
            @Override
3038
            public void visit(Visitable value) {
3039
                if (!vars.contains((Variable) value)) {
3040
                    vars.add((Variable) value);
3041
                }
3042
            }
3043
        }, new ClassVisitorFilter(Variable.class));
3044
        return vars;
3045
    }
3046

    
3047
    @Override
3048
    public List<String> parameters_names() {
3049
        List<String> params = new ArrayList<>();
3050
        for (Parameter param : parameters()) {
3051
            String s;
3052
            switch (param.type()) {
3053
                case PARAMETER_TYPE_CONSTANT:
3054
                    Object theValue = param.value();
3055
                    if (theValue == null) {
3056
                        s = "null";
3057
                    } else if (theValue instanceof String) {
3058
                        s = "'" + (String) theValue + "'";
3059
                    } else {
3060
                        s = theValue.toString();
3061
                    }
3062
                    break;
3063
                case PARAMETER_TYPE_VARIABLE:
3064
                default:
3065
                    s = "\"" + param.name() + "\"";
3066
            }
3067
            params.add(s);
3068
        }
3069
        return params;
3070
    }
3071

    
3072
    @Override
3073
    public List<String> variables_names() {
3074
        List<String> vars = new ArrayList<>();
3075
        for (Variable var : this.variables()) {
3076
            vars.add(var.name());
3077
        }
3078
        Collections.sort(vars);
3079
        return vars;
3080
    }
3081
}