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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1119
        @Override
1120
        public String toString() {
1121
            return this.toString(formatter());
1122
        }
1123

    
1124
        @Override
1125
        public String toString(Formatter<Value> formatter) {
1126
            if (formatter!=null && formatter.canApply(this)) {
1127
                return formatter.format(this);
1128
            }
1129
            StringBuilder builder = new StringBuilder();
1130
            if (!this.isValid(builder)) {
1131
                throw new IllegalStateException(builder.toString());
1132
            }
1133
            builder.append("SELECT ");
1134
            if (this.distinct) {
1135
                builder.append("DISTINCT ");
1136
            }
1137
            boolean first = true;
1138
            for (SelectColumnBuilder column : columns) {
1139
                if (first) {
1140
                    first = false;
1141
                } else {
1142
                    builder.append(", ");
1143
                }
1144
                builder.append(column.toString(formatter));
1145
            }
1146

    
1147
            if (this.has_from()) {
1148
                builder.append(" FROM ");
1149
                builder.append(this.from.toString(formatter));
1150
            }
1151
            if (this.has_where()) {
1152
                builder.append(" WHERE ");
1153
                builder.append(this.where.toString(formatter));
1154
            }
1155
            if( this.has_group_by() ) {
1156
                builder.append(" GROUP BY ");
1157
                builder.append(this.groupColumn.get(0).toString(formatter));
1158
                for (int i = 1; i < groupColumn.size(); i++) {
1159
                    builder.append(", ");
1160
                    builder.append(this.groupColumn.get(i).toString(formatter));
1161
                }
1162
            }
1163
            if (this.has_order_by()) {
1164
                builder.append(" ORDER BY ");
1165
                first = true;
1166
                for (OrderByBuilder item : this.order_by) {
1167
                    if (first) {
1168
                        first = false;
1169
                    } else {
1170
                        builder.append(", ");
1171
                    }
1172
                    builder.append(item.toString(formatter));
1173
                }
1174
            }
1175

    
1176
            if (this.has_limit()) {
1177
                builder.append(" LIMIT ");
1178
                builder.append(this.limit);
1179
            }
1180
            if (this.has_offset()) {
1181
                builder.append(" OFFSET ");
1182
                builder.append(this.offset);
1183
            }
1184
            return builder.toString();
1185

    
1186
        }
1187
    }
1188

    
1189
    public class DropTableBuilderBase
1190
            extends AbstractStatement
1191
            implements DropTableBuilder {
1192

    
1193
        protected TableNameBuilder table;
1194

    
1195
        @Override
1196
        public TableNameBuilder table() {
1197
            if (table == null) {
1198
                table = createTableNameBuilder();
1199
            }
1200
            return table;
1201
        }
1202

    
1203
        @Override
1204
        public void accept(Visitor visitor, VisitorFilter filter) {
1205
            if (filter.accept(this)) {
1206
                visitor.visit(this);
1207
            }
1208
            this.table.accept(visitor, filter);
1209
        }
1210

    
1211
        @Override
1212
        public String toString() {
1213
            return this.toString(formatter());
1214
        }
1215

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

    
1237
        @Override
1238
        public List<String> toStrings() {
1239
            return this.toStrings(formatter());
1240
        }
1241

    
1242
        @Override
1243
        public List<String> toStrings(Formatter formatter) {
1244
            List<String> sqls = new ArrayList<>();
1245

    
1246
            sqls.add(
1247
                    MessageFormat.format(
1248
                            STMT_DROP_TABLE_table,
1249
                            this.table.toString(formatter)
1250
                    )
1251
            );
1252
            String sql;
1253
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1254
                if (this.table.has_schema()) {
1255
                    sql = MessageFormat.format(
1256
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1257
                            as_string(this.table.getSchema()),
1258
                            as_string(this.table.getName())
1259
                    );
1260
                } else {
1261
                    sql = MessageFormat.format(
1262
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1263
                            as_identifier(this.table.getName())
1264
                    );
1265
                }
1266
                if (!StringUtils.isEmpty(sql)) {
1267
                    sqls.add(sql);
1268
                }
1269
            }
1270
            return sqls;
1271
        }
1272
    }
1273

    
1274
    public class GrantRoleBuilderBase
1275
            extends AbstractStatementPart
1276
            implements GrantRoleBuilder {
1277

    
1278
        protected TableNameBuilder table;
1279
        protected String role;
1280
        protected Set<Privilege> privileges;
1281

    
1282
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1283
            this.table = table;
1284
            this.role = role;
1285
            this.privileges = new HashSet<>();
1286
        }
1287

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

    
1294
        @Override
1295
        public GrantRoleBuilder select() {
1296
            privileges.add(Privilege.SELECT);
1297
            return this;
1298
        }
1299

    
1300
        @Override
1301
        public GrantRoleBuilder update() {
1302
            privileges.add(Privilege.UPDATE);
1303
            return this;
1304
        }
1305

    
1306
        @Override
1307
        public GrantRoleBuilder insert() {
1308
            privileges.add(Privilege.INSERT);
1309
            return this;
1310
        }
1311

    
1312
        @Override
1313
        public GrantRoleBuilder delete() {
1314
            privileges.add(Privilege.DELETE);
1315
            return this;
1316
        }
1317

    
1318
        @Override
1319
        public GrantRoleBuilder truncate() {
1320
            privileges.add(Privilege.TRUNCATE);
1321
            return this;
1322
        }
1323

    
1324
        @Override
1325
        public GrantRoleBuilder reference() {
1326
            privileges.add(Privilege.REFERENCE);
1327
            return this;
1328
        }
1329

    
1330
        @Override
1331
        public GrantRoleBuilder trigger() {
1332
            privileges.add(Privilege.TRIGGER);
1333
            return this;
1334
        }
1335

    
1336
        @Override
1337
        public GrantRoleBuilder all() {
1338
            privileges.add(Privilege.ALL);
1339
            return this;
1340
        }
1341

    
1342
        protected String getPrivilegeName(Privilege privilege) {
1343
            switch (privilege) {
1344
                case DELETE:
1345
                    return "DELETE";
1346
                case INSERT:
1347
                    return "INSERT";
1348
                case REFERENCE:
1349
                    return "REFERENCE";
1350
                case SELECT:
1351
                    return "SELECT";
1352
                case TRIGGER:
1353
                    return "TRIGGER";
1354
                case TRUNCATE:
1355
                    return "TRUNCATE";
1356
                case UPDATE:
1357
                    return "UPDATE";
1358
                case ALL:
1359
                default:
1360
                    return "ALL";
1361
            }
1362
        }
1363

    
1364
        @Override
1365
        public String toString() {
1366
            return this.toString(formatter());
1367
        }
1368

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

    
1394
    public class GrantBuilderBase
1395
            extends AbstractStatement
1396
            implements GrantBuilder {
1397

    
1398
        protected TableNameBuilder table;
1399
        protected Map<String, GrantRoleBuilder> roles;
1400

    
1401
        public GrantBuilderBase() {
1402
            this.roles = new HashMap<>();
1403
        }
1404

    
1405
        @Override
1406
        public TableNameBuilder table() {
1407
            if (table == null) {
1408
                table = createTableNameBuilder();
1409
            }
1410
            return table;
1411
        }
1412

    
1413
        @Override
1414
        public void accept(Visitor visitor, VisitorFilter filter) {
1415
            if (filter.accept(this)) {
1416
                visitor.visit(this);
1417
            }
1418
            if (this.table != null) {
1419
                this.table.accept(visitor, filter);
1420
            }
1421
        }
1422

    
1423
        @Override
1424
        public GrantRoleBuilder role(String role) {
1425
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1426
            if (roleBuilder == null) {
1427
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1428
                this.roles.put(role, roleBuilder);
1429
            }
1430
            return roleBuilder;
1431
        }
1432

    
1433
        @Override
1434
        public String toString() {
1435
            return this.toString(formatter());
1436
        }
1437

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

    
1459
        @Override
1460
        public List<String> toStrings() {
1461
            return this.toStrings(formatter());
1462
        }
1463

    
1464
        @Override
1465
        public List<String> toStrings(Formatter formatter) {
1466
            List<String> sqls = new ArrayList<>();
1467
            for (GrantRoleBuilder role : roles.values()) {
1468
                sqls.add(role.toString(formatter));
1469
            }
1470
            return sqls;
1471
        }
1472
    }
1473

    
1474
    public class UpdateColumnBuilderBase
1475
            extends InsertColumnBuilderBase
1476
            implements UpdateColumnBuilder {
1477

    
1478
        public UpdateColumnBuilderBase() {
1479
            super();
1480
        }
1481

    
1482
        @Override
1483
        public UpdateColumnBuilder name(String name) {
1484
            return (UpdateColumnBuilder) super.name(name);
1485
        }
1486

    
1487
        @Override
1488
        public UpdateColumnBuilder with_value(Value value) {
1489
            return (UpdateColumnBuilder) super.with_value(value);
1490
        }
1491

    
1492
    }
1493

    
1494
    public class UpdateBuilderBase
1495
            extends AbstractStatement
1496
            implements UpdateBuilder {
1497

    
1498
        protected GeometryExpressionBuilder where;
1499
        protected List<UpdateColumnBuilder> columns;
1500
        protected TableNameBuilder table;
1501

    
1502
        public UpdateBuilderBase() {
1503
            this.columns = new ArrayList<>();
1504
        }
1505

    
1506
        @Override
1507
        public void accept(Visitor visitor, VisitorFilter filter) {
1508
            if (filter.accept(this)) {
1509
                visitor.visit(this);
1510
            }
1511
            if (this.table != null) {
1512
                this.table.accept(visitor, filter);
1513
            }
1514
            for (UpdateColumnBuilder column : columns) {
1515
                column.accept(visitor, filter);
1516
            }
1517
            if (this.has_where()) {
1518
                this.where.accept(visitor, filter);
1519
            }
1520
        }
1521

    
1522
        @Override
1523
        public GeometryExpressionBuilder where() {
1524
            if (this.where == null) {
1525
                this.where = createExpressionBuilder();
1526
            }
1527
            return this.where;
1528
        }
1529

    
1530
        @Override
1531
        public TableNameBuilder table() {
1532
            if (table == null) {
1533
                table = createTableNameBuilder();
1534
            }
1535
            return table;
1536
        }
1537

    
1538
        @Override
1539
        public UpdateColumnBuilder column() {
1540
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1541
            this.columns.add(column);
1542
            return column;
1543
        }
1544

    
1545
        @Override
1546
        public boolean has_where() {
1547
            return this.where != null;
1548
        }
1549

    
1550
        @Override
1551
        public String toString() {
1552
            return this.toString(formatter());
1553
        }
1554

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

    
1568
            boolean first = true;
1569
            for (UpdateColumnBuilder column : columns) {
1570
                if (first) {
1571
                    first = false;
1572
                } else {
1573
                    columnsAndValues.append(", ");
1574
                }
1575
                columnsAndValues.append(as_identifier(column.getName()));
1576
                columnsAndValues.append(" = ");
1577
                columnsAndValues.append(column.getValue().toString(formatter));
1578
            }
1579

    
1580
            String sql;
1581
            if (this.has_where()) {
1582
                sql = MessageFormat.format(
1583
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1584
                        this.table.toString(formatter),
1585
                        columnsAndValues.toString(),
1586
                        this.where.toString(formatter)
1587
                );
1588
            } else {
1589
                sql = MessageFormat.format(
1590
                        STMT_UPDATE_table_SET_columnsAndValues,
1591
                        this.table.toString(formatter),
1592
                        columnsAndValues.toString()
1593
                );
1594
            }
1595
            return sql;
1596
        }
1597
    }
1598

    
1599
    public class DeleteBuilderBase
1600
            extends AbstractStatement
1601
            implements DeleteBuilder {
1602

    
1603
        protected GeometryExpressionBuilder where;
1604
        protected TableNameBuilder table;
1605

    
1606
        public DeleteBuilderBase() {
1607
        }
1608

    
1609
        @Override
1610
        public void accept(Visitor visitor, VisitorFilter filter) {
1611
            if (filter.accept(this)) {
1612
                visitor.visit(this);
1613
            }
1614
            if (this.table != null) {
1615
                this.table.accept(visitor, filter);
1616
            }
1617
            if (this.has_where()) {
1618
                this.where.accept(visitor, filter);
1619
            }
1620
        }
1621

    
1622
        @Override
1623
        public GeometryExpressionBuilder where() {
1624
            if (this.where == null) {
1625
                this.where = createExpressionBuilder();
1626
            }
1627
            return this.where;
1628
        }
1629

    
1630
        @Override
1631
        public TableNameBuilder table() {
1632
            if (table == null) {
1633
                table = createTableNameBuilder();
1634
            }
1635
            return table;
1636
        }
1637

    
1638
        @Override
1639
        public boolean has_where() {
1640
            return this.where != null;
1641
        }
1642

    
1643
        @Override
1644
        public String toString() {
1645
            return this.toString(formatter());
1646
        }
1647

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

    
1674
    public class CreateIndexBuilderBase
1675
            extends AbstractStatement
1676
            implements CreateIndexBuilder {
1677

    
1678
        protected boolean ifNotExist = false;
1679
        protected boolean isUnique = false;
1680
        protected String indexName;
1681
        protected boolean isSpatial = false;
1682
        protected TableNameBuilder table;
1683
        protected final List<String> columns;
1684

    
1685
        public CreateIndexBuilderBase() {
1686
            this.columns = new ArrayList<>();
1687
        }
1688

    
1689
        @Override
1690
        public CreateIndexBuilder unique() {
1691
            this.isUnique = true;
1692
            return this;
1693
        }
1694

    
1695
        @Override
1696
        public CreateIndexBuilder if_not_exist() {
1697
            this.ifNotExist = true;
1698
            return this;
1699
        }
1700

    
1701
        @Override
1702
        public CreateIndexBuilder name(String name) {
1703
            this.indexName = name;
1704
            return this;
1705
        }
1706

    
1707
        @Override
1708
        public CreateIndexBuilder spatial() {
1709
            this.isSpatial = true;
1710
            return this;
1711
        }
1712

    
1713
        @Override
1714
        public CreateIndexBuilder column(String name) {
1715
            this.columns.add(name);
1716
            return this;
1717
        }
1718

    
1719
        @Override
1720
        public TableNameBuilder table() {
1721
            if (table == null) {
1722
                table = createTableNameBuilder();
1723
            }
1724
            return table;
1725
        }
1726

    
1727
        @Override
1728
        public void accept(Visitor visitor, VisitorFilter filter) {
1729
            if (filter.accept(this)) {
1730
                visitor.visit(this);
1731
            }
1732
            if (this.table != null) {
1733
                this.table.accept(visitor, filter);
1734
            }
1735
        }
1736

    
1737
        @Override
1738
        public String toString() {
1739
            return this.toString(formatter());
1740
        }
1741

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

    
1763
        @Override
1764
        public List<String> toStrings() {
1765
            return this.toStrings(formatter());
1766
        }
1767

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

    
1797
            List<String> sqls = new ArrayList<>();
1798
            sqls.add(builder.toString());
1799
            return sqls;
1800
        }
1801

    
1802
    }
1803

    
1804
    public class AlterTableBuilderBase
1805
            extends AbstractStatement
1806
            implements AlterTableBuilder {
1807

    
1808
        protected TableNameBuilder table;
1809
        protected List<String> drops;
1810
        protected List<ColumnDescriptor> adds;
1811
        protected List<ColumnDescriptor> alters;
1812
        protected List<Pair<String, String>> renames;
1813

    
1814
        public AlterTableBuilderBase() {
1815
            this.drops = new ArrayList<>();
1816
            this.adds = new ArrayList<>();
1817
            this.alters = new ArrayList<>();
1818
            this.renames = new ArrayList<>();
1819
        }
1820

    
1821
        @Override
1822
        public boolean isEmpty() {
1823
            return this.drops.isEmpty()
1824
                    && this.adds.isEmpty()
1825
                    && this.alters.isEmpty()
1826
                    && this.renames.isEmpty();
1827
        }
1828

    
1829
        @Override
1830
        public void accept(Visitor visitor, VisitorFilter filter) {
1831
            if (filter.accept(this)) {
1832
                visitor.visit(this);
1833
            }
1834
            if (this.table != null) {
1835
                this.table.accept(visitor, filter);
1836
            }
1837
        }
1838

    
1839
        @Override
1840
        public TableNameBuilder table() {
1841
            if (table == null) {
1842
                table = createTableNameBuilder();
1843
            }
1844
            return table;
1845
        }
1846

    
1847
        @Override
1848
        public AlterTableBuilder drop_column(String columnName) {
1849
            this.drops.add(columnName);
1850
            return this;
1851
        }
1852

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

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

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

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

    
1886
        @Override
1887
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1888
            this.alters.add(new ColumnDescriptorBase(fad));
1889
            return this;
1890
        }
1891

    
1892
        @Override
1893
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1894
            if (isPk || isAutomatic) {
1895
                allowNulls = false;
1896
            }
1897
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1898
            return this;
1899
        }
1900

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

    
1910
        @Override
1911
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1912
            if (StringUtils.isEmpty(columnName)) {
1913
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1914
            }
1915
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1916
            return this;
1917
        }
1918

    
1919
        @Override
1920
        public AlterTableBuilder rename_column(String source, String target) {
1921
            this.renames.add(new ImmutablePair(source, target));
1922
            return this;
1923
        }
1924

    
1925
        @Override
1926
        public String toString() {
1927
            return this.toString(formatter());
1928
        }
1929

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

    
1951
        @Override
1952
        public List<String> toStrings() {
1953
            return this.toStrings(formatter());
1954
        }
1955

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

    
2057
    }
2058

    
2059
    public class CreateTableBuilderBase
2060
            extends AbstractStatement
2061
            implements CreateTableBuilder {
2062

    
2063
        protected TableNameBuilder table;
2064
        protected List<ColumnDescriptor> columns;
2065

    
2066
        public CreateTableBuilderBase() {
2067
            this.columns = new ArrayList<>();
2068
        }
2069

    
2070
        @Override
2071
        public void accept(Visitor visitor, VisitorFilter filter) {
2072
            if (filter.accept(this)) {
2073
                visitor.visit(this);
2074
            }
2075
            if (this.table != null) {
2076
                this.table.accept(visitor, filter);
2077
            }
2078
        }
2079

    
2080
        @Override
2081
        public TableNameBuilder table() {
2082
            if (table == null) {
2083
                table = createTableNameBuilder();
2084
            }
2085
            return table;
2086
        }
2087

    
2088
        @Override
2089
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2090
            this.columns.add(new ColumnDescriptorBase(fad));
2091
            return this;
2092
        }
2093

    
2094
        @Override
2095
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2096
            if (StringUtils.isEmpty(columnName)) {
2097
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2098
            }
2099
            if (isPk || isAutomatic) {
2100
                allowNulls = false;
2101
            }
2102
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2103
            return this;
2104
        }
2105

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

    
2115
        @Override
2116
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2117
            if (StringUtils.isEmpty(columnName)) {
2118
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2119
            }
2120
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2121
            return this;
2122
        }
2123

    
2124
        @Override
2125
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2126
            if (StringUtils.isEmpty(columnName)) {
2127
                return null;
2128
            }
2129
            for (ColumnDescriptor column : columns) {
2130
                if (columnName.equals(column.getName())) {
2131
                    return column;
2132
                }
2133
            }
2134
            return null;
2135
        }
2136

    
2137
        @Override
2138
        public String toString() {
2139
            return this.toString(formatter());
2140
        }
2141

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

    
2163
        @Override
2164
        public List<String> toStrings() {
2165
            return this.toStrings(formatter());
2166
        }
2167

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

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

    
2249
    public class InsertColumnBuilderBase
2250
            extends AbstractStatement
2251
            implements InsertColumnBuilder {
2252

    
2253
        protected Variable name;
2254
        protected Value value;
2255

    
2256
        public InsertColumnBuilderBase() {
2257
        }
2258

    
2259
        @Override
2260
        public void accept(Visitor visitor, VisitorFilter filter) {
2261
            if (filter.accept(this)) {
2262
                visitor.visit(this);
2263
            }
2264
            if (this.name != null) {
2265
                this.name.accept(visitor, filter);
2266
            }
2267
            if (this.value != null) {
2268
                this.value.accept(visitor, filter);
2269
            }
2270
        }
2271

    
2272
        @Override
2273
        public InsertColumnBuilder name(String name) {
2274
            this.name = expression().variable(name);
2275
            return this;
2276
        }
2277

    
2278
        @Override
2279
        public InsertColumnBuilder with_value(Value value) {
2280
            this.value = value;
2281
            return this;
2282
        }
2283

    
2284
        @Override
2285
        public String getName() {
2286
            return this.name.name();
2287
        }
2288

    
2289
        @Override
2290
        public Value getValue() {
2291
            return this.value;
2292
        }
2293

    
2294
        @Override
2295
        public String toString() {
2296
            return this.toString(formatter());
2297
        }
2298

    
2299
        @Override
2300
        public String toString(Formatter<Value> formatter) {
2301
            if (formatter!=null && formatter.canApply(this)) {
2302
                return formatter.format(this);
2303
            }
2304
            return this.value.toString(formatter);
2305
        }
2306
    }
2307

    
2308
    public class InsertBuilderBase
2309
            extends AbstractStatement
2310
            implements InsertBuilder {
2311

    
2312
        protected List<InsertColumnBuilder> columns;
2313
        protected TableNameBuilder table;
2314

    
2315
        public InsertBuilderBase() {
2316
            this.columns = new ArrayList<>();
2317
        }
2318

    
2319
        @Override
2320
        public void accept(Visitor visitor, VisitorFilter filter) {
2321
            if (filter.accept(this)) {
2322
                visitor.visit(this);
2323
            }
2324
            if (this.table != null) {
2325
                this.table.accept(visitor, filter);
2326
            }
2327
            for (InsertColumnBuilder column : columns) {
2328
                column.accept(visitor, filter);
2329
            }
2330
        }
2331

    
2332
        @Override
2333
        public TableNameBuilder table() {
2334
            if (table == null) {
2335
                table = createTableNameBuilder();
2336
            }
2337
            return table;
2338
        }
2339

    
2340
        @Override
2341
        public InsertColumnBuilder column() {
2342
            InsertColumnBuilder column = createInsertColumnBuilder();
2343
            this.columns.add(column);
2344
            return column;
2345
        }
2346

    
2347
        @Override
2348
        public String toString() {
2349
            return this.toString(formatter());
2350
        }
2351

    
2352
        @Override
2353
        public String toString(Formatter<Value> formatter) {
2354
            if (formatter!=null && formatter.canApply(this)) {
2355
                return formatter.format(this);
2356
            }
2357
            /*
2358
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2359
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2360
             * output_expression [ AS output_name ] [, ...] ]
2361
             */
2362
            StringBuilder builderColumns = new StringBuilder();
2363
            StringBuilder builderValues = new StringBuilder();
2364

    
2365
            boolean first = true;
2366
            for (InsertColumnBuilder column : columns) {
2367
                if (first) {
2368
                    first = false;
2369
                } else {
2370
                    builderColumns.append(", ");
2371
                }
2372
                builderColumns.append(as_identifier(column.getName()));
2373
            }
2374
            first = true;
2375
            for (InsertColumnBuilder column : columns) {
2376
                if (first) {
2377
                    first = false;
2378
                } else {
2379
                    builderValues.append(", ");
2380
                }
2381
                builderValues.append(column.toString(formatter));
2382
            }
2383

    
2384
            String sql = MessageFormat.format(
2385
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2386
                    this.table.toString(formatter),
2387
                    builderColumns.toString(),
2388
                    builderValues.toString()
2389
            );
2390
            return sql;
2391

    
2392
        }
2393
    }
2394

    
2395
    public class UpdateTableStatisticsBuilderBase
2396
            extends AbstractStatement
2397
            implements UpdateTableStatisticsBuilder {
2398

    
2399
        protected TableNameBuilder table;
2400

    
2401
        @Override
2402
        public void accept(Visitor visitor, VisitorFilter filter) {
2403
            if (filter.accept(this)) {
2404
                visitor.visit(this);
2405
            }
2406
            if (this.table != null) {
2407
                this.table.accept(visitor, filter);
2408
            }
2409
        }
2410

    
2411
        @Override
2412
        public TableNameBuilder table() {
2413
            if (table == null) {
2414
                table = createTableNameBuilder();
2415
            }
2416
            return table;
2417
        }
2418

    
2419
        @Override
2420
        public String toString() {
2421
            return this.toString(formatter());
2422
        }
2423

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

    
2445
        @Override
2446
        public List<String> toStrings() {
2447
            return this.toStrings(formatter());
2448
        }
2449

    
2450
        @Override
2451
        public List<String> toStrings(Formatter formatter) {
2452
            List<String> sqls = new ArrayList<>();
2453

    
2454
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2455
                String sql = MessageFormat.format(
2456
                        STMT_UPDATE_TABLE_STATISTICS_table,
2457
                        table.toString(formatter)
2458
                );
2459
                if (!StringUtils.isEmpty(sql)) {
2460
                    sqls.add(sql);
2461
                }
2462
            }
2463
            return sqls;
2464
        }
2465
    }
2466

    
2467
    protected GeometryExpressionBuilder expressionBuilder;
2468

    
2469
    protected String defaultSchema;
2470
    protected boolean supportSchemas;
2471
    protected boolean hasSpatialFunctions;
2472
    protected GeometrySupportType geometrySupportType;
2473
    protected boolean allowAutomaticValues;
2474

    
2475
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2476

    
2477
    protected String constant_true = "(1=1)";
2478
    protected String constant_false = "(1<>1)";
2479

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

    
2502
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2503
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2504
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2505
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2506
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2507
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2508
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2509
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2510
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2511
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2512

    
2513
    public SQLBuilderBase() {
2514
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2515

    
2516
        this.hasSpatialFunctions = false;
2517
        this.supportSchemas = true;
2518
        this.geometrySupportType = GeometrySupportType.WKT;
2519

    
2520
        this.defaultSchema = "public";
2521
        this.allowAutomaticValues = true;
2522

    
2523
    }
2524
    
2525
    @Override
2526
    public void setProperties(Class filter, final Object... values) {
2527
        this.accept(new Visitor() {
2528
            @Override
2529
            public void visit(Visitable v) {
2530
                for (int i = 0; i < values.length; i+=2) {
2531
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2532
                }
2533
            }
2534
        }, new ClassVisitorFilter(filter) );
2535
    }
2536

    
2537
    public String quote_for_identifiers() {
2538
        return "\"";
2539
    }
2540

    
2541
    public String quote_for_strings() {
2542
        return "'";
2543
    }
2544

    
2545
    @Override
2546
    public String as_identifier(String id) {
2547
        String quote = this.quote_for_identifiers();
2548
//        No se porque no esta disponible wrapIfMissing
2549
//        return StringUtils.wrapIfMissing(id,quote);
2550
        if (id.startsWith(quote)) {
2551
            return id;
2552
        }
2553
        return quote + id + quote;
2554

    
2555
    }
2556

    
2557
    @Override
2558
    public String as_string(String s) {
2559
        String quote = this.quote_for_strings();
2560
//        No se porque no esta disponible wrapIfMissing
2561
//        return StringUtils.wrapIfMissing(id,quote);
2562
        if (s.startsWith(quote)) {
2563
            return s;
2564
        }
2565
        return quote + s + quote;
2566

    
2567
    }
2568

    
2569
    @Override
2570
    public String as_string(byte[] data) {
2571
        return this.expressionBuilder.bytearray_0x(data);
2572
//        return this.expressionBuilder.bytearray_hex(data);
2573
//        return this.expressionBuilder.bytearray_x(data);
2574
    }
2575
    
2576
    @Override
2577
    public String as_string(boolean value) {
2578
        return value? "TRUE" : "FALSE";
2579
    }
2580

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

    
2611
    @Override
2612
    public boolean has_spatial_functions() {
2613
        return this.hasSpatialFunctions;
2614
    }
2615

    
2616
    @Override
2617
    public GeometrySupportType geometry_support_type() {
2618
        return this.geometrySupportType;
2619
    }
2620

    
2621
    protected GeometryExpressionBuilder createExpressionBuilder() {
2622
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2623
    }
2624

    
2625
    @Override
2626
    public Object srs_id(IProjection projection) {
2627
        String abrev = projection.getAbrev();
2628
        return abrev.split(":")[1].trim();
2629
    }
2630

    
2631
    @Override
2632
    public String default_schema() {
2633
        return this.defaultSchema;
2634
    }
2635

    
2636
    @Override
2637
    public boolean support_schemas() {
2638
        return this.supportSchemas;
2639
    }
2640

    
2641
    @Override
2642
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2643
        switch (type) {
2644
            case DataTypes.BOOLEAN:
2645
                return type_boolean;
2646
            case DataTypes.CHAR:
2647
                return type_char;
2648

    
2649

    
2650
            case DataTypes.BYTE:
2651
                return type_byte;
2652
            case DataTypes.INT:
2653
                return type_int;
2654
            case DataTypes.LONG:
2655
                return type_long;
2656

    
2657
            case DataTypes.FLOAT:
2658
                return type_float;
2659
            case DataTypes.DOUBLE:
2660
                return type_double;
2661
            case DataTypes.DECIMAL:
2662
                if (precision < 1) {
2663
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2664
                }
2665
                if (scale < 1) {
2666
                  return MessageFormat.format(type_decimal_p, precision);
2667
                }
2668
                return MessageFormat.format(type_decimal_ps, precision, scale);
2669

    
2670
                
2671
            case DataTypes.STRING:
2672
                if (size < 0) {
2673
                    return type_string;
2674
                } else if (size < 4096) {
2675
                    return MessageFormat.format(type_string_p, size);
2676
                }
2677
                return type_string;
2678

    
2679
                
2680
            case DataTypes.DATE:
2681
                return type_date;
2682
            case DataTypes.TIME:
2683
                return type_time;
2684
            case DataTypes.TIMESTAMP:
2685
                return type_timestamp;
2686

    
2687
            case DataTypes.BYTEARRAY:
2688
                return type_bytearray;
2689

    
2690
            case DataTypes.GEOMETRY:
2691
                return type_geometry;
2692

    
2693
            case DataTypes.VERSION:
2694
                return type_version;
2695
            case DataTypes.URI:
2696
                return type_URI;
2697
            case DataTypes.URL:
2698
                return type_URL;
2699
            case DataTypes.FILE:
2700
                return type_FILE;
2701
            case DataTypes.FOLDER:
2702
                return type_FOLDER;
2703
            default:
2704
                return null;
2705
        }
2706
    }
2707

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

    
2720
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2721
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2722
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2723
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2724

    
2725
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2726
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2727
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2728
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2729

    
2730
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2731
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2732
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2733
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2734

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

    
2740
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2741
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2742
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2743
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2744

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

    
2750
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2751
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2752
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2753
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2754

    
2755
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2756
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2757
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2758
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2759
        }
2760
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2761
    }
2762

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

    
2781
    @Override
2782
    public TableNameBuilder createTableNameBuilder() {
2783
        return new TableNameBuilderBase();
2784
    }
2785

    
2786
    protected SelectColumnBuilder createSelectColumnBuilder() {
2787
        return new SelectColumnBuilderBase();
2788
    }
2789

    
2790
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2791
        return new UpdateColumnBuilderBase();
2792
    }
2793

    
2794
    protected InsertColumnBuilder createInsertColumnBuilder() {
2795
        return new InsertColumnBuilderBase();
2796
    }
2797

    
2798
    protected OrderByBuilder createOrderByBuilder() {
2799
        return new OrderByBuilderBase();
2800
    }
2801

    
2802
    protected FromBuilder createFromBuilder() {
2803
        return new FromBuilderBase();
2804
    }
2805

    
2806
    protected SelectBuilder createSelectBuilder() {
2807
        return new SelectBuilderBase();
2808
    }
2809

    
2810
    protected UpdateBuilder createUpdateBuilder() {
2811
        return new UpdateBuilderBase();
2812
    }
2813

    
2814
    protected DeleteBuilder createDeleteBuilder() {
2815
        return new DeleteBuilderBase();
2816
    }
2817

    
2818
    protected GrantBuilder createGrantBuilder() {
2819
        return new GrantBuilderBase();
2820
    }
2821

    
2822
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2823
        return new GrantRoleBuilderBase(table, role);
2824
    }
2825

    
2826
    protected DropTableBuilder createDropTableBuilder() {
2827
        return new DropTableBuilderBase();
2828
    }
2829

    
2830
    protected CreateTableBuilder createCreateTableBuilder() {
2831
        return new CreateTableBuilderBase();
2832
    }
2833

    
2834
    protected AlterTableBuilder createAlterTableBuilder() {
2835
        return new AlterTableBuilderBase();
2836
    }
2837

    
2838
    protected InsertBuilder createInsertBuilder() {
2839
        return new InsertBuilderBase();
2840
    }
2841

    
2842
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2843
        return new UpdateTableStatisticsBuilderBase();
2844
    }
2845

    
2846
    protected CreateIndexBuilder createCreateIndexBuilder() {
2847
        return new CreateIndexBuilderBase();
2848
    }
2849

    
2850
    @Override
2851
    public SelectBuilder select() {
2852
        if (this.select == null) {
2853
            this.select = this.createSelectBuilder();
2854
        }
2855
        return this.select;
2856
    }
2857

    
2858
    @Override
2859
    public UpdateBuilder update() {
2860
        if (this.update == null) {
2861
            this.update = this.createUpdateBuilder();
2862
        }
2863
        return this.update;
2864
    }
2865

    
2866
    @Override
2867
    public UpdateTableStatisticsBuilder update_table_statistics() {
2868
        if (this.update_table_statistics == null) {
2869
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2870
        }
2871
        return this.update_table_statistics;
2872
    }
2873

    
2874
    @Override
2875
    public DropTableBuilder drop_table() {
2876
        if (this.drop_table == null) {
2877
            this.drop_table = this.createDropTableBuilder();
2878
        }
2879
        return this.drop_table;
2880
    }
2881

    
2882
    @Override
2883
    public CreateIndexBuilder create_index() {
2884
        if (this.create_index == null) {
2885
            this.create_index = this.createCreateIndexBuilder();
2886
        }
2887
        return this.create_index;
2888
    }
2889

    
2890
    @Override
2891
    public DeleteBuilder delete() {
2892
        if (this.delete == null) {
2893
            this.delete = this.createDeleteBuilder();
2894
        }
2895
        return this.delete;
2896
    }
2897

    
2898
    @Override
2899
    public InsertBuilder insert() {
2900
        if (this.insert == null) {
2901
            this.insert = this.createInsertBuilder();
2902
        }
2903
        return this.insert;
2904
    }
2905

    
2906
    @Override
2907
    public TableNameBuilder table_name() {
2908
        if (this.table_name == null) {
2909
            this.table_name = this.createTableNameBuilder();
2910
        }
2911
        return this.table_name;
2912
    }
2913

    
2914
    
2915
    @Override
2916
    public AlterTableBuilder alter_table() {
2917
        if (this.alter_table == null) {
2918
            this.alter_table = this.createAlterTableBuilder();
2919
        }
2920
        return this.alter_table;
2921
    }
2922

    
2923
    @Override
2924
    public CreateTableBuilder create_table() {
2925
        if (this.create_table == null) {
2926
            this.create_table = this.createCreateTableBuilder();
2927
        }
2928
        return this.create_table;
2929
    }
2930

    
2931
    @Override
2932
    public GrantBuilder grant() {
2933
        if (this.grant == null) {
2934
            this.grant = this.createGrantBuilder();
2935
        }
2936
        return this.grant;
2937
    }
2938
    
2939
    @Override
2940
    public Column column(String name) {
2941
        ColumnBase col = new ColumnBase(null, name);
2942
        return col;
2943
    }
2944

    
2945
    @Override
2946
    public Column column(TableNameBuilder table, String name) {
2947
        ColumnBase col = new ColumnBase(table, name);
2948
        return col;
2949
    }
2950
    
2951
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2952
        return new JoinBase(type, table, expression);
2953
    }
2954

    
2955
    public void accept(Visitor visitor, VisitorFilter filter) {
2956
        if (this.select != null) {
2957
            this.select.accept(visitor, filter);
2958
        }
2959
        if (this.update != null) {
2960
            this.update.accept(visitor, filter);
2961
        }
2962
        if (this.insert != null) {
2963
            this.insert.accept(visitor, filter);
2964
        }
2965
        if (this.delete != null) {
2966
            this.delete.accept(visitor, filter);
2967
        }
2968
        if (this.alter_table != null) {
2969
            this.alter_table.accept(visitor, filter);
2970
        }
2971
        if (this.create_table != null) {
2972
            this.create_table.accept(visitor, filter);
2973
        }
2974
        if (this.drop_table != null) {
2975
            this.drop_table.accept(visitor, filter);
2976
        }
2977
        if (this.table_name != null) {
2978
            this.table_name.accept(visitor, filter);
2979
        }
2980
    }
2981

    
2982
    protected Formatter formatter() {
2983
        return ExpressionBuilder.BASE_FORMATTER;
2984
    }
2985

    
2986
    @Override
2987
    public String toString() {
2988
        return this.toString(formatter());
2989
    }
2990

    
2991
    @Override
2992
    public String toString(Formatter formatter) {
2993
        if (this.select != null) {
2994
            return this.select.toString(formatter);
2995
        }
2996
        if (this.update != null) {
2997
            return this.update.toString(formatter);
2998
        }
2999
        if (this.insert != null) {
3000
            return this.insert.toString(formatter);
3001
        }
3002
        if (this.delete != null) {
3003
            return this.delete.toString(formatter);
3004
        }
3005
        if (this.alter_table != null) {
3006
            return this.alter_table.toString(formatter);
3007
        }
3008
        if (this.create_table != null) {
3009
            return this.create_table.toString(formatter);
3010
        }
3011
        if (this.drop_table != null) {
3012
            return this.drop_table.toString(formatter);
3013
        }
3014
        if (this.update_table_statistics != null) {
3015
            return this.update_table_statistics.toString(formatter);
3016
        }
3017
        if (this.table_name != null) {
3018
            return this.table_name.toString(formatter);
3019
        }
3020
        return "";
3021
    }
3022

    
3023
    @Override
3024
    public CountBuilder count() {
3025
        return new CountBuilderBase();
3026
    }
3027

    
3028
    @Override
3029
    public List<Parameter> parameters() {
3030
        final List<Parameter> params = new ArrayList<>();
3031
        this.accept(new Visitor() {
3032
            @Override
3033
            public void visit(Visitable value) {
3034
                params.add((Parameter) value);
3035
            }
3036
        }, new ClassVisitorFilter(Parameter.class));
3037
        return params;
3038
    }
3039

    
3040
    @Override
3041
    public List<Variable> variables() {
3042
        final List<Variable> vars = new ArrayList<>();
3043
        this.accept(new Visitor() {
3044
            @Override
3045
            public void visit(Visitable value) {
3046
                if (!vars.contains((Variable) value)) {
3047
                    vars.add((Variable) value);
3048
                }
3049
            }
3050
        }, new ClassVisitorFilter(Variable.class));
3051
        return vars;
3052
    }
3053

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

    
3079
    @Override
3080
    public List<String> variables_names() {
3081
        List<String> vars = new ArrayList<>();
3082
        for (Variable var : this.variables()) {
3083
            vars.add(var.name());
3084
        }
3085
        Collections.sort(vars);
3086
        return vars;
3087
    }
3088
}