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

History | View | Annotate | Download (138 KB)

1 47779 fdiaz
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 static org.gvsig.expressionevaluator.ExpressionBuilder.VALUE_NULL;
23
import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
24
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
25
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
26
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
27
import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
28
import org.gvsig.expressionevaluator.Formatter;
29
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
30
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
31
import org.gvsig.expressionevaluator.GeometryExpressionEvaluatorLocator;
32
import org.gvsig.fmap.dal.DataManager;
33
import org.gvsig.fmap.dal.DataStoreParameters;
34
import org.gvsig.fmap.dal.DataTypes;
35
import org.gvsig.fmap.dal.SQLBuilder;
36
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
37
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
38
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
41
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
42
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
43
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
44
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
45
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
46
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
47
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
48
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
49
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
50
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
51
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
52
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
53
import org.gvsig.fmap.dal.feature.FeatureType;
54
import org.gvsig.fmap.geom.Geometry;
55
import org.gvsig.fmap.geom.GeometryUtils;
56
import org.gvsig.fmap.geom.primitive.Envelope;
57
import org.gvsig.tools.dataTypes.DataType;
58
import org.gvsig.tools.dynobject.Tags;
59
import org.gvsig.tools.lang.CloneableUtils;
60
import org.gvsig.tools.util.Bitmask;
61
import org.gvsig.tools.util.PropertiesSupport;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64
65
@SuppressWarnings("UseSpecificCatch")
66
public class SQLBuilderBase implements SQLBuilder {
67
68
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
69
70
    protected SelectBuilder select;
71
    protected UpdateBuilder update;
72
    protected MergeBuilder merge;
73
    protected InsertBuilder insert;
74
    protected DeleteBuilder delete;
75
    protected AlterTableBuilder alter_table;
76
    protected CreateTableBuilder create_table;
77
    protected GrantBuilder grant;
78
    protected DropTableBuilder drop_table;
79
    protected UpdateTableStatisticsBuilder update_table_statistics;
80
    protected CreateIndexBuilder create_index;
81
    protected DropIndexBuilder drop_index;
82
    protected TableNameBuilder table_name;
83
84
    protected abstract class AbstractStatementPart extends AbstractValue {
85
86
    }
87
88
    protected abstract class AbstractStatement extends AbstractStatementPart {
89
        @Override
90
        public Value clone() throws CloneNotSupportedException {
91
            throw new CloneNotSupportedException();
92
        }
93
    }
94
95
    protected class ColumnDescriptorBase implements ColumnDescriptor {
96
97
        private String name;
98
        private int type;
99
        private int size;
100
        private int precision;
101
        private int scale;
102
        private boolean isPk;
103
        private boolean _allowNulls;
104
        private boolean _allowIndexDuplicateds;
105
        private boolean _isAutomatic;
106
        private Object defaultValue;
107
        private int geom_type;
108
        private int geom_subtype;
109
        private Object geom_srsdbcode;
110
        private Envelope tablebbox;
111
        private boolean _isIndexed;
112
        private DataStoreParameters parameters = null;
113
114
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
115
            this.name = name;
116
            this.type = type;
117
            this.size = -1;
118
            this.precision = -1;
119
            this.scale = -1;
120
            this.isPk = false;
121
            this._allowNulls = true;
122
            this._isAutomatic = false;
123
            this.defaultValue = defaultValue;
124
            this.geom_type = Geometry.TYPES.GEOMETRY;
125
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
126
            this.geom_srsdbcode = null;
127
            this.tablebbox = null;
128
            this._isIndexed = false;
129
            this._allowIndexDuplicateds = true;
130
        }
131
132
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
133
            this(name, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, true);
134
        }
135
136
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue, boolean allowIndexDuplicateds) {
137
            this.name = name;
138
            this.type = type;
139
            this.size = size;
140
            this.precision = precision;
141
            this.scale = scale;
142
            this.isPk = isPk;
143
            this._allowNulls = allowNulls;
144
            this._isAutomatic = isAutomatic;
145
            this.defaultValue = defaultValue;
146
            this.geom_type = Geometry.TYPES.GEOMETRY;
147
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
148
            this.geom_srsdbcode = null;
149
            this.tablebbox = null;
150
            this._isIndexed = isIndexed;
151
            this._allowIndexDuplicateds = allowIndexDuplicateds;
152
        }
153
154
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
155
            this.name = name;
156
            this.type = DataTypes.GEOMETRY;
157
            this.size = 0;
158
            this.precision = 0;
159
            this.scale = 0;
160
            this.isPk = false;
161
            this._allowNulls = allowNulls;
162
            this._isAutomatic = false;
163
            this.defaultValue = null;
164
            this.geom_type = geom_type;
165
            this.geom_subtype = geom_subtype;
166
            this.geom_srsdbcode = srs_id(proj);
167
            this.tablebbox = null;
168
            this._isIndexed = isIndexed;
169
            this._allowIndexDuplicateds = true;
170
        }
171
172
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
173
            this.name = name;
174
            this.type = DataTypes.GEOMETRY;
175
            this.size = 0;
176
            this.precision = 0;
177
            this.scale = 0;
178
            this.isPk = false;
179
            this._allowNulls = allowNulls;
180
            this._isAutomatic = false;
181
            this.defaultValue = null;
182
            this.geom_type = geom_type;
183
            this.geom_subtype = geom_subtype;
184
            this.geom_srsdbcode = srsdbcode;
185
            this.tablebbox = null;
186
            this._isIndexed = isIndexed;
187
            this._allowIndexDuplicateds = true;
188
        }
189
190
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
191
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
192
            this.precision = fad.getPrecision();
193
            this.size = fad.getSize();
194
            this.scale = fad.getScale();
195
            this.isPk = fad.isPrimaryKey();
196
            this._allowNulls = fad.allowNull();
197
            this._isAutomatic = fad.isAutomatic();
198
            this._isIndexed = fad.isIndexed();
199
            this._allowIndexDuplicateds = fad.allowIndexDuplicateds();
200
201
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
202
                this.geom_type = fad.getGeomType().getType();
203
                this.geom_subtype = fad.getGeomType().getSubType();
204
                this.geom_srsdbcode =  srs_id(fad.getSRS());
205
                this.tablebbox = null;
206
                Tags tags = fad.getTags();
207
                String s = tags.getString("tablebbox", null);
208
                if( StringUtils.isNotBlank(s) ) {
209
                    try {
210
                        Geometry g = GeometryUtils.createFrom(s);
211
                        if( g!=null ) {
212
                            this.tablebbox = g.getEnvelope();
213
                        }
214
                    } catch(Exception ex) {
215
                        LOGGER.warn("Can't parse tablebbox for column '"+s+"'.",ex);
216
                    }
217
                }
218
            }
219
        }
220
221
222
        @Override
223
        public String getName() {
224
            return this.name;
225
        }
226
227
        @Override
228
        public void setName(String name) {
229
            this.name = name;
230
        }
231
232
        @Override
233
        public int getType() {
234
            return this.type;
235
        }
236
237
        @Override
238
        public void setType(int type) {
239
            this.type = type;
240
        }
241
242
        @Override
243
        public int getPrecision() {
244
            return precision;
245
        }
246
247
        @Override
248
        public void setPrecision(int precision) {
249
            this.precision = precision;
250
        }
251
252
        @Override
253
        public int getScale() {
254
            return scale;
255
        }
256
257
        @Override
258
        public void setScale(int scale) {
259
            this.scale = scale;
260
        }
261
262
        @Override
263
        public int getSize() {
264
            return size;
265
        }
266
267
        @Override
268
        public void setSize(int size) {
269
            this.size = size;
270
        }
271
272
        @Override
273
        public boolean isPrimaryKey() {
274
            return isPk;
275
        }
276
277
        @Override
278
        public void setIsPrimaryKey(boolean isPk) {
279
            this.isPk = isPk;
280
        }
281
282
        @Override
283
        public boolean allowNulls() {
284
            return _allowNulls;
285
        }
286
287
        @Override
288
        public void setAllowNulls(boolean allowNulls) {
289
            this._allowNulls = allowNulls;
290
        }
291
292
        @Override
293
        public boolean isAutomatic() {
294
            return _isAutomatic;
295
        }
296
297
        @Override
298
        public boolean isIndexed() {
299
            return _isIndexed;
300
        }
301
302
        @Override
303
        public void setIsAutomatic(boolean isAutomatic) {
304
            this._isAutomatic = isAutomatic;
305
        }
306
307
        @Override
308
        public Object getDefaultValue() {
309
            return defaultValue;
310
        }
311
312
        @Override
313
        public void setDefaultValue(Object defaultValue) {
314
            this.defaultValue = defaultValue;
315
        }
316
317
        @Override
318
        public int getGeometryType() {
319
            return geom_type;
320
        }
321
322
        @Override
323
        public void setGeometryType(int geom_type) {
324
            this.geom_type = geom_type;
325
        }
326
327
        @Override
328
        public int getGeometrySubtype() {
329
            return geom_subtype;
330
        }
331
332
        @Override
333
        public void setGeometrySubtype(int geom_subtype) {
334
            this.geom_subtype = geom_subtype;
335
        }
336
337
        @Override
338
        public Object getGeometrySRSId() {
339
            return geom_srsdbcode;
340
        }
341
342
        @Override
343
        public void setGeometrySRSId(Object geom_srsid) {
344
            this.geom_srsdbcode = geom_srsid;
345
        }
346
347
        @Override
348
        public boolean isGeometry() {
349
            return this.type == DataTypes.GEOMETRY;
350
        }
351
352
        private void setStoreParameters(DataStoreParameters parameters) {
353
            this.parameters = parameters;
354
        }
355
356
        @Override
357
        public DataStoreParameters getStoreParameters() {
358
            return this.parameters;
359
        }
360
361
        public Envelope getTableBBox() {
362
            return this.tablebbox;
363
        }
364
365
        public void setTableBBox(Envelope bbox) {
366
            this.tablebbox = bbox;
367
        }
368
369
        @Override
370
        public boolean allowIndexDuplicateds() {
371
            return this._allowIndexDuplicateds;
372
        }
373
374
        @Override
375
        public void setAllowIndexDuplicateds(boolean allowIndexDuplicateds) {
376
            this._allowIndexDuplicateds = allowIndexDuplicateds;
377
        }
378
379
    }
380
381
    public class ColumnBase extends AbstractValue implements Column {
382
383
        private final String name;
384
        private TableNameBuilder table;
385
386
        public ColumnBase(TableNameBuilder table, String name) {
387
            this.name = name;
388
            this.table = table;
389
        }
390
391
        @Override
392
        public ColumnBase clone() throws CloneNotSupportedException {
393
            ColumnBase other = (ColumnBase) super.clone();
394
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
395
            return other;
396
        }
397
398
399
        @Override
400
        public String name() {
401
            return this.name;
402
        }
403
404
        @Override
405
        public TableNameBuilder table() {
406
            return this.table;
407
        }
408
409
        @Override
410
        public TableNameBuilder table(TableNameBuilder table) {
411
            this.table = table;
412
            return this.table;
413
        }
414
415
        @Override
416
        public String toString() {
417
            return this.toString(formatter());
418
        }
419
420
        @Override
421
        public String toString(Formatter<Value> formatter) {
422
            if( formatter!=null && formatter.canApply(this) ) {
423
                return formatter.format(this);
424
            }
425
            if( this.table==null ) {
426
                return as_identifier(this.name);
427
            }
428
            return this.table.toString(formatter) + "." + as_identifier(this.name);
429
        }
430
431
        @Override
432
        public int compareTo(Variable o) {
433
            return this.name.compareTo(o.name());
434
        }
435
436
        @Override
437
        public boolean equals(Object obj) {
438
            if (!(obj instanceof Variable)) {
439
                return false;
440
            }
441
            return StringUtils.equals(this.toString(), ((Variable) obj).toString());
442
        }
443
444
        @Override
445
        public int hashCode() {
446
            int hash = 7;
447
            hash = 37 * hash + Objects.hashCode(this.toString());
448
            return hash;
449
        }
450
451
        @Override
452
        public void setProperty(String name, Object value) {
453
            super.setProperty(name, value);
454
            if(this.table != null){
455
                this.table.setProperty(name, value);
456
            }
457
        }
458
459
460
    }
461
462
    public class TableNameBuilderBase
463
            extends AbstractStatementPart
464
            implements TableNameBuilder {
465
466
        public String tableName;
467
        public String schemaName;
468
        private String databaseName;
469
470
        public TableNameBuilderBase() {
471
        }
472
473
        @Override
474
        public void accept(Visitor visitor, VisitorFilter filter) {
475
            if (filter==null || filter.accept(this)) {
476
                visitor.visit(this);
477
            }
478
        }
479
480
        @Override
481
        public TableNameBuilder database(String name) {
482
            this.databaseName = name;
483
            return this;
484
        }
485
486
        @Override
487
        public TableNameBuilder schema(String name) {
488
            if (support_schemas()) {
489
                this.schemaName = name;
490
            }
491
            return this;
492
        }
493
494
        @Override
495
        public TableNameBuilder name(String name) {
496
            this.tableName = name;
497
            return this;
498
        }
499
500
        protected String databaseName2provider() {
501
            return this.databaseName;
502
        }
503
504
        protected String schemaName2provider() {
505
            return this.schemaName;
506
        }
507
508
        protected String tableName2provider() {
509
            return this.tableName;
510
        }
511
512
        @Override
513
        public String getDatabase() {
514
            return this.databaseName;
515
        }
516
517
        @Override
518
        public String getSchema() {
519
            return this.schemaName;
520
        }
521
522
        @Override
523
        public String getName() {
524
            return this.tableName;
525
        }
526
527
        @Override
528
        public boolean has_schema() {
529
            if (!support_schemas()) {
530
                return false;
531
            }
532
            return StringUtils.isNotBlank(this.schemaName);
533
        }
534
535
        @Override
536
        public boolean has_name() {
537
            return StringUtils.isNotBlank(this.tableName);
538
        }
539
540
        @Override
541
        public boolean has_database() {
542
            return StringUtils.isNotBlank(this.databaseName);
543
        }
544
545
        @Override
546
        public boolean isEmpty() {
547
            return !this.has_database() && !this.has_schema() && !this.has_name();
548
        }
549
550
        @Override
551
        public String toString() {
552
            return this.toString(formatter());
553
        }
554
555
        @Override
556
        public String toString(Formatter<Value> formatter) {
557
            if (formatter!=null && formatter.canApply(this)) {
558
                return formatter.format(this);
559
            }
560
            if (this.has_database()) {
561
                if (this.has_schema()) {
562
                    return as_identifier(this.databaseName2provider()) + "."
563
                            + as_identifier(this.schemaName2provider()) + "."
564
                            + as_identifier(this.tableName2provider());
565
                }
566
//                return as_identifier(this.databaseName) + "."
567
//                        + as_identifier(this.tableName);
568
            } else {
569
                if (this.has_schema()) {
570
                    return as_identifier(this.schemaName2provider()) + "."
571
                            + as_identifier(this.tableName2provider());
572
                }
573
            }
574
            return as_identifier(this.tableName2provider());
575
        }
576
577
        @Override
578
        public boolean equals(Object obj) {
579
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
580
                return false;
581
            }
582
            TableNameBuilder other = (TableNameBuilder) obj;
583
584
            if (this.has_database() != other.has_database()) {
585
                return false;
586
            }
587
            String thisSchema = null;
588
            String otherSchema = null;
589
            if(support_schemas()) {
590
                thisSchema = this.schemaName;
591
                if (StringUtils.isBlank(thisSchema)) {
592
                    thisSchema = default_schema();
593
                }
594
                otherSchema = other.getSchema();
595
                if (StringUtils.isBlank(otherSchema)) {
596
                    otherSchema = default_schema();
597
                }
598
            }
599
            if (this.has_database()) {
600
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
601
                           StringUtils.equals(thisSchema, otherSchema) &&
602
                           StringUtils.equals(this.tableName,other.getName());
603
            } else {
604
                    return StringUtils.equals(thisSchema, otherSchema) &&
605
                           StringUtils.equals(this.tableName,other.getName());
606
            }
607
        }
608
609
        @Override
610
        public int hashCode() {
611
            int hash = 7;
612
            hash = 37 * hash + Objects.hashCode(this.toString());
613
            return hash;
614
        }
615
616
    }
617
618
    public class CountBuilderBase
619
            extends AbstractStatementPart
620
            implements CountBuilder {
621
622
        protected Value value;
623
        protected boolean distinct;
624
        protected boolean all;
625
626
        public CountBuilderBase() {
627
            this.value = null;
628
            this.distinct = false;
629
            this.all = false;
630
        }
631
632
        @Override
633
        public CountBuilderBase clone() throws CloneNotSupportedException {
634
            CountBuilderBase other = (CountBuilderBase) super.clone();
635
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
636
            return other;
637
        }
638
639
        @Override
640
        public CountBuilder all() {
641
            this.all = true;
642
            return this;
643
        }
644
645
        @Override
646
        public CountBuilder column(Value value) {
647
            this.value = value;
648
            return this;
649
        }
650
651
        @Override
652
        public CountBuilder distinct() {
653
            this.distinct = true;
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 formatter) {
664
            if (formatter!=null && formatter.canApply(this)) {
665
                return formatter.format(this);
666
            }
667
            if (this.all) {
668
                return "COUNT(*)";
669
            }
670
            if (this.distinct) {
671
                return MessageFormat.format(
672
                        "COUNT(DISTINCT {0})",
673
                        value.toString(formatter)
674
                );
675
            }
676
            return MessageFormat.format(
677
                    "COUNT({0})",
678
                    value.toString(formatter)
679
            );
680
        }
681
682
    }
683
684
    protected class JoinBase
685
            extends AbstractStatementPart
686
            implements JoinBuilder
687
        {
688
        protected String type;
689
        protected TableNameBuilder table;
690
        protected Value expression;
691
692
        public JoinBase(String type, TableNameBuilder table, Value expression) {
693
            this.type = type;
694
            this.table = table;
695
            this.expression = expression;
696
        }
697
698
        @Override
699
        public JoinBase clone() throws CloneNotSupportedException {
700
            JoinBase other = (JoinBase) super.clone();
701
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
702
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
703
            return other;
704
        }
705
706
        @Override
707
        public String toString() {
708
            return this.toString(formatter());
709
        }
710
711
        @Override
712
        public String toString(Formatter<Value> formatter) {
713
            if (formatter!=null && formatter.canApply(this)) {
714
                return formatter.format(this);
715
            }
716
            StringBuilder builder = new StringBuilder();
717
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
718
            builder.append(this.type.toUpperCase());
719
            builder.append(" JOIN ");
720
            builder.append(this.table.toString(formatter));
721
            builder.append(" ON ");
722
            builder.append(this.expression.toString(formatter));
723
            return builder.toString();
724
        }
725
726
        @Override
727
        public TableNameBuilder getTable() {
728
            return this.table;
729
        }
730
731
        @Override
732
        public String getType() {
733
            return this.type;
734
        }
735
736
        @Override
737
        public Value getCondition() {
738
            return this.expression;
739
        }
740
741
        @Override
742
        public void accept(Visitor visitor, VisitorFilter filter) {
743
            boolean visitChildren = true;
744
            if (filter==null || filter.accept(this)) {
745
                visitor.visit(this);
746
            } else {
747
                visitChildren = !filter.skipChildren();
748
            }
749
            if(visitChildren){
750
                if (this.expression != null) {
751
                    this.expression.accept(visitor, filter);
752
                }
753
            }
754
        }
755
756
    }
757
758
    public class FromBuilderBase
759
            extends AbstractStatementPart
760
            implements FromBuilder {
761
762
        protected TableNameBuilder tableName;
763
        protected String subquery;
764
        protected String passthrough;
765
        protected List<JoinBuilder> joins;
766
767
        public FromBuilderBase() {
768
            this.tableName = null;
769
            this.subquery = null;
770
            this.passthrough = null;
771
            this.joins = null;
772
        }
773
774
        @Override
775
        public FromBuilderBase clone() throws CloneNotSupportedException {
776
            FromBuilderBase other = (FromBuilderBase) super.clone();
777
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
778
            if (joins!=null) {
779
                for (int i = 0; i < joins.size(); i++) {
780
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
781
                }
782
            }
783
            return other;
784
        }
785
786
        @Override
787
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
788
            JoinBase join = createJoin("LEFT", table, expression);
789
            if( this.joins==null ) {
790
                this.joins = new ArrayList<>();
791
            }
792
            this.joins.add(join);
793
            return this;
794
        }
795
796
        @Override
797
        public TableNameBuilder table() {
798
            if (tableName == null) {
799
                this.tableName = createTableNameBuilder();
800
            }
801
            return this.tableName;
802
        }
803
804
        @Override
805
        public void accept(Visitor visitor, VisitorFilter filter) {
806
            boolean visitChildren = true;
807
            if (filter==null || filter.accept(this)) {
808
                visitor.visit(this);
809
            } else {
810
                visitChildren = !filter.skipChildren();
811
            }
812
            if(visitChildren){
813
                if (this.tableName != null) {
814
                    this.tableName.accept(visitor, filter);
815
                }
816
                if(this.joins != null) {
817
                    for (JoinBuilder join : joins) {
818
                        join.accept(visitor, filter);
819
                    }
820
                }
821
            }
822
        }
823
824
        @Override
825
        public FromBuilder custom(String passthrough) {
826
            this.passthrough = passthrough;
827
            return this;
828
        }
829
830
        @Override
831
        public FromBuilder subquery(String subquery) {
832
            this.subquery = subquery;
833
            return this;
834
        }
835
836
        @Override
837
        public String toString() {
838
            return this.toString(formatter());
839
        }
840
841
        @Override
842
        public String toString(Formatter<Value> formatter) {
843
            if (formatter!=null && formatter.canApply(this)) {
844
                return formatter.format(this);
845
            }
846
            if (!StringUtils.isEmpty(passthrough)) {
847
                return passthrough;
848
            }
849
            if (!StringUtils.isEmpty(subquery)) {
850
                return "( " + this.subquery + ") AS _subquery_alias_ ";
851
            }
852
            if( this.joins==null || this.joins.isEmpty() ) {
853
                return this.tableName.toString(formatter);
854
            }
855
            StringBuilder builder = new StringBuilder();
856
            builder.append(this.tableName.toString(formatter));
857
            for (JoinBuilder join : this.joins) {
858
                builder.append(" ");
859
                builder.append(join.toString(formatter));
860
            }
861
            return builder.toString();
862
        }
863
864
        @Override
865
        public List<JoinBuilder> getJoins() {
866
            return this.joins;
867
        }
868
869
    }
870
871
    public class SelectColumnBuilderBase
872
            extends AbstractStatementPart
873
            implements SelectColumnBuilder {
874
875
        protected Column name = null;
876
        protected String alias = null;
877
        protected Value value = null;
878
        protected boolean asGeometry = false;
879
        protected TableNameBuilder table;
880
        protected SQLBuilder sqlbuilder;
881
882
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
883
            this.sqlbuilder = sqlbuilder;
884
        }
885
886
        @Override
887
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
888
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
889
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
890
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
891
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
892
            return other;
893
        }
894
895
        @Override
896
        public void accept(Visitor visitor, VisitorFilter filter) {
897
            boolean visitChildren = true;
898
            if (filter==null || filter.accept(this)) {
899
                visitor.visit(this);
900
            } else {
901
                visitChildren = !filter.skipChildren();
902
            }
903
            if(visitChildren){
904
                if (this.value != null) {
905
                    this.value.accept(visitor, filter);
906
                } else if (this.name != null) {
907
                    this.name.accept(visitor, filter);
908
                }
909
            }
910
        }
911
912
        @Override
913
        public void replace(Value target, Value replacement) {
914
            if (this.name!=null ) {
915
                if( this.name == target) {
916
                    if(replacement == null){
917
                        this.name = null;
918
                    } else if(replacement instanceof Column){
919
                        this.name = (Column) replacement;
920
                    } else if(replacement instanceof Variable){
921
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
922
                    } else {
923
                        this.value = replacement;
924
                    }
925
                }
926
            }
927
            if( this.value!=null ) {
928
                if (this.value == target) {
929
                    this.value = replacement;
930
                } else {
931
                    this.value.replace(target, replacement);
932
                }
933
            }
934
        }
935
936
        @Override
937
        public SelectColumnBuilder name(String name) {
938
            return this.name(this.table, name);
939
        }
940
941
        @Override
942
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
943
            String quote = quote_for_identifiers();
944
            if (name.startsWith(quote)) {
945
                // Remove quotes
946
                name = name.substring(1, name.length() - 1);
947
            }
948
            this.table = table;
949
            this.name = new ColumnBase(this.table, name);
950
            this.value = null;
951
            this.asGeometry = false;
952
            return this;
953
        }
954
955
        public SelectColumnBuilder table(TableNameBuilder table) {
956
            this.table = table;
957
            if(this.name != null){
958
                this.name.table(table);
959
            }
960
            return this;
961
        }
962
963
        @Override
964
        public SelectColumnBuilder all() {
965
            this.name = null;
966
            this.value = expression().custom("*");
967
            this.asGeometry = false;
968
            return this;
969
        }
970
971
        @Override
972
        public SelectColumnBuilder as_geometry() {
973
            this.asGeometry = true;
974
            return this;
975
        }
976
977
        @Override
978
        public SelectColumnBuilder value(Value value) {
979
            this.value = value;
980
            return this;
981
        }
982
983
        @Override
984
        public SelectColumnBuilder as(String alias) {
985
            this.alias = alias;
986
            return this;
987
        }
988
989
        @Override
990
        public String getName() {
991
            if (this.name==null) {
992
                return null;
993
            }
994
            return this.name.name();
995
        }
996
997
        @Override
998
        public String getAlias() {
999
            return this.alias;
1000
        }
1001
1002
        @Override
1003
        public Value getValue() {
1004
            return this.value;
1005
        }
1006
1007
        @Override
1008
        public String toString() {
1009
            return this.toString(formatter());
1010
        }
1011
1012
        @Override
1013
        public String toString(Formatter<Value> formatter) {
1014
            if (formatter!=null && formatter.canApply(this)) {
1015
                return formatter.format(this);
1016
            }
1017
            StringBuilder builder = new StringBuilder();
1018
            if (this.asGeometry) {
1019
                if(this.value == VALUE_NULL){
1020
                    builder.append(this.value.toString(formatter));
1021
                } else {
1022
                    switch(expression().geometry_support_type()) {
1023
                        case WKB:
1024
                            builder.append(expression().ST_AsBinary(this.name).toString(formatter));
1025
                            break;
1026
                        case EWKB:
1027
                            builder.append(expression().ST_AsEWKB(this.name).toString(formatter));
1028
                            break;
1029
                        case WKT:
1030
                            builder.append(expression().ST_AsText(this.name).toString(formatter));
1031
                            break;
1032
                        case NATIVE:
1033
                            builder.append(as_identifier(this.name.toString(formatter)));
1034
                            break;
1035
                    }
1036
                }
1037
            } else {
1038
                if (this.value == null) {
1039
                    builder.append(this.name.toString(formatter));
1040
                } else {
1041
                    builder.append(this.value.toString(formatter));
1042
                }
1043
            }
1044
            if (this.alias != null) {
1045
                builder.append(" AS ");
1046
                builder.append(as_identifier(this.alias));
1047
            }
1048
            return builder.toString();
1049
        }
1050
1051
        @Override
1052
        public boolean isGeometry() {
1053
            return this.asGeometry;
1054
        }
1055
1056
        @Override
1057
        public TableNameBuilder getTable() {
1058
            return this.table;
1059
        }
1060
1061
        @Override
1062
        public boolean isAggregateFunction() {
1063
            if( this.value == null ) {
1064
                return false;
1065
            }
1066
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
1067
                return false;
1068
            }
1069
            String funcname = ((ExpressionBuilder.Function)this.value).name();
1070
            return this.sqlbuilder.isAggregateFunction(funcname);
1071
        }
1072
    }
1073
1074
    public class OrderByBuilderBase
1075
            extends AbstractStatementPart
1076
            implements OrderByBuilder {
1077
1078
        protected Value value;
1079
        protected String custom;
1080
        protected boolean ascending;
1081
        protected int nullsMode;
1082
1083
        public OrderByBuilderBase() {
1084
            this.ascending = true;
1085
            this.nullsMode = MODE_NULLS_LAST;
1086
        }
1087
1088
        @Override
1089
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
1090
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
1091
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
1092
            return other;
1093
        }
1094
1095
        @Override
1096
        public void accept(Visitor visitor, VisitorFilter filter) {
1097
            boolean visitChildren = true;
1098
            if (filter==null || filter.accept(this)) {
1099
                visitor.visit(this);
1100
            } else {
1101
                visitChildren = !filter.skipChildren();
1102
            }
1103
            if(visitChildren){
1104
                if (this.value!=null) {
1105
                    this.value.accept(visitor, filter);
1106
                }
1107
            }
1108
        }
1109
1110
        @Override
1111
        public OrderByBuilder column(String name) {
1112
            this.value = expression().variable(name);
1113
            return this;
1114
        }
1115
1116
        @Override
1117
        public boolean isColumn(String name) {
1118
            if(this.value instanceof ExpressionBuilder.Variable){
1119
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1120
            }
1121
            return false;
1122
        }
1123
1124
        @Override
1125
        public boolean isColumn(Value value) {
1126
            if(value instanceof ExpressionBuilder.Variable){
1127
                return isColumn(((ExpressionBuilder.Variable)value).name());
1128
            }
1129
            return this.value == value;
1130
        }
1131
1132
        @Override
1133
        public OrderByBuilder value(Value expression) {
1134
            this.value = expression;
1135
            return this;
1136
        }
1137
1138
        @Override
1139
        public OrderByBuilder custom(String order) {
1140
            this.custom = order;
1141
            return this;
1142
        }
1143
1144
        @Override
1145
        public OrderByBuilder ascending() {
1146
            this.ascending = true;
1147
            return this;
1148
        }
1149
1150
        @Override
1151
        public OrderByBuilder ascending(boolean asc) {
1152
            this.ascending = asc;
1153
            return this;
1154
        }
1155
1156
        @Override
1157
        public OrderByBuilder descending() {
1158
            this.ascending = false;
1159
            return this;
1160
        }
1161
1162
        @Override
1163
        public OrderByBuilder nulls(int mode) {
1164
            this.nullsMode = mode;
1165
            return this;
1166
        }
1167
1168
        @Override
1169
        public int getNullsMode() {
1170
            return this.nullsMode;
1171
        }
1172
1173
        @Override
1174
        public String toString() {
1175
            return this.toString(formatter());
1176
        }
1177
1178
        @Override
1179
        public String toString(Formatter<Value> formatter) {
1180
            if (formatter!=null && formatter.canApply(this)) {
1181
                return formatter.format(this);
1182
            }
1183
            if (!StringUtils.isEmpty(this.custom)) {
1184
                return this.custom;
1185
            }
1186
            String order_s = this.value.toString(formatter);
1187
            if (this.ascending) {
1188
                order_s += " ASC";
1189
            } else {
1190
                order_s += " DESC";
1191
            }
1192
            switch(this.nullsMode) {
1193
                case MODE_NULLS_NOT_SPECIFIED:
1194
                    break;
1195
                case MODE_NULLS_FIRST:
1196
                    order_s += " NULLS FIRST";
1197
                    break;
1198
                case MODE_NULLS_LAST:
1199
                default:
1200
                    order_s += " NULLS LAST";
1201
                    break;
1202
            }
1203
            return order_s;
1204
        }
1205
1206
        @Override
1207
        public void replace(Value target, Value replacement) {
1208
            super.replace(target, replacement);
1209
            if(target == this.value){
1210
                this.value = replacement;
1211
                return;
1212
            }
1213
            if(this.value == null){
1214
                return;
1215
            }
1216
            this.value.replace(target, replacement);
1217
        }
1218
1219
1220
    }
1221
1222
    public class SelectBuilderBase
1223
            extends AbstractStatement
1224
            implements SelectBuilder {
1225
1226
        protected FromBuilder from;
1227
        protected GeometryExpressionBuilder where;
1228
        protected long limit = -1;
1229
        protected long offset = -1;
1230
        protected List<SelectColumnBuilder> columns;
1231
        protected List<OrderByBuilder> order_by;
1232
        protected boolean distinct;
1233
        protected List<Value> groupColumn;
1234
        protected boolean check_order_and_offset = true;
1235
1236
        public SelectBuilderBase() {
1237
            this.columns = new ArrayList<>();
1238
            this.distinct = false;
1239
        }
1240
        @Override
1241
        public List<Value> getGroups() {
1242
            return this.groupColumn;
1243
        }
1244
1245
        @Override
1246
        public List<SelectColumnBuilder> getColumns() {
1247
            return Collections.unmodifiableList(this.columns);
1248
    }
1249
1250
        @Override
1251
        public void remove_column(String columnName) {
1252
            SelectColumnBuilder found = null;
1253
            for (SelectColumnBuilder column : columns) {
1254
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1255
                    found = column;
1256
                    break;
1257
                }
1258
1259
            }
1260
            if(found!=null) {
1261
                columns.remove(found);
1262
            }
1263
        }
1264
1265
        @Override
1266
        public SelectBuilder group_by(Value... columns) {
1267
            if( this.groupColumn==null ) {
1268
                this.groupColumn = new ArrayList<>();
1269
            }
1270
            for (Value column : columns) {
1271
                this.groupColumn.add(column);
1272
            }
1273
            return this;
1274
        }
1275
1276
        @Override
1277
        public void accept(Visitor visitor, VisitorFilter filter) {
1278
            boolean visitChildren = true;
1279
            if (filter==null || filter.accept(this)) {
1280
                visitor.visit(this);
1281
            } else {
1282
                visitChildren = !filter.skipChildren();
1283
            }
1284
            if(visitChildren){
1285
                for (SelectColumnBuilder column : columns) {
1286
                    column.accept(visitor, filter);
1287
                }
1288
                if (this.has_from()) {
1289
                    this.from.accept(visitor, filter);
1290
                }
1291
                if (this.has_where()) {
1292
                    this.where.accept(visitor, filter);
1293
                }
1294
                if (this.has_order_by()) {
1295
                    for (OrderByBuilder order : order_by) {
1296
                        order.accept(visitor, filter);
1297
                    }
1298
                }
1299
                if (this.has_group_by()) {
1300
                    for (Value group : groupColumn) {
1301
                        group.accept(visitor, filter);
1302
                    }
1303
                }
1304
            }
1305
        }
1306
1307
        @Override
1308
        public void replace(Value target, Value replacement) {
1309
            if( this.columns!=null ) {
1310
                for (int i = 0; i < columns.size(); i++) {
1311
                    SelectColumnBuilder column = columns.get(i);
1312
                    if( column == target ) {
1313
                        columns.set(i, (SelectColumnBuilder) replacement);
1314
                    } else {
1315
                        column.replace(target, replacement);
1316
                    }
1317
                }
1318
            }
1319
            if (this.has_from()) {
1320
                if( this.from == target ) {
1321
                    this.from = (FromBuilder) replacement;
1322
                } else {
1323
                    this.from.replace(target, replacement);
1324
                }
1325
            }
1326
            if (this.has_where()) {
1327
                if( this.where == target ) {
1328
                    this.where = (GeometryExpressionBuilder) replacement;
1329
                } else if( this.where.value() == target ) {
1330
                    this.where.value(replacement);
1331
                } else {
1332
                    this.where.value().replace(target, replacement);
1333
                }
1334
            }
1335
            if (this.has_order_by()) {
1336
                for (int i = 0; i < order_by.size(); i++) {
1337
                    OrderByBuilder order = order_by.get(i);
1338
                    if( order == target ) {
1339
                        order_by.set(i, (OrderByBuilder) replacement);
1340
                    } else {
1341
                        order.replace(target, replacement);
1342
                    }
1343
                }
1344
            }
1345
            if (this.has_group_by()) {
1346
                for (int i = 0; i < groupColumn.size(); i++) {
1347
                    Value group = groupColumn.get(i);
1348
                    if( group == target ) {
1349
                        groupColumn.set(i, replacement);
1350
                    } else {
1351
                        group.replace(target, replacement);
1352
                    }
1353
                }
1354
            }
1355
        }
1356
1357
        @Override
1358
        public SelectBuilder distinct() {
1359
            this.distinct = true;
1360
            return this;
1361
        }
1362
1363
        @Override
1364
        public SelectColumnBuilder column() {
1365
            return column(createSelectColumnBuilder());
1366
        }
1367
1368
        @Override
1369
        public SelectColumnBuilder column(SelectColumnBuilder columnBuilder) {
1370
            this.columns.add(columnBuilder);
1371
            if( this.has_from() && !this.from().table().isEmpty() ) {
1372
                TableNameBuilder table = (TableNameBuilder) CloneableUtils.cloneQuietly(this.from().table());
1373
                columnBuilder.table(table);
1374
            }
1375
            return columnBuilder;
1376
        }
1377
1378
        @Override
1379
        public SelectColumnBuilder column(String name) {
1380
            for (SelectColumnBuilder column : columns) {
1381
                if (StringUtils.equals(name, column.getName())) {
1382
                    return column;
1383
                }
1384
            }
1385
            return column(createSelectColumnBuilder()).name(name);
1386
        }
1387
1388
        @Override
1389
        public SelectColumnBuilder getColumn(String name) {
1390
            for (SelectColumnBuilder column : columns) {
1391
                if (StringUtils.equals(name, column.getName())) {
1392
                    return column;
1393
                }
1394
            }
1395
            return null;
1396
        }
1397
1398
        @Override
1399
        public SelectBuilder remove_all_columns() {
1400
            this.columns = new ArrayList<>();
1401
            return this;
1402
        }
1403
1404
        @Override
1405
        public boolean has_column(String name) {
1406
            for (SelectColumnBuilder column : columns) {
1407
                if (StringUtils.equals(name, column.getName())) {
1408
                    return true;
1409
                }
1410
                if (StringUtils.equals(name, column.getAlias())) {
1411
                    return true;
1412
                }
1413
            }
1414
            return false;
1415
        }
1416
1417
        @Override
1418
        public FromBuilder from() {
1419
            if (this.from == null) {
1420
                this.from = createFromBuilder();
1421
            }
1422
            return this.from;
1423
        }
1424
1425
        @Override
1426
        public boolean has_from() {
1427
            return this.from != null;
1428
        }
1429
1430
        @Override
1431
        public GeometryExpressionBuilder where() {
1432
            if (this.where == null) {
1433
                this.where = createExpressionBuilder();
1434
            }
1435
            return this.where;
1436
        }
1437
1438
        @Override
1439
        public boolean has_where() {
1440
            if (this.where == null) {
1441
                return false;
1442
            }
1443
            return this.where.value() != null;
1444
        }
1445
1446
        @Override
1447
        public SelectBuilder limit(long limit) {
1448
            this.limit = limit;
1449
            return this;
1450
        }
1451
1452
        @Override
1453
        public SelectBuilder limit(Long limit) {
1454
            if (limit == null) {
1455
                this.limit = -1;
1456
            } else {
1457
                this.limit = limit;
1458
            }
1459
            return this;
1460
        }
1461
1462
        @Override
1463
        public boolean has_limit() {
1464
            return this.limit >= 0;
1465
        }
1466
1467
        @Override
1468
        public SelectBuilder offset(long offset) {
1469
            this.offset = offset;
1470
            return this;
1471
        }
1472
1473
        @Override
1474
        public boolean has_offset() {
1475
            return this.offset > 0;
1476
        }
1477
1478
        @Override
1479
        public OrderByBuilder order_by() {
1480
            if (this.order_by == null) {
1481
                this.order_by = new ArrayList<>();
1482
            }
1483
            OrderByBuilder order = createOrderByBuilder();
1484
            this.order_by.add(order);
1485
            return order;
1486
        }
1487
1488
        @Override
1489
        public OrderByBuilder getOrderBy(Value column) {
1490
            if(this.order_by == null){
1491
                return null;
1492
            }
1493
            for (OrderByBuilder orderByBuilder : this.order_by) {
1494
                if(orderByBuilder.isColumn(column)){
1495
                    return orderByBuilder;
1496
                }
1497
            }
1498
            return null;
1499
        }
1500
1501
        @Override
1502
        public OrderByBuilder getOrderBy(String column) {
1503
            if(this.order_by == null){
1504
                return null;
1505
            }
1506
            for (OrderByBuilder orderByBuilder : this.order_by) {
1507
                if(orderByBuilder.isColumn(column)){
1508
                    return orderByBuilder;
1509
                }
1510
            }
1511
            return null;
1512
        }
1513
1514
        @Override
1515
        public boolean isGroupBy(String column) {
1516
            if(this.groupColumn == null){
1517
                return false;
1518
            }
1519
            for (Value group : this.groupColumn) {
1520
                if(group instanceof Variable){
1521
                    if(StringUtils.equalsIgnoreCase(((Variable)group).name(), column)){
1522
                        return true;
1523
                    }
1524
                }
1525
            }
1526
            return false;
1527
        }
1528
1529
        @Override
1530
        public boolean has_order_by() {
1531
            if (this.order_by == null) {
1532
                return false;
1533
            }
1534
            return !this.order_by.isEmpty();
1535
        }
1536
1537
        @Override
1538
        public boolean has_group_by() {
1539
            if (this.groupColumn == null) {
1540
                return false;
1541
            }
1542
            return !this.groupColumn.isEmpty();
1543
        }
1544
1545
        @Override
1546
        public boolean has_aggregate_functions() {
1547
            if (this.columns == null || this.columns.isEmpty() ) {
1548
                return false;
1549
            }
1550
            for (SelectColumnBuilder column : this.columns) {
1551
                if( column.isAggregateFunction() ) {
1552
                    return true;
1553
                }
1554
            }
1555
            return false;
1556
        }
1557
1558
        @Override
1559
        public void disable_check_order_and_offset() {
1560
          this.check_order_and_offset = false;
1561
        }
1562
1563
        protected boolean isValid(StringBuilder message) {
1564
            if (message == null) {
1565
                message = new StringBuilder();
1566
            }
1567
            if( this.check_order_and_offset ) {
1568
              if (this.has_offset() && !this.has_order_by()) {
1569
                  // Algunos gestores de BBDD requieren que se especifique un
1570
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1571
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1572
                  // siempre.
1573
                  message.append("Can't use OFFSET without an ORDER BY.");
1574
                  return false;
1575
              }
1576
            }
1577
            return true;
1578
        }
1579
1580
        @Override
1581
        public String toString() {
1582
            return this.toString(formatter());
1583
        }
1584
1585
        @Override
1586
        public String toString(Formatter<Value> formatter) {
1587
            if (formatter!=null && formatter.canApply(this)) {
1588
                return formatter.format(this);
1589
            }
1590
            StringBuilder builder = new StringBuilder();
1591
            if (!this.isValid(builder)) {
1592
                throw new IllegalStateException(builder.toString());
1593
            }
1594
            builder.append("SELECT ");
1595
            if (this.distinct) {
1596
                builder.append("DISTINCT ");
1597
            }
1598
            boolean first = true;
1599
            for (SelectColumnBuilder column : columns) {
1600
                if (first) {
1601
                    first = false;
1602
                } else {
1603
                    builder.append(", ");
1604
                }
1605
                builder.append(column.toString(formatter));
1606
            }
1607
1608
            if (this.has_from()) {
1609
                builder.append(" FROM ");
1610
                builder.append(this.from.toString(formatter));
1611
            }
1612
            if (this.has_where()) {
1613
                builder.append(" WHERE ");
1614
                builder.append(this.where.toString(formatter));
1615
            }
1616
            if( this.has_group_by() ) {
1617
                builder.append(" GROUP BY ");
1618
                builder.append(this.groupColumn.get(0).toString(formatter));
1619
                for (int i = 1; i < groupColumn.size(); i++) {
1620
                    builder.append(", ");
1621
                    builder.append(this.groupColumn.get(i).toString(formatter));
1622
                }
1623
            }
1624
            if (this.has_order_by()) {
1625
                builder.append(" ORDER BY ");
1626
                first = true;
1627
                for (OrderByBuilder item : this.order_by) {
1628
                    if (first) {
1629
                        first = false;
1630
                    } else {
1631
                        builder.append(", ");
1632
                    }
1633
                    builder.append(item.toString(formatter));
1634
                }
1635
            }
1636
1637
            if (this.has_limit()) {
1638
                builder.append(" LIMIT ");
1639
                builder.append(this.limit);
1640
            }
1641
            if (this.has_offset()) {
1642
                builder.append(" OFFSET ");
1643
                builder.append(this.offset);
1644
            }
1645
            return builder.toString();
1646
1647
        }
1648
    }
1649
1650
    public class DropTableBuilderBase
1651
            extends AbstractStatement
1652
            implements DropTableBuilder {
1653
1654
        protected TableNameBuilder table;
1655
1656
        @Override
1657
        public TableNameBuilder table() {
1658
            if (table == null) {
1659
                table = createTableNameBuilder();
1660
            }
1661
            return table;
1662
        }
1663
1664
        @Override
1665
        public void accept(Visitor visitor, VisitorFilter filter) {
1666
            boolean visitChildren = true;
1667
            if (filter==null || filter.accept(this)) {
1668
                visitor.visit(this);
1669
            } else {
1670
                visitChildren = !filter.skipChildren();
1671
            }
1672
            if(visitChildren){
1673
                this.table.accept(visitor, filter);
1674
            }
1675
        }
1676
1677
        @Override
1678
        public String toString() {
1679
            return this.toString(formatter());
1680
        }
1681
1682
        @Override
1683
        public String toString(Formatter<Value> formatter) {
1684
            if (formatter!=null && formatter.canApply(this)) {
1685
                return formatter.format(this);
1686
            }
1687
            StringBuilder builder = new StringBuilder();
1688
            boolean first = true;
1689
            for (String sql : toStrings(formatter)) {
1690
                if (StringUtils.isEmpty(sql)) {
1691
                    continue;
1692
                }
1693
                if (first) {
1694
                    first = false;
1695
                } else {
1696
                    builder.append("; ");
1697
                }
1698
                builder.append(sql);
1699
            }
1700
            return builder.toString();
1701
        }
1702
1703
        @Override
1704
        public List<String> toStrings() {
1705
            return this.toStrings(formatter());
1706
        }
1707
1708
        @Override
1709
        public List<String> toStrings(Formatter formatter) {
1710
            List<String> sqls = new ArrayList<>();
1711
1712
            sqls.add(
1713
                    MessageFormat.format(
1714
                            STMT_DROP_TABLE_table,
1715
                            this.table.toString(formatter)
1716
                    )
1717
            );
1718
            String sql;
1719
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1720
                if (this.table.has_schema()) {
1721
                    sql = MessageFormat.format(
1722
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1723
                            as_string(this.table.getSchema()),
1724
                            as_string(this.table.getName())
1725
                    );
1726
                } else {
1727
                    sql = MessageFormat.format(
1728
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1729
                            as_identifier(this.table.getName())
1730
                    );
1731
                }
1732
                if (!StringUtils.isEmpty(sql)) {
1733
                    sqls.add(sql);
1734
                }
1735
            }
1736
            return sqls;
1737
        }
1738
    }
1739
1740
    public class GrantRoleBuilderBase
1741
            extends AbstractStatementPart
1742
            implements GrantRoleBuilder {
1743
1744
        protected TableNameBuilder table;
1745
        protected String role;
1746
        protected Set<Privilege> privileges;
1747
1748
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1749
            this.table = table;
1750
            this.role = role;
1751
            this.privileges = new HashSet<>();
1752
        }
1753
1754
        @Override
1755
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1756
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1757
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1758
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1759
1760
            return other;
1761
        }
1762
1763
        @Override
1764
        public GrantRoleBuilder privilege(Privilege privilege) {
1765
            privileges.add(privilege);
1766
            return this;
1767
        }
1768
1769
        @Override
1770
        public GrantRoleBuilder select() {
1771
            privileges.add(Privilege.SELECT);
1772
            return this;
1773
        }
1774
1775
        @Override
1776
        public GrantRoleBuilder update() {
1777
            privileges.add(Privilege.UPDATE);
1778
            return this;
1779
        }
1780
1781
        @Override
1782
        public GrantRoleBuilder insert() {
1783
            privileges.add(Privilege.INSERT);
1784
            return this;
1785
        }
1786
1787
        @Override
1788
        public GrantRoleBuilder delete() {
1789
            privileges.add(Privilege.DELETE);
1790
            return this;
1791
        }
1792
1793
        @Override
1794
        public GrantRoleBuilder truncate() {
1795
            privileges.add(Privilege.TRUNCATE);
1796
            return this;
1797
        }
1798
1799
        @Override
1800
        public GrantRoleBuilder reference() {
1801
            privileges.add(Privilege.REFERENCE);
1802
            return this;
1803
        }
1804
1805
        @Override
1806
        public GrantRoleBuilder trigger() {
1807
            privileges.add(Privilege.TRIGGER);
1808
            return this;
1809
        }
1810
1811
        @Override
1812
        public GrantRoleBuilder all() {
1813
            privileges.add(Privilege.ALL);
1814
            return this;
1815
        }
1816
1817
        protected String getPrivilegeName(Privilege privilege) {
1818
            switch (privilege) {
1819
                case DELETE:
1820
                    return "DELETE";
1821
                case INSERT:
1822
                    return "INSERT";
1823
                case REFERENCE:
1824
                    return "REFERENCE";
1825
                case SELECT:
1826
                    return "SELECT";
1827
                case TRIGGER:
1828
                    return "TRIGGER";
1829
                case TRUNCATE:
1830
                    return "TRUNCATE";
1831
                case UPDATE:
1832
                    return "UPDATE";
1833
                case ALL:
1834
                default:
1835
                    return "ALL";
1836
            }
1837
        }
1838
1839
        @Override
1840
        public String toString() {
1841
            return this.toString(formatter());
1842
        }
1843
1844
        @Override
1845
        public String toString(Formatter<Value> formatter) {
1846
            if (formatter!=null && formatter.canApply(this)) {
1847
                return formatter.format(this);
1848
            }
1849
            StringBuilder builder = new StringBuilder();
1850
            boolean first = true;
1851
            for (Privilege privilege : privileges) {
1852
                if (first) {
1853
                    first = false;
1854
                } else {
1855
                    builder.append(", ");
1856
                }
1857
                builder.append(this.getPrivilegeName(privilege));
1858
            }
1859
            String sql = MessageFormat.format(
1860
                    STMT_GRANT_privileges_ON_table_TO_role,
1861
                    builder.toString(),
1862
                    table.toString(formatter),
1863
                    role
1864
            );
1865
            return sql;
1866
        }
1867
    }
1868
1869
    public class GrantBuilderBase
1870
            extends AbstractStatement
1871
            implements GrantBuilder {
1872
1873
        protected TableNameBuilder table;
1874
        protected Map<String, GrantRoleBuilder> roles;
1875
1876
        public GrantBuilderBase() {
1877
            this.roles = new HashMap<>();
1878
        }
1879
1880
        @Override
1881
        public TableNameBuilder table() {
1882
            if (table == null) {
1883
                table = createTableNameBuilder();
1884
            }
1885
            return table;
1886
        }
1887
1888
        @Override
1889
        public void accept(Visitor visitor, VisitorFilter filter) {
1890
            boolean visitChildren = true;
1891
            if (filter==null || filter.accept(this)) {
1892
                visitor.visit(this);
1893
            } else {
1894
                visitChildren = !filter.skipChildren();
1895
            }
1896
            if(visitChildren){
1897
                if (this.table != null) {
1898
                    this.table.accept(visitor, filter);
1899
                }
1900
            }
1901
        }
1902
1903
        @Override
1904
        public GrantRoleBuilder role(String role) {
1905
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1906
            if (roleBuilder == null) {
1907
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1908
                this.roles.put(role, roleBuilder);
1909
            }
1910
            return roleBuilder;
1911
        }
1912
1913
        @Override
1914
        public String toString() {
1915
            return this.toString(formatter());
1916
        }
1917
1918
        @Override
1919
        public String toString(Formatter<Value> formatter) {
1920
            if (formatter!=null && formatter.canApply(this)) {
1921
                return formatter.format(this);
1922
            }
1923
            StringBuilder builder = new StringBuilder();
1924
            boolean first = true;
1925
            for (String sql : toStrings(formatter)) {
1926
                if (StringUtils.isEmpty(sql)) {
1927
                    continue;
1928
                }
1929
                if (first) {
1930
                    first = false;
1931
                } else {
1932
                    builder.append("; ");
1933
                }
1934
                builder.append(sql);
1935
            }
1936
            return builder.toString();
1937
        }
1938
1939
        @Override
1940
        public List<String> toStrings() {
1941
            return this.toStrings(formatter());
1942
        }
1943
1944
        @Override
1945
        public List<String> toStrings(Formatter formatter) {
1946
            List<String> sqls = new ArrayList<>();
1947
            for (GrantRoleBuilder role : roles.values()) {
1948
                sqls.add(role.toString(formatter));
1949
            }
1950
            return sqls;
1951
        }
1952
    }
1953
1954
    public class UpdateColumnBuilderBase
1955
            extends InsertColumnBuilderBase
1956
            implements UpdateColumnBuilder {
1957
1958
        public UpdateColumnBuilderBase() {
1959
            super();
1960
        }
1961
1962
        @Override
1963
        public UpdateColumnBuilder name(String name) {
1964
            return (UpdateColumnBuilder) super.name(name);
1965
        }
1966
1967
        @Override
1968
        public UpdateColumnBuilder with_value(Value value) {
1969
            return (UpdateColumnBuilder) super.with_value(value);
1970
        }
1971
1972
    }
1973
1974
    public class UpdateBuilderBase
1975
            extends AbstractStatement
1976
            implements UpdateBuilder {
1977
1978
        protected GeometryExpressionBuilder where;
1979
        protected List<UpdateColumnBuilder> columns;
1980
        protected TableNameBuilder table;
1981
1982
        public UpdateBuilderBase() {
1983
            this.columns = new ArrayList<>();
1984
        }
1985
1986
        @Override
1987
        public void accept(Visitor visitor, VisitorFilter filter) {
1988
            boolean visitChildren = true;
1989
            if (filter==null || filter.accept(this)) {
1990
                visitor.visit(this);
1991
            } else {
1992
                visitChildren = !filter.skipChildren();
1993
            }
1994
            if(visitChildren){
1995
                if (this.table != null) {
1996
                    this.table.accept(visitor, filter);
1997
                }
1998
                for (UpdateColumnBuilder column : columns) {
1999
                    column.accept(visitor, filter);
2000
                }
2001
                if (this.has_where()) {
2002
                    this.where.accept(visitor, filter);
2003
                }
2004
            }
2005
        }
2006
2007
        @Override
2008
        public GeometryExpressionBuilder where() {
2009
            if (this.where == null) {
2010
                this.where = createExpressionBuilder();
2011
            }
2012
            return this.where;
2013
        }
2014
2015
        @Override
2016
        public TableNameBuilder table() {
2017
            if (table == null) {
2018
                table = createTableNameBuilder();
2019
            }
2020
            return table;
2021
        }
2022
2023
        @Override
2024
        public UpdateColumnBuilder column() {
2025
            UpdateColumnBuilder column = createUpdateColumnBuilder();
2026
            this.columns.add(column);
2027
            return column;
2028
        }
2029
2030
        @Override
2031
        public boolean has_where() {
2032
            return this.where != null;
2033
        }
2034
2035
        @Override
2036
        public String toString() {
2037
            return this.toString(formatter());
2038
        }
2039
2040
        @Override
2041
        public String toString(Formatter<Value> formatter) {
2042
            if (formatter!=null && formatter.canApply(this)) {
2043
                return formatter.format(this);
2044
            }
2045
            /*
2046
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
2047
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
2048
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
2049
             * output_expression [ AS output_name ] [, ...] ]
2050
             */
2051
            StringBuilder columnsAndValues = new StringBuilder();
2052
2053
            boolean first = true;
2054
            for (UpdateColumnBuilder column : columns) {
2055
                if (first) {
2056
                    first = false;
2057
                } else {
2058
                    columnsAndValues.append(", ");
2059
                }
2060
                columnsAndValues.append(as_identifier(column.getName()));
2061
                columnsAndValues.append(" = ");
2062
                columnsAndValues.append(column.getValue().toString(formatter));
2063
            }
2064
2065
            String sql;
2066
            if (this.has_where()) {
2067
                sql = MessageFormat.format(
2068
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
2069
                        this.table.toString(formatter),
2070
                        columnsAndValues.toString(),
2071
                        this.where.toString(formatter)
2072
                );
2073
            } else {
2074
                sql = MessageFormat.format(
2075
                        STMT_UPDATE_table_SET_columnsAndValues,
2076
                        this.table.toString(formatter),
2077
                        columnsAndValues.toString()
2078
                );
2079
            }
2080
            return sql;
2081
        }
2082
    }
2083
2084
    public class DeleteBuilderBase
2085
            extends AbstractStatement
2086
            implements DeleteBuilder {
2087
2088
        protected GeometryExpressionBuilder where;
2089
        protected TableNameBuilder table;
2090
2091
        public DeleteBuilderBase() {
2092
        }
2093
2094
        @Override
2095
        public void accept(Visitor visitor, VisitorFilter filter) {
2096
            boolean visitChildren = true;
2097
            if (filter==null || filter.accept(this)) {
2098
                visitor.visit(this);
2099
            } else {
2100
                visitChildren = !filter.skipChildren();
2101
            }
2102
            if(visitChildren){
2103
                if (this.table != null) {
2104
                    this.table.accept(visitor, filter);
2105
                }
2106
                if (this.has_where()) {
2107
                    this.where.accept(visitor, filter);
2108
                }
2109
            }
2110
        }
2111
2112
        @Override
2113
        public GeometryExpressionBuilder where() {
2114
            if (this.where == null) {
2115
                this.where = createExpressionBuilder();
2116
            }
2117
            return this.where;
2118
        }
2119
2120
        @Override
2121
        public TableNameBuilder table() {
2122
            if (table == null) {
2123
                table = createTableNameBuilder();
2124
            }
2125
            return table;
2126
        }
2127
2128
        @Override
2129
        public boolean has_where() {
2130
            return this.where != null;
2131
        }
2132
2133
        @Override
2134
        public String toString() {
2135
            return this.toString(formatter());
2136
        }
2137
2138
        @Override
2139
        public String toString(Formatter<Value> formatter) {
2140
            if (formatter!=null && formatter.canApply(this)) {
2141
                return formatter.format(this);
2142
            }
2143
            /*
2144
             * DELETE FROM table_name
2145
             * WHERE some_column=some_value;
2146
             */
2147
            String sql;
2148
            if (this.has_where()) {
2149
                sql = MessageFormat.format(
2150
                        STMT_DELETE_FROM_table_WHERE_expresion,
2151
                        this.table.toString(formatter),
2152
                        this.where.toString(formatter)
2153
                );
2154
            } else {
2155
                sql = MessageFormat.format(
2156
                        STMT_DELETE_FROM_table,
2157
                        this.table.toString(formatter)
2158
                );
2159
            }
2160
            return sql;
2161
        }
2162
    }
2163
2164
    public class CreateIndexBuilderBase
2165
            extends AbstractStatement
2166
            implements CreateIndexBuilder {
2167
2168
        protected boolean ifNotExist = false;
2169
        protected boolean isUnique = false;
2170
        protected String indexName;
2171
        protected boolean isSpatial = false;
2172
        protected TableNameBuilder table;
2173
        protected final List<String> columns;
2174
        protected FeatureType type;
2175
2176
        public CreateIndexBuilderBase() {
2177
            this.columns = new ArrayList<>();
2178
        }
2179
2180
        @Override
2181
        public CreateIndexBuilder unique() {
2182
            this.isUnique = true;
2183
            return this;
2184
        }
2185
2186
        @Override
2187
        public CreateIndexBuilder if_not_exist() {
2188
            this.ifNotExist = true;
2189
            return this;
2190
        }
2191
2192
        @Override
2193
        public CreateIndexBuilder name(String name) {
2194
            this.indexName = name;
2195
            return this;
2196
        }
2197
2198
        @Override
2199
        public CreateIndexBuilder name(String tableName, String columnName) {
2200
            this.indexName = tableName + "_IDX_" + columnName;
2201
            return this;
2202
        }
2203
2204
        @Override
2205
        public CreateIndexBuilder spatial() {
2206
            this.isSpatial = true;
2207
            return this;
2208
        }
2209
2210
        @Override
2211
        public CreateIndexBuilder column(String name) {
2212
            this.columns.add(name);
2213
            return this;
2214
        }
2215
2216
        @Override
2217
        public TableNameBuilder table() {
2218
            if (table == null) {
2219
                table = createTableNameBuilder();
2220
            }
2221
            return table;
2222
        }
2223
2224
        @Override
2225
        public void setFeatureType(FeatureType type) {
2226
            this.type = type;
2227
        }
2228
2229
        @Override
2230
        public void accept(Visitor visitor, VisitorFilter filter) {
2231
            boolean visitChildren = true;
2232
            if (filter==null || filter.accept(this)) {
2233
                visitor.visit(this);
2234
            } else {
2235
                visitChildren = !filter.skipChildren();
2236
            }
2237
            if(visitChildren){
2238
                if (this.table != null) {
2239
                    this.table.accept(visitor, filter);
2240
                }
2241
            }
2242
        }
2243
2244
        @Override
2245
        public String toString() {
2246
            return this.toString(formatter());
2247
        }
2248
2249
        @Override
2250
        public String toString(Formatter<Value> formatter) {
2251
            if (formatter!=null && formatter.canApply(this)) {
2252
                return formatter.format(this);
2253
            }
2254
            StringBuilder builder = new StringBuilder();
2255
            boolean first = true;
2256
            for (String sql : toStrings(formatter)) {
2257
                if (StringUtils.isEmpty(sql)) {
2258
                    continue;
2259
                }
2260
                if (first) {
2261
                    first = false;
2262
                } else {
2263
                    builder.append("; ");
2264
                }
2265
                builder.append(sql);
2266
            }
2267
            return builder.toString();
2268
        }
2269
2270
        @Override
2271
        public List<String> toStrings() {
2272
            return this.toStrings(formatter());
2273
        }
2274
2275
        @Override
2276
        public List<String> toStrings(Formatter formatter) {
2277
            StringBuilder builder = new StringBuilder();
2278
            builder.append("CREATE ");
2279
            if (this.isUnique) {
2280
                builder.append("UNIQUE ");
2281
            }
2282
            builder.append("INDEX ");
2283
            if (this.ifNotExist) {
2284
                builder.append("IF NOT EXISTS ");
2285
            }
2286
            builder.append(as_identifier(this.indexName));
2287
            builder.append(" ON ");
2288
            builder.append(this.table.toString(formatter));
2289
            if (this.isSpatial) {
2290
                builder.append(" USING GIST ");
2291
            }
2292
            builder.append(" ( ");
2293
            boolean is_first_column = true;
2294
            for (String column : this.columns) {
2295
                if (is_first_column) {
2296
                    is_first_column = false;
2297
                } else {
2298
                    builder.append(", ");
2299
                }
2300
                builder.append(column);
2301
            }
2302
            builder.append(" )");
2303
2304
            List<String> sqls = new ArrayList<>();
2305
            sqls.add(builder.toString());
2306
            return sqls;
2307
        }
2308
2309
    }
2310
2311
    public class DropIndexBuilderBase
2312
            extends AbstractStatement
2313
            implements DropIndexBuilder {
2314
2315
        protected boolean ifExist = false;
2316
        protected String indexName;
2317
2318
        public DropIndexBuilderBase() {
2319
        }
2320
2321
        @Override
2322
        public DropIndexBuilder if_exist() {
2323
            this.ifExist = true;
2324
            return this;
2325
        }
2326
2327
        @Override
2328
        public DropIndexBuilder name(String name) {
2329
            this.indexName = name;
2330
            return this;
2331
        }
2332
2333
        @Override
2334
        public DropIndexBuilder name(String tableName, String columnName) {
2335
            this.indexName = tableName + "_IDX_" + columnName;
2336
            return this;
2337
        }
2338
2339
        @Override
2340
        public String toString() {
2341
            return this.toString(formatter());
2342
        }
2343
2344
        @Override
2345
        public String toString(Formatter<Value> formatter) {
2346
            if (formatter!=null && formatter.canApply(this)) {
2347
                return formatter.format(this);
2348
            }
2349
            StringBuilder builder = new StringBuilder();
2350
            boolean first = true;
2351
            for (String sql : toStrings(formatter)) {
2352
                if (StringUtils.isEmpty(sql)) {
2353
                    continue;
2354
                }
2355
                if (first) {
2356
                    first = false;
2357
                } else {
2358
                    builder.append("; ");
2359
                }
2360
                builder.append(sql);
2361
            }
2362
            return builder.toString();
2363
        }
2364
2365
        @Override
2366
        public List<String> toStrings() {
2367
            return this.toStrings(formatter());
2368
        }
2369
2370
        @Override
2371
        public List<String> toStrings(Formatter formatter) {
2372
            StringBuilder builder = new StringBuilder();
2373
            builder.append("DROP INDEX ");
2374
            if (this.ifExist) {
2375
                builder.append("IF EXISTS ");
2376
            }
2377
            builder.append(as_identifier(this.indexName));
2378
            List<String> sqls = new ArrayList<>();
2379
            sqls.add(builder.toString());
2380
            return sqls;
2381
        }
2382
2383
    }
2384
2385
    public class AlterTableBuilderBase
2386
            extends AbstractStatement
2387
            implements AlterTableBuilder {
2388
2389
        protected TableNameBuilder table;
2390
        protected List<String> drops;
2391
        protected List<ColumnDescriptor> adds;
2392
2393
        // alters debera dejarse de usar en favor de operations
2394
        @Deprecated
2395
        protected List<ColumnDescriptor> alters;
2396
        protected List<Pair<Bitmask,ColumnDescriptor>> operations;
2397
2398
        protected List<Pair<String, String>> renames;
2399
        protected String drop_primary_key_column;
2400
        protected final SQLBuilderBase sqlbuilder;
2401
2402
        public AlterTableBuilderBase(SQLBuilderBase sqlbuilder) {
2403
            this.sqlbuilder = sqlbuilder;
2404
            this.drops = new ArrayList<>();
2405
            this.adds = new ArrayList<>();
2406
            this.alters = new ArrayList<>();
2407
            this.operations = new ArrayList<>();
2408
            this.renames = new ArrayList<>();
2409
        }
2410
2411
        public List<Pair<Bitmask,ColumnDescriptor>> getOperations() {
2412
            return this.operations;
2413
        }
2414
2415
        @Override
2416
        public boolean isEmpty() {
2417
            return this.drops.isEmpty()
2418
                    && this.adds.isEmpty()
2419
                    && this.alters.isEmpty()
2420
                    && this.operations.isEmpty()
2421
                    && this.renames.isEmpty();
2422
        }
2423
2424
        @Override
2425
        public void accept(Visitor visitor, VisitorFilter filter) {
2426
            boolean visitChildren = true;
2427
            if (filter==null || filter.accept(this)) {
2428
                visitor.visit(this);
2429
            } else {
2430
                visitChildren = !filter.skipChildren();
2431
            }
2432
            if(visitChildren){
2433
                if (this.table != null) {
2434
                    this.table.accept(visitor, filter);
2435
                }
2436
            }
2437
        }
2438
2439
        @Override
2440
        public TableNameBuilder table() {
2441
            if (table == null) {
2442
                table = createTableNameBuilder();
2443
            }
2444
            return table;
2445
        }
2446
2447
        @Override
2448
        public AlterTableBuilder drop_column(String columnName) {
2449
            this.drops.add(columnName);
2450
            return this;
2451
        }
2452
2453
        @Override
2454
        public AlterTableBuilder drop_primary_key(String columnName) {
2455
            this.drop_primary_key_column = columnName;
2456
            return this;
2457
        }
2458
2459
        @Override
2460
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2461
            this.adds.add(new ColumnDescriptorBase(fad));
2462
            return this;
2463
        }
2464
2465
        @Override
2466
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue, boolean allowIndexDuplicateds) {
2467
            if (isPk || isAutomatic) {
2468
                allowNulls = false;
2469
            }
2470
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds));
2471
            return this;
2472
        }
2473
2474
        @Override
2475
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2476
            if (StringUtils.isEmpty(columnName)) {
2477
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2478
            }
2479
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2480
            return this;
2481
        }
2482
2483
        @Override
2484
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2485
            if (StringUtils.isEmpty(columnName)) {
2486
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2487
            }
2488
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2489
            return this;
2490
        }
2491
2492
        protected void update_or_add_alters(ColumnDescriptorBase column) {
2493
            int i = 0;
2494
            for (; i < alters.size(); i++) {
2495
                ColumnDescriptor prevColumn = alters.get(i);
2496
                if( prevColumn.getName().equalsIgnoreCase(column.getName()) ) {
2497
                    // Si ya existia la actualizamos
2498
                    alters.set(i, column);
2499
                    break;
2500
                }
2501
2502
            }
2503
            if( i >= alters.size() ) {
2504
                // Si no existis la a?adimos
2505
                this.alters.add(column);
2506
            }
2507
        }
2508
2509
        @Override
2510
        public AlterTableBuilder alter_column(Bitmask operation, FeatureAttributeDescriptor fad) {
2511
            ColumnDescriptorBase column = new ColumnDescriptorBase(fad);
2512
            update_or_add_alters(column);
2513
            if( operation==null ) {
2514
                operation = Bitmask.createBitmask(0);
2515
            }
2516
            if( operation.isEmpty() ) {
2517
                operation.setBit(ALTER_COLUMN_ALL);
2518
            }
2519
            this.operations.add(new ImmutablePair<>(operation,column));
2520
            return this;
2521
        }
2522
2523
        @Override
2524
        public AlterTableBuilder alter_column(Bitmask operation, String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue, boolean allowIndexDuplicateds) {
2525
            if ( (isPk || isAutomatic) && allowNulls) {
2526
                allowNulls = false;
2527
                operation.setBit(ALTER_COLUMN_SET_NULL);
2528
            }
2529
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds);
2530
            update_or_add_alters(column);
2531
            if( operation == null ) {
2532
                operation = Bitmask.createBitmask(0);
2533
            }
2534
            if( operation.isEmpty() ) {
2535
                operation.setBit(ALTER_COLUMN_ALL);
2536
            }
2537
            this.operations.add(new ImmutablePair<>(operation,column));
2538
            return this;
2539
        }
2540
2541
//        @Override
2542
//        public AlterTableBuilder alter_column(Bitmask operation,String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2543
//            if ( (isPk || isAutomatic) && allowNulls) {
2544
//                allowNulls = false;
2545
//                operation.setBit(ALTER_COLUMN_SET_NULL);
2546
//            }
2547
//            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue);
2548
//            update_or_add_alters(column);
2549
//            this.operations.add(new ImmutablePair<>(operation,column));
2550
//            return this;
2551
//        }
2552
2553
        @Override
2554
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2555
            if (StringUtils.isEmpty(columnName)) {
2556
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2557
            }
2558
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls);
2559
            update_or_add_alters(column);
2560
            if( operation == null ) {
2561
                operation = Bitmask.createBitmask(0);
2562
            }
2563
            if( operation.isEmpty() ) {
2564
                operation.setBit(ALTER_COLUMN_ALL);
2565
            }
2566
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2567
            this.operations.add(new ImmutablePair<>(operation,column));
2568
            return this;
2569
        }
2570
2571
        @Override
2572
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2573
            if (StringUtils.isEmpty(columnName)) {
2574
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2575
            }
2576
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls);
2577
            update_or_add_alters(column);
2578
            if( operation == null ) {
2579
                operation = Bitmask.createBitmask(0);
2580
            }
2581
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2582
            this.operations.add(new ImmutablePair<>(operation,column));
2583
            return this;
2584
        }
2585
2586
        @Override
2587
        public AlterTableBuilder rename_column(String source, String target) {
2588
            this.renames.add(new ImmutablePair(source, target));
2589
            return this;
2590
        }
2591
2592
        protected String getConstrainName(String constrainType, String columnName) {
2593
            return this.sqlbuilder.getConstrainName(table, columnName, constrainType);
2594
        }
2595
2596
        protected List<String> alter_table_add_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2597
            // ALTER TABLE table_name ADD CONSTRAINT IF NOT EXISTS constraint_name PRIMARY KEY(column_name)
2598
            List<String> sqls = new ArrayList<>();
2599
            StringBuilder builder = new StringBuilder();
2600
            builder.append("ALTER TABLE ");
2601
            builder.append(this.table.toString(formatter));
2602
            builder.append(" ADD CONSTRAINT ");
2603
            builder.append("IF NOT EXISTS ");
2604
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2605
            builder.append(" PRIMARY KEY( ");
2606
            builder.append(as_identifier(column.getName()));
2607
            builder.append(" )");
2608
            sqls.add(builder.toString());
2609
            return sqls;
2610
        }
2611
2612
        protected List<String> alter_table_drop_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2613
            // ALTER TABLE table_name DROP CONSTRAINT constraint_name
2614
            StringBuilder builder = new StringBuilder();
2615
            builder.append("ALTER TABLE ");
2616
            builder.append(this.table.toString(formatter));
2617
            builder.append(" DROP CONSTRAINT ");
2618
            builder.append("IF EXISTS ");
2619
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2620
            return Collections.singletonList(builder.toString());
2621
        }
2622
2623
        protected List<String> create_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2624
            CreateIndexBuilder createIndex = this.sqlbuilder.createCreateIndexBuilder();
2625
            if( column.isGeometry() ) {
2626
                createIndex.spatial();
2627
            }
2628
            createIndex.if_not_exist();
2629
            createIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2630
            createIndex.column(column.getName());
2631
            createIndex.table()
2632
                    .database(this.table.getDatabase())
2633
                    .schema(this.table.getSchema())
2634
                    .name(this.table.getName()
2635
            );
2636
            if(!column.allowIndexDuplicateds()){
2637
                createIndex.unique();
2638
            }
2639
            return createIndex.toStrings();
2640
        }
2641
2642
        protected List<String> drop_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2643
            DropIndexBuilder dropIndex = this.sqlbuilder.createDropIndexBuilder();
2644
            dropIndex.if_exist();
2645
            dropIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2646
            return dropIndex.toStrings();
2647
        }
2648
2649
        protected List<String> alter_table_alter_column_set_data_type_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2650
            StringBuilder builder = new StringBuilder();
2651
            builder.append("ALTER TABLE ");
2652
            builder.append(this.table.toString(formatter));
2653
            builder.append(" ALTER COLUMN ");
2654
            builder.append(as_identifier(column.getName()));
2655
            builder.append(" SET DATA TYPE ");
2656
            if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2657
                builder.append(" SERIAL");
2658
            } else {
2659
                builder.append(
2660
                        sqltype(
2661
                                column.getType(),
2662
                                column.getSize(),
2663
                                column.getPrecision(),
2664
                                column.getScale(),
2665
                                column.getGeometryType(),
2666
                                column.getGeometrySubtype()
2667
                        )
2668
                );
2669
            }
2670
            return Collections.singletonList(builder.toString());
2671
        }
2672
2673
        protected List<String> alter_table_alter_column_set_default_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2674
            StringBuilder builder = new StringBuilder();
2675
            builder.append("ALTER TABLE ");
2676
            builder.append(this.table.toString(formatter));
2677
            builder.append(" ALTER COLUMN ");
2678
            builder.append(as_identifier(column.getName()));
2679
            if (column.getDefaultValue() == null) {
2680
                if (column.allowNulls()) {
2681
                    builder.append(" SET DEFAULT NULL");
2682
                } else {
2683
                    builder.append(" DROP DEFAULT");
2684
                }
2685
            } else {
2686
                builder.append(" SET DEFAULT '");
2687
                builder.append(column.getDefaultValue().toString());
2688
                builder.append("'");
2689
            }
2690
            return Collections.singletonList(builder.toString());
2691
        }
2692
2693
        protected List<String> alter_table_alter_column_set_null_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2694
            StringBuilder builder = new StringBuilder();
2695
            builder.append("ALTER TABLE ");
2696
            builder.append(this.table.toString(formatter));
2697
            builder.append(" ALTER COLUMN ");
2698
            builder.append(as_identifier(column.getName()));
2699
            if (column.allowNulls()) {
2700
                builder.append(" SET NULL");
2701
            } else {
2702
                builder.append(" SET NOT NULL");
2703
            }
2704
            return Collections.singletonList(builder.toString());
2705
        }
2706
2707
        protected List<String> alter_table_drop_column_sqls(Formatter<Value> formatter, String columnName) {
2708
            StringBuilder builder = new StringBuilder();
2709
            builder.append("ALTER TABLE ");
2710
            builder.append(this.table.toString(formatter));
2711
            builder.append(" DROP COLUMN ");
2712
            builder.append(" IF EXISTS ");
2713
            builder.append(as_identifier(columnName));
2714
            return Collections.singletonList(builder.toString());
2715
        }
2716
2717
        protected List<String> alter_table_add_column_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2718
            List<String> sqls = new ArrayList<>();
2719
            StringBuilder builder = new StringBuilder();
2720
            builder.append("ALTER TABLE ");
2721
            builder.append(this.table.toString(formatter));
2722
            builder.append(" ADD COLUMN ");
2723
            builder.append(as_identifier(column.getName()));
2724
            builder.append(" ");
2725
            if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2726
                builder.append(" SERIAL");
2727
            } else {
2728
                builder.append(
2729
                        sqltype(
2730
                                column.getType(),
2731
                                column.getSize(),
2732
                                column.getPrecision(),
2733
                                column.getScale(),
2734
                                column.getGeometryType(),
2735
                                column.getGeometrySubtype()
2736
                        )
2737
                );
2738
            }
2739
            if (column.getDefaultValue() == null) {
2740
                if (column.allowNulls()) {
2741
                    builder.append(" DEFAULT NULL");
2742
                }
2743
            } else {
2744
                builder.append(" DEFAULT '");
2745
                builder.append(Objects.toString(column.getDefaultValue(),""));
2746
                builder.append("'");
2747
            }
2748
            if (column.allowNulls()) {
2749
                builder.append(" NULL");
2750
            } else {
2751
                builder.append(" NOT NULL");
2752
            }
2753
            if (column.isPrimaryKey()) {
2754
                builder.append(" PRIMARY KEY");
2755
            }
2756
            sqls.add(builder.toString());
2757
2758
            if( column.isGeometry() ) {
2759
                sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2760
            }
2761
            if( column.isIndexed() ) {
2762
                sqls.addAll(create_index_sqls(formatter, column));
2763
            }
2764
            return sqls;
2765
        }
2766
2767
        protected List<String> alter_table_alter_column_rename_sqls(Formatter<Value> formatter, String oldName, String newName) {
2768
            StringBuilder builder = new StringBuilder();
2769
            builder.append("ALTER TABLE ");
2770
            builder.append(this.table.toString(formatter));
2771
            builder.append(" ALTER COLUMN ");
2772
            builder.append(as_identifier(oldName));
2773
            builder.append(" RENAME TO ");
2774
            builder.append(as_identifier(newName));
2775
            return Collections.singletonList(builder.toString());
2776
        }
2777
2778
        protected List<String> alter_column_add_geometry_constraint_sqls(Formatter<ExpressionBuilder.Value> formatter, ColumnDescriptor column) {
2779
            return Collections.EMPTY_LIST;
2780
        }
2781
2782
        @Override
2783
        public String toString() {
2784
            return this.toString(formatter());
2785
        }
2786
2787
        @Override
2788
        public String toString(Formatter<Value> formatter) {
2789
            if (formatter!=null && formatter.canApply(this)) {
2790
                return formatter.format(this);
2791
            }
2792
            StringBuilder builder = new StringBuilder();
2793
            boolean first = true;
2794
            for (String sql : toStrings(formatter)) {
2795
                if (StringUtils.isEmpty(sql)) {
2796
                    continue;
2797
                }
2798
                if (first) {
2799
                    first = false;
2800
                } else {
2801
                    builder.append("; ");
2802
                }
2803
                builder.append(sql);
2804
            }
2805
            return builder.toString();
2806
        }
2807
2808
        @Override
2809
        public List<String> toStrings() {
2810
            return this.toStrings(formatter());
2811
        }
2812
2813
        @Override
2814
        public List<String> toStrings(Formatter formatter) {
2815
            List<String> sqls = new ArrayList<>();
2816
            if (this.isEmpty()) {
2817
                return sqls;
2818
            }
2819
            for (String column : drops) {
2820
                sqls.addAll(alter_table_drop_column_sqls(formatter, column));
2821
            }
2822
            for (ColumnDescriptor column : adds) {
2823
                sqls.addAll(alter_table_add_column_sqls(formatter, column));
2824
            }
2825
            for (Pair<Bitmask,ColumnDescriptor> operationAndColumn : this.getOperations()) {
2826
                Bitmask operation = operationAndColumn.getLeft();
2827
                ColumnDescriptor column = operationAndColumn.getRight();
2828
                if( operation.isSetBit(ALTER_COLUMN_ALL) ) {
2829
                    if( column.isPrimaryKey() ) {
2830
                        sqls.addAll(alter_table_add_primarykey_sqls(formatter, column));
2831
                    } else {
2832
                        sqls.addAll(alter_table_drop_primarykey_sqls(formatter, column));
2833
                        if( column.isIndexed() ) {
2834
                            sqls.addAll(create_index_sqls(formatter, column));
2835
                        }
2836
                    }
2837
                    sqls.addAll(alter_table_alter_column_set_data_type_sqls(formatter, column));
2838
                    sqls.addAll(alter_table_alter_column_set_default_sqls(formatter, column));
2839
                    sqls.addAll(alter_table_alter_column_set_null_sqls(formatter, column));
2840
                    if( column.isGeometry() ) {
2841
                        sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2842
                    }
2843
                } else {
2844
                    if( operation.isSetBit(ALTER_COLUMN_SET_NULL) ) { // Debe ir antes del "add primary key"
2845
                        sqls.addAll(alter_table_alter_column_set_null_sqls(formatter, column));
2846
                    }
2847
2848
                    if( operation.isSetBit(ALTER_COLUMN_SET_DATA_TYPE) ) {
2849
                        sqls.addAll(alter_table_alter_column_set_data_type_sqls(formatter, column));
2850
                    }
2851
2852
                    if( operation.isSetBit(ALTER_COLUMN_ADD_PRIMARY_KEY) ) {
2853
                        sqls.addAll(alter_table_add_primarykey_sqls(formatter, column));
2854
                    }
2855
2856
                    if( operation.isSetBit(ALTER_COLUMN_DROP_PRIMARY_KEY) ) {
2857
                        sqls.addAll(alter_table_drop_primarykey_sqls(formatter, column));
2858
                    }
2859
2860
                    if( operation.isSetBit(ALTER_COLUMN_SET_DEFAULT) ) {
2861
                        sqls.addAll(alter_table_alter_column_set_default_sqls(formatter, column));
2862
                    }
2863
2864
                    if( operation.isSetBit(ALTER_COLUMN_CREATE_INDEX) ) {
2865
                        sqls.addAll(create_index_sqls(formatter, column));
2866
                    }
2867
2868
                    if( operation.isSetBit(ALTER_COLUMN_DROP_INDEX) ) {
2869
                        sqls.addAll(drop_index_sqls(formatter, column));
2870
                    }
2871
2872
                    if( operation.isSetBit(ALTER_COLUMN_GEOMETRY) ) {
2873
                        if( column.isGeometry() ) {
2874
                            sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2875
                        }
2876
                    }
2877
2878
                }
2879
            }
2880
2881
            for (Pair<String, String> pair : renames) {
2882
                sqls.addAll(alter_table_alter_column_rename_sqls(formatter, pair.getLeft(), pair.getRight()));
2883
            }
2884
            return sqls;
2885
        }
2886
2887
    }
2888
2889
    public class CreateTableBuilderBase
2890
            extends AbstractStatement
2891
            implements CreateTableBuilder {
2892
2893
        protected TableNameBuilder table;
2894
        protected List<ColumnDescriptor> columns;
2895
2896
        public CreateTableBuilderBase() {
2897
            this.columns = new ArrayList<>();
2898
        }
2899
2900
        @Override
2901
        public void accept(Visitor visitor, VisitorFilter filter) {
2902
            boolean visitChildren = true;
2903
            if (filter==null || filter.accept(this)) {
2904
                visitor.visit(this);
2905
            } else {
2906
                visitChildren = !filter.skipChildren();
2907
            }
2908
            if(visitChildren){
2909
                if (this.table != null) {
2910
                    this.table.accept(visitor, filter);
2911
                }
2912
            }
2913
        }
2914
2915
        @Override
2916
        public TableNameBuilder table() {
2917
            if (table == null) {
2918
                table = createTableNameBuilder();
2919
            }
2920
            return table;
2921
        }
2922
2923
        @Override
2924
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2925
            this.columns.add(new ColumnDescriptorBase(fad));
2926
            return this;
2927
        }
2928
2929
        @Override
2930
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2931
            if (StringUtils.isEmpty(columnName)) {
2932
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2933
            }
2934
            if (isPk || isAutomatic) {
2935
                allowNulls = false;
2936
            }
2937
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2938
            return this;
2939
        }
2940
2941
        @Override
2942
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2943
            if (StringUtils.isEmpty(columnName)) {
2944
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2945
            }
2946
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2947
            return this;
2948
        }
2949
2950
        @Override
2951
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2952
            if (StringUtils.isEmpty(columnName)) {
2953
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2954
            }
2955
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2956
            return this;
2957
        }
2958
2959
        @Override
2960
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2961
            if (StringUtils.isEmpty(columnName)) {
2962
                return null;
2963
            }
2964
            for (ColumnDescriptor column : columns) {
2965
                if (columnName.equals(column.getName())) {
2966
                    return column;
2967
                }
2968
            }
2969
            return null;
2970
        }
2971
2972
        @Override
2973
        public String toString() {
2974
            return this.toString(formatter());
2975
        }
2976
2977
        @Override
2978
        public String toString(Formatter<Value> formatter) {
2979
            if (formatter!=null && formatter.canApply(this)) {
2980
                return formatter.format(this);
2981
            }
2982
            StringBuilder builder = new StringBuilder();
2983
            boolean first = true;
2984
            for (String sql : toStrings(formatter)) {
2985
                if (StringUtils.isEmpty(sql)) {
2986
                    continue;
2987
                }
2988
                if (first) {
2989
                    first = false;
2990
                } else {
2991
                    builder.append("; ");
2992
                }
2993
                builder.append(sql);
2994
            }
2995
            return builder.toString();
2996
        }
2997
2998
        @Override
2999
        public List<String> toStrings() {
3000
            return this.toStrings(formatter());
3001
        }
3002
3003
        @Override
3004
        /*
3005
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
3006
        */
3007
        public List<String> toStrings(Formatter formatter) {
3008
            List<String> sqls = new ArrayList<>();
3009
            /**
3010
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
3011
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
3012
             * column_constraint [ ... ] ] | table_constraint | LIKE
3013
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
3014
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
3015
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
3016
             *
3017
             * where column_constraint is:
3018
             *
3019
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
3020
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
3021
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
3022
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
3023
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
3024
             *
3025
             * and table_constraint is:
3026
             *
3027
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
3028
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
3029
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
3030
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
3031
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
3032
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
3033
             */
3034
3035
            StringBuilder builder = new StringBuilder();
3036
3037
            builder.append("CREATE TABLE ");
3038
            builder.append(this.table.toString(formatter));
3039
            builder.append(" (");
3040
            boolean first = true;
3041
            for (ColumnDescriptor column : columns) {
3042
                if (first) {
3043
                    first = false;
3044
                } else {
3045
                    builder.append(", ");
3046
                }
3047
                builder.append(as_identifier(column.getName()));
3048
                builder.append(" ");
3049
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
3050
                    builder.append("SERIAL");
3051
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
3052
                    builder.append("BIGSERIAL");
3053
                } else {
3054
                    builder.append(sqltype(
3055
                            column.getType(),
3056
                            column.getSize(),
3057
                            column.getPrecision(),
3058
                            column.getScale(),
3059
                            column.getGeometryType(),
3060
                            column.getGeometrySubtype()
3061
                    )
3062
                    );
3063
                }
3064
                if (column.getDefaultValue() == null) {
3065
                    if (column.allowNulls()) {
3066
                        builder.append(" DEFAULT NULL");
3067
                    }
3068
                } else {
3069
                    builder.append(" DEFAULT '");
3070
                    builder.append(Objects.toString(column.getDefaultValue(),""));
3071
                    builder.append("'");
3072
                }
3073
                if (column.isPrimaryKey()) {
3074
                    builder.append(" NOT NULL");
3075
                    builder.append(" PRIMARY KEY");
3076
                } else {
3077
                    if (column.allowNulls()) {
3078
                        builder.append(" NULL");
3079
                    } else {
3080
                        builder.append(" NOT NULL");
3081
                    }
3082
                }
3083
            }
3084
            builder.append(" )");
3085
            sqls.add(builder.toString());
3086
            return sqls;
3087
        }
3088
    }
3089
3090
    public class InsertColumnBuilderBase
3091
            extends AbstractStatement
3092
            implements InsertColumnBuilder {
3093
3094
        protected Variable name;
3095
        protected Value value;
3096
3097
        public InsertColumnBuilderBase() {
3098
        }
3099
3100
        @Override
3101
        public void accept(Visitor visitor, VisitorFilter filter) {
3102
            boolean visitChildren = true;
3103
            if (filter==null || filter.accept(this)) {
3104
                visitor.visit(this);
3105
            } else {
3106
                visitChildren = !filter.skipChildren();
3107
            }
3108
            if(visitChildren){
3109
                if (this.name != null) {
3110
                    this.name.accept(visitor, filter);
3111
                }
3112
                if (this.value != null) {
3113
                    this.value.accept(visitor, filter);
3114
                }
3115
            }
3116
        }
3117
3118
        @Override
3119
        public InsertColumnBuilder name(String name) {
3120
            this.name = expression().variable(name);
3121
            return this;
3122
        }
3123
3124
        @Override
3125
        public InsertColumnBuilder with_value(Value value) {
3126
            this.value = value;
3127
            return this;
3128
        }
3129
3130
        @Override
3131
        public String getName() {
3132
            return this.name.name();
3133
        }
3134
3135
        @Override
3136
        public Value getValue() {
3137
            return this.value;
3138
        }
3139
3140
        @Override
3141
        public String toString() {
3142
            return this.toString(formatter());
3143
        }
3144
3145
        @Override
3146
        public String toString(Formatter<Value> formatter) {
3147
            if (formatter!=null && formatter.canApply(this)) {
3148
                return formatter.format(this);
3149
            }
3150
            return this.value.toString(formatter);
3151
        }
3152
    }
3153
3154
    public class MergeBuilderBase
3155
            extends InsertBuilderBase
3156
            implements MergeBuilder {
3157
3158
        protected List<String> keycolumns;
3159
3160
        public MergeBuilderBase() {
3161
            super();
3162
            this.keycolumns = new ArrayList<>();
3163
        }
3164
3165
        @Override
3166
        public MergeBuilder key(String id) {
3167
            this.keycolumns.add(id);
3168
            return this;
3169
        }
3170
3171
        @Override
3172
        public String toString(Formatter<Value> formatter) {
3173
            if (formatter!=null && formatter.canApply(this)) {
3174
                return formatter.format(this);
3175
            }
3176
            /*
3177
             * MERGE INTO table [ ( column [, ...] ) ] KEY (columnName [,...] ) { DEFAULT VALUES | VALUES (
3178
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3179
             * output_expression [ AS output_name ] [, ...] ]
3180
             */
3181
            StringBuilder builderKeyColumns = new StringBuilder();
3182
            StringBuilder builderColumns = new StringBuilder();
3183
            StringBuilder builderValues = new StringBuilder();
3184
3185
            boolean first = true;
3186
            for (InsertColumnBuilder column : columns) {
3187
                if (first) {
3188
                    first = false;
3189
                } else {
3190
                    builderColumns.append(", ");
3191
                }
3192
                builderColumns.append(as_identifier(column.getName()));
3193
            }
3194
            first = true;
3195
            for (String column : keycolumns) {
3196
                if (first) {
3197
                    first = false;
3198
                } else {
3199
                    builderKeyColumns.append(", ");
3200
                }
3201
                builderKeyColumns.append(as_identifier(column));
3202
            }
3203
            first = true;
3204
            for (InsertColumnBuilder column : columns) {
3205
                if (first) {
3206
                    first = false;
3207
                } else {
3208
                    builderValues.append(", ");
3209
                }
3210
                builderValues.append(column.toString(formatter));
3211
            }
3212
3213
            String sql = MessageFormat.format(
3214
                    STMT_MERGE_INTO_table_KEY_column_columns_VALUES_values,
3215
                    this.table.toString(formatter),
3216
                    builderColumns.toString(),
3217
                    builderKeyColumns.toString(),
3218
                    builderValues.toString()
3219
            );
3220
            return sql;
3221
3222
        }
3223
    }
3224
3225
3226
    public class InsertBuilderBase
3227
            extends AbstractStatement
3228
            implements InsertBuilder {
3229
3230
        protected List<InsertColumnBuilder> columns;
3231
        protected TableNameBuilder table;
3232
3233
        public InsertBuilderBase() {
3234
            this.columns = new ArrayList<>();
3235
        }
3236
3237
        @Override
3238
        public void accept(Visitor visitor, VisitorFilter filter) {
3239
            boolean visitChildren = true;
3240
            if (filter==null || filter.accept(this)) {
3241
                visitor.visit(this);
3242
            } else {
3243
                visitChildren = !filter.skipChildren();
3244
            }
3245
            if(visitChildren){
3246
                if (this.table != null) {
3247
                    this.table.accept(visitor, filter);
3248
                }
3249
                for (InsertColumnBuilder column : columns) {
3250
                    column.accept(visitor, filter);
3251
                }
3252
            }
3253
        }
3254
3255
        @Override
3256
        public TableNameBuilder table() {
3257
            if (table == null) {
3258
                table = createTableNameBuilder();
3259
            }
3260
            return table;
3261
        }
3262
3263
        @Override
3264
        public InsertColumnBuilder column() {
3265
            InsertColumnBuilder column = createInsertColumnBuilder();
3266
            this.columns.add(column);
3267
            return column;
3268
        }
3269
3270
        @Override
3271
        public String toString() {
3272
            return this.toString(formatter());
3273
        }
3274
3275
        @Override
3276
        public String toString(Formatter<Value> formatter) {
3277
            if (formatter!=null && formatter.canApply(this)) {
3278
                return formatter.format(this);
3279
            }
3280
            /*
3281
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
3282
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3283
             * output_expression [ AS output_name ] [, ...] ]
3284
             */
3285
            StringBuilder builderColumns = new StringBuilder();
3286
            StringBuilder builderValues = new StringBuilder();
3287
3288
            boolean first = true;
3289
            for (InsertColumnBuilder column : columns) {
3290
                if (first) {
3291
                    first = false;
3292
                } else {
3293
                    builderColumns.append(", ");
3294
                }
3295
                builderColumns.append(as_identifier(column.getName()));
3296
            }
3297
            first = true;
3298
            for (InsertColumnBuilder column : columns) {
3299
                if (first) {
3300
                    first = false;
3301
                } else {
3302
                    builderValues.append(", ");
3303
                }
3304
                builderValues.append(column.toString(formatter));
3305
            }
3306
3307
            String sql = MessageFormat.format(
3308
                    STMT_INSERT_INTO_table_columns_VALUES_values,
3309
                    this.table.toString(formatter),
3310
                    builderColumns.toString(),
3311
                    builderValues.toString()
3312
            );
3313
            return sql;
3314
3315
        }
3316
    }
3317
3318
    public class UpdateTableStatisticsBuilderBase
3319
            extends AbstractStatement
3320
            implements UpdateTableStatisticsBuilder {
3321
3322
        protected TableNameBuilder table;
3323
3324
        @Override
3325
        public void accept(Visitor visitor, VisitorFilter filter) {
3326
            boolean visitChildren = true;
3327
            if (filter==null || filter.accept(this)) {
3328
                visitor.visit(this);
3329
            } else {
3330
                visitChildren = !filter.skipChildren();
3331
            }
3332
            if(visitChildren){
3333
                if (this.table != null) {
3334
                    this.table.accept(visitor, filter);
3335
                }
3336
            }
3337
        }
3338
3339
        @Override
3340
        public TableNameBuilder table() {
3341
            if (table == null) {
3342
                table = createTableNameBuilder();
3343
            }
3344
            return table;
3345
        }
3346
3347
        @Override
3348
        public String toString() {
3349
            return this.toString(formatter());
3350
        }
3351
3352
        @Override
3353
        public String toString(Formatter<Value> formatter) {
3354
            if (formatter!=null && formatter.canApply(this)) {
3355
                return formatter.format(this);
3356
            }
3357
            StringBuilder builder = new StringBuilder();
3358
            boolean first = true;
3359
            for (String sql : toStrings(formatter)) {
3360
                if (StringUtils.isEmpty(sql)) {
3361
                    continue;
3362
                }
3363
                if (first) {
3364
                    first = false;
3365
                } else {
3366
                    builder.append("; ");
3367
                }
3368
                builder.append(sql);
3369
            }
3370
            return builder.toString();
3371
        }
3372
3373
        @Override
3374
        public List<String> toStrings() {
3375
            return this.toStrings(formatter());
3376
        }
3377
3378
        @Override
3379
        public List<String> toStrings(Formatter formatter) {
3380
            List<String> sqls = new ArrayList<>();
3381
3382
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
3383
                String sql = MessageFormat.format(
3384
                        STMT_UPDATE_TABLE_STATISTICS_table,
3385
                        table.toString(formatter)
3386
                );
3387
                if (!StringUtils.isEmpty(sql)) {
3388
                    sqls.add(sql);
3389
                }
3390
            }
3391
            return sqls;
3392
        }
3393
    }
3394
3395
    protected GeometryExpressionBuilder expressionBuilder;
3396
3397
    protected String defaultSchema;
3398
    protected boolean supportSchemas;
3399
    protected boolean hasSpatialFunctions;
3400
    protected GeometrySupportType geometrySupportType;
3401
    protected boolean allowAutomaticValues;
3402
3403
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
3404
3405
    protected String constant_true = "(1=1)";
3406
    protected String constant_false = "(1<>1)";
3407
3408
    protected String type_boolean = "BOOLEAN";
3409
    protected String type_byte = "TINYINT";
3410
    protected String type_bytearray = "BYTEA";
3411
    protected String type_geometry = "TEXT";
3412
    protected String type_char = "CHARACTER(1)";
3413
    protected String type_date = "DATE";
3414
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
3415
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
3416
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
3417
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
3418
    protected String type_int = "INT";
3419
    protected String type_long = "BIGINT";
3420
    protected String type_string = "TEXT";
3421
    protected String type_string_p = "VARCHAR({0,Number,#######})";
3422
    protected String type_time = "TIME";
3423
    protected String type_timestamp = "TIMESTAMP";
3424
    protected String type_version = "VARCHAR(30)";
3425
    protected String type_URI = "TEXT";
3426
    protected String type_URL = "TEXT";
3427
    protected String type_FILE = "TEXT";
3428
    protected String type_FOLDER = "TEXT";
3429
3430
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
3431
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
3432
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
3433
    protected String STMT_MERGE_INTO_table_KEY_column_columns_VALUES_values = "MERGE INTO {0} ( {1} )  KEY( {2} ) VALUES ( {3} )";
3434
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
3435
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
3436
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
3437
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
3438
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
3439
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
3440
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3441
3442
    public SQLBuilderBase() {
3443
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3444
        this.expressionBuilder.setProperty(PROP_SQLBUILDER, this);
3445
3446
        this.hasSpatialFunctions = false;
3447
        this.supportSchemas = true;
3448
        this.geometrySupportType = GeometrySupportType.WKT;
3449
3450
        this.defaultSchema = "public";
3451
        this.allowAutomaticValues = true;
3452
3453
    }
3454
3455
    @Override
3456
    public void setProperties(Class filter, final Object... values) {
3457
        this.expressionBuilder.setProperties(filter, values);
3458
        setProperties(this, filter, values);
3459
    }
3460
3461
    @Override
3462
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3463
        if(visitable == null){
3464
            return;
3465
        }
3466
        if(visitable instanceof PropertiesSupport){
3467
            for (int i = 0; i < values.length; i+=2) {
3468
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3469
            }
3470
        }
3471
        visitable.accept((Visitable v) -> {
3472
            if(v instanceof PropertiesSupport){
3473
                for (int i = 0; i < values.length; i+=2) {
3474
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3475
                }
3476
            }
3477
        }, new ClassVisitorFilter(filter) );
3478
    }
3479
3480
    public String quote_for_identifiers() {
3481
        return "\"";
3482
    }
3483
3484
    public String quote_for_strings() {
3485
        return "'";
3486
    }
3487
3488
    @Override
3489
    public String as_identifier(String id) {
3490
        String quote = this.quote_for_identifiers();
3491
//        No se porque no esta disponible wrapIfMissing
3492
//        return StringUtils.wrapIfMissing(id,quote);
3493
        if (id.startsWith(quote)) {
3494
            return id;
3495
        }
3496
        return quote + id + quote;
3497
3498
    }
3499
3500
    @Override
3501
    public String as_clob(String s) {
3502
        int chunkSize = 1024;
3503
        StringBuilder builder = new StringBuilder();
3504
        builder.append("(CAST('");
3505
        for (int i = 0; i < s.length(); i += chunkSize) {
3506
            String chunk = s.substring(i, Math.min(s.length(), i + chunkSize));
3507
            if( i>0 ) {
3508
                builder.append("' AS NCLOB) || CAST('");
3509
            }
3510
            builder.append(StringUtils.replace(chunk, "'", "''"));
3511
        }
3512
        builder.append("' AS NCLOB))");
3513
        return builder.toString();
3514
    }
3515
3516
    @Override
3517
    public String as_string(String s) {
3518
        String quote = this.quote_for_strings();
3519
//        No se porque no esta disponible wrapIfMissing
3520
//        return StringUtils.wrapIfMissing(id,quote);
3521
        if (s.startsWith(quote)) {
3522
            return s;
3523
        }
3524
        return quote + s + quote;
3525
3526
    }
3527
3528
    @Override
3529
    public String as_string(byte[] data) {
3530
        return this.expressionBuilder.bytearray_0x(data);
3531
//        return this.expressionBuilder.bytearray_hex(data);
3532
//        return this.expressionBuilder.bytearray_x(data);
3533
    }
3534
3535
    @Override
3536
    public String as_string(boolean value) {
3537
        return value? "TRUE" : "FALSE";
3538
    }
3539
3540
    @Override
3541
    public String as_string(Number value) {
3542
        return Objects.toString(value);
3543
    }
3544
3545
    @Override
3546
    public String as_string(Object value) {
3547
        if( value == null ) {
3548
            return "NULL";
3549
        }
3550
        if( value instanceof CharSequence ) {
3551
            return as_string(value.toString());
3552
        }
3553
        if( value instanceof Number ) {
3554
            return as_string((Number)value);
3555
        }
3556
        if( value instanceof Boolean ) {
3557
            return as_string((boolean)value);
3558
        }
3559
        if( value instanceof byte[] ) {
3560
            return as_string((byte[])value);
3561
        }
3562
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3563
    }
3564
3565
    @Override
3566
    public GeometryExpressionBuilder expression() {
3567
        return this.expressionBuilder;
3568
    }
3569
3570
    @Override
3571
    public boolean has_spatial_functions() {
3572
        return this.hasSpatialFunctions;
3573
    }
3574
3575
    @Override
3576
    public GeometrySupportType geometry_support_type() {
3577
        return this.geometrySupportType;
3578
    }
3579
3580
    protected GeometryExpressionBuilder createExpressionBuilder() {
3581
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3582
    }
3583
3584
    @Override
3585
    public Object srs_id(IProjection projection) {
3586
        String abrev = projection.getAbrev();
3587
        return abrev.split(":")[1].trim();
3588
    }
3589
3590
    @Override
3591
    public String default_schema() {
3592
        return this.defaultSchema;
3593
    }
3594
3595
    @Override
3596
    public boolean support_schemas() {
3597
        return this.supportSchemas;
3598
    }
3599
3600
    @Override
3601
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3602
        switch (type) {
3603
            case DataTypes.BOOLEAN:
3604
                return type_boolean;
3605
            case DataTypes.CHAR:
3606
                return type_char;
3607
3608
3609
            case DataTypes.BYTE:
3610
                return type_byte;
3611
            case DataTypes.INT:
3612
                return type_int;
3613
            case DataTypes.LONG:
3614
                return type_long;
3615
3616
            case DataTypes.FLOAT:
3617
                return type_float;
3618
            case DataTypes.DOUBLE:
3619
                return type_double;
3620
            case DataTypes.DECIMAL:
3621
                if (precision < 1) {
3622
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3623
                }
3624
                if (scale < 1) {
3625
                  return MessageFormat.format(type_decimal_p, precision);
3626
                }
3627
                return MessageFormat.format(type_decimal_ps, precision, scale);
3628
3629
3630
            case DataTypes.STRING:
3631
                if (size < 0) {
3632
                    return type_string;
3633
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3634
                    return MessageFormat.format(type_string_p, size);
3635
                }
3636
                return type_string;
3637
3638
3639
            case DataTypes.DATE:
3640
                return type_date;
3641
            case DataTypes.TIME:
3642
                return type_time;
3643
            case DataTypes.TIMESTAMP:
3644
                return type_timestamp;
3645
3646
            case DataTypes.BYTEARRAY:
3647
                return type_bytearray;
3648
3649
            case DataTypes.GEOMETRY:
3650
                return type_geometry;
3651
3652
            case DataTypes.VERSION:
3653
                return type_version;
3654
            case DataTypes.URI:
3655
                return type_URI;
3656
            case DataTypes.URL:
3657
                return type_URL;
3658
            case DataTypes.FILE:
3659
                return type_FILE;
3660
            case DataTypes.FOLDER:
3661
                return type_FOLDER;
3662
            default:
3663
                return null;
3664
        }
3665
    }
3666
3667
    @Override
3668
    public Object sqlgeometrytype(int type, int subtype) {
3669
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3670
        // identificadores numericos para el tipo y otros strings.
3671
        // Por defecto vamos a devolver strings.
3672
        if (sqlgeometrytypes == null) {
3673
            sqlgeometrytypes = new HashMap<>();
3674
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3675
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3676
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3677
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3678
3679
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3680
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3681
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3682
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3683
3684
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3685
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3686
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3687
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3688
3689
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3690
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3691
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3692
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3693
3694
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3695
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3696
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3697
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3698
3699
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3700
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3701
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3702
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3703
3704
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3705
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3706
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3707
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3708
3709
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3710
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3711
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3712
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3713
3714
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3715
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3716
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3717
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3718
        }
3719
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3720
    }
3721
3722
    @Override
3723
    public Object sqlgeometrydimension(int type, int subtype) {
3724
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3725
        // identificadores numericos para las dimensiones y otros strings.
3726
        // Por defecto vamos a devolver enteros.
3727
        switch (subtype) {
3728
            case Geometry.SUBTYPES.GEOM3D:
3729
                return 3;
3730
            case Geometry.SUBTYPES.GEOM2DM:
3731
                return 3;
3732
            case Geometry.SUBTYPES.GEOM3DM:
3733
                return 4;
3734
            case Geometry.SUBTYPES.GEOM2D:
3735
            default:
3736
                return 2;
3737
        }
3738
    }
3739
3740
    @Override
3741
    public SelectColumnBuilder column() {
3742
        return createSelectColumnBuilder();
3743
    }
3744
3745
    @Override
3746
    public TableNameBuilder createTableNameBuilder() {
3747
        return new TableNameBuilderBase();
3748
    }
3749
3750
    protected SelectColumnBuilder createSelectColumnBuilder() {
3751
        return new SelectColumnBuilderBase(this);
3752
    }
3753
3754
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3755
        return new UpdateColumnBuilderBase();
3756
    }
3757
3758
    protected InsertColumnBuilder createInsertColumnBuilder() {
3759
        return new InsertColumnBuilderBase();
3760
    }
3761
3762
    protected OrderByBuilder createOrderByBuilder() {
3763
        return new OrderByBuilderBase();
3764
    }
3765
3766
    protected FromBuilder createFromBuilder() {
3767
        return new FromBuilderBase();
3768
    }
3769
3770
    public SelectBuilder createSelectBuilder() {
3771
        return new SelectBuilderBase();
3772
    }
3773
3774
    protected UpdateBuilder createUpdateBuilder() {
3775
        return new UpdateBuilderBase();
3776
    }
3777
3778
    protected DeleteBuilder createDeleteBuilder() {
3779
        return new DeleteBuilderBase();
3780
    }
3781
3782
    protected GrantBuilder createGrantBuilder() {
3783
        return new GrantBuilderBase();
3784
    }
3785
3786
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3787
        return new GrantRoleBuilderBase(table, role);
3788
    }
3789
3790
    protected DropTableBuilder createDropTableBuilder() {
3791
        return new DropTableBuilderBase();
3792
    }
3793
3794
    protected CreateTableBuilder createCreateTableBuilder() {
3795
        return new CreateTableBuilderBase();
3796
    }
3797
3798
    protected AlterTableBuilder createAlterTableBuilder() {
3799
        return new AlterTableBuilderBase(this);
3800
    }
3801
3802
    protected InsertBuilder createInsertBuilder() {
3803
        return new InsertBuilderBase();
3804
    }
3805
3806
    protected MergeBuilder createMergeBuilder() {
3807
        return new MergeBuilderBase();
3808
    }
3809
3810
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3811
        return new UpdateTableStatisticsBuilderBase();
3812
    }
3813
3814
    public CreateIndexBuilder createCreateIndexBuilder() {
3815
        return new CreateIndexBuilderBase();
3816
    }
3817
3818
    public DropIndexBuilder createDropIndexBuilder() {
3819
        return new DropIndexBuilderBase();
3820
    }
3821
3822
    @Override
3823
    public SelectBuilder select() {
3824
        if (this.select == null) {
3825
            this.select = this.createSelectBuilder();
3826
        }
3827
        return this.select;
3828
    }
3829
3830
    @Override
3831
    public UpdateBuilder update() {
3832
        if (this.update == null) {
3833
            this.update = this.createUpdateBuilder();
3834
        }
3835
        return this.update;
3836
    }
3837
3838
    @Override
3839
    public UpdateTableStatisticsBuilder update_table_statistics() {
3840
        if (this.update_table_statistics == null) {
3841
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3842
        }
3843
        return this.update_table_statistics;
3844
    }
3845
3846
    @Override
3847
    public DropTableBuilder drop_table() {
3848
        if (this.drop_table == null) {
3849
            this.drop_table = this.createDropTableBuilder();
3850
        }
3851
        return this.drop_table;
3852
    }
3853
3854
    @Override
3855
    public CreateIndexBuilder create_index() {
3856
        if (this.create_index == null) {
3857
            this.create_index = this.createCreateIndexBuilder();
3858
        }
3859
        return this.create_index;
3860
    }
3861
3862
    @Override
3863
    public DropIndexBuilder drop_index() {
3864
        if (this.drop_index == null) {
3865
            this.drop_index = this.createDropIndexBuilder();
3866
        }
3867
        return this.drop_index;
3868
    }
3869
3870
    @Override
3871
    public DeleteBuilder delete() {
3872
        if (this.delete == null) {
3873
            this.delete = this.createDeleteBuilder();
3874
        }
3875
        return this.delete;
3876
    }
3877
3878
    @Override
3879
    public InsertBuilder insert() {
3880
        if (this.insert == null) {
3881
            this.insert = this.createInsertBuilder();
3882
        }
3883
        return this.insert;
3884
    }
3885
3886
    @Override
3887
    public MergeBuilder merge() {
3888
        if (this.merge == null) {
3889
            this.merge = this.createMergeBuilder();
3890
        }
3891
        return this.merge;
3892
    }
3893
3894
    @Override
3895
    public TableNameBuilder table_name() {
3896
        if (this.table_name == null) {
3897
            this.table_name = this.createTableNameBuilder();
3898
        }
3899
        return this.table_name;
3900
    }
3901
3902
3903
    @Override
3904
    public AlterTableBuilder alter_table() {
3905
        if (this.alter_table == null) {
3906
            this.alter_table = this.createAlterTableBuilder();
3907
        }
3908
        return this.alter_table;
3909
    }
3910
3911
    @Override
3912
    public CreateTableBuilder create_table() {
3913
        if (this.create_table == null) {
3914
            this.create_table = this.createCreateTableBuilder();
3915
        }
3916
        return this.create_table;
3917
    }
3918
3919
    @Override
3920
    public GrantBuilder grant() {
3921
        if (this.grant == null) {
3922
            this.grant = this.createGrantBuilder();
3923
        }
3924
        return this.grant;
3925
    }
3926
3927
    @Override
3928
    public Column column(String name) {
3929
        ColumnBase col = new ColumnBase(null, name);
3930
        return col;
3931
    }
3932
3933
    @Override
3934
    public Column column(TableNameBuilder table, String name) {
3935
        ColumnBase col = new ColumnBase(table, name);
3936
        return col;
3937
    }
3938
3939
    public Column column_from(Variable variable) {
3940
        Column c = null;
3941
        if (variable instanceof Column) {
3942
            c = this.column(((Column) variable).table(), variable.name());
3943
        } else {
3944
            c = this.column(variable.name());
3945
        }
3946
        c.copyPropertiesFrom(variable);
3947
        return c;
3948
3949
    }
3950
3951
    public Column column_from(TableNameBuilder table, Variable variable) {
3952
        Column c = this.column(table, variable.name());
3953
        c.copyPropertiesFrom(variable);
3954
        return c;
3955
    }
3956
3957
3958
3959
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3960
        return new JoinBase(type, table, expression);
3961
    }
3962
3963
    @Override
3964
    public void accept(Visitor visitor, VisitorFilter filter) {
3965
        if (this.select != null) {
3966
            this.select.accept(visitor, filter);
3967
        }
3968
        if (this.update != null) {
3969
            this.update.accept(visitor, filter);
3970
        }
3971
        if (this.insert != null) {
3972
            this.insert.accept(visitor, filter);
3973
        }
3974
        if (this.merge != null) {
3975
            this.merge.accept(visitor, filter);
3976
        }
3977
        if (this.delete != null) {
3978
            this.delete.accept(visitor, filter);
3979
        }
3980
        if (this.alter_table != null) {
3981
            this.alter_table.accept(visitor, filter);
3982
        }
3983
        if (this.create_table != null) {
3984
            this.create_table.accept(visitor, filter);
3985
        }
3986
        if (this.drop_table != null) {
3987
            this.drop_table.accept(visitor, filter);
3988
        }
3989
        if (this.table_name != null) {
3990
            this.table_name.accept(visitor, filter);
3991
        }
3992
    }
3993
3994
    @Override
3995
    public Formatter formatter() {
3996
        return expression().formatter();
3997
    }
3998
3999
    @Override
4000
    public String toString() {
4001
        return this.toString(formatter());
4002
    }
4003
4004
    @Override
4005
    public String toString(Formatter formatter) {
4006
        if (this.select != null) {
4007
            return this.select.toString(formatter);
4008
        }
4009
        if (this.update != null) {
4010
            return this.update.toString(formatter);
4011
        }
4012
        if (this.insert != null) {
4013
            return this.insert.toString(formatter);
4014
        }
4015
        if (this.merge != null) {
4016
            return this.merge.toString(formatter);
4017
        }
4018
        if (this.delete != null) {
4019
            return this.delete.toString(formatter);
4020
        }
4021
        if (this.alter_table != null) {
4022
            return this.alter_table.toString(formatter);
4023
        }
4024
        if (this.create_table != null) {
4025
            return this.create_table.toString(formatter);
4026
        }
4027
        if (this.drop_table != null) {
4028
            return this.drop_table.toString(formatter);
4029
        }
4030
        if (this.update_table_statistics != null) {
4031
            return this.update_table_statistics.toString(formatter);
4032
        }
4033
        if (this.create_index != null) {
4034
            return this.create_index.toString(formatter);
4035
        }
4036
        if (this.drop_index != null) {
4037
            return this.drop_index.toString(formatter);
4038
        }
4039
        if (this.table_name != null) {
4040
            return this.table_name.toString(formatter);
4041
        }
4042
        return "";
4043
    }
4044
4045
    @Override
4046
    public CountBuilder count() {
4047
        return new CountBuilderBase();
4048
    }
4049
4050
    @Override
4051
    public List<Parameter> parameters() {
4052
        final List<Parameter> params = new ArrayList<>();
4053
        this.accept((Visitable value) -> {
4054
            params.add((Parameter) value);
4055
        }, new ClassVisitorFilter(Parameter.class));
4056
        return params;
4057
    }
4058
4059
    @Override
4060
    public List<Variable> variables() {
4061
        final List<Variable> vars = new ArrayList<>();
4062
        this.accept(new Visitor() {
4063
            @Override
4064
            public void visit(Visitable value) {
4065
                if (!vars.contains((Variable) value)) {
4066
                    vars.add((Variable) value);
4067
                }
4068
            }
4069
        }, new ClassVisitorFilter(Variable.class));
4070
        return vars;
4071
    }
4072
4073
    @Override
4074
    public List<String> parameters_names() {
4075
        List<String> params = new ArrayList<>();
4076
        for (Parameter param : parameters()) {
4077
            String s;
4078
            switch (param.type()) {
4079
                case PARAMETER_TYPE_CONSTANT:
4080
                    Object theValue = param.value();
4081
                    if (theValue == null) {
4082
                        s = "null";
4083
                    } else if (theValue instanceof String) {
4084
                        s = "'" + (String) theValue + "'";
4085
                    } else {
4086
                        s = theValue.toString();
4087
                    }
4088
                    break;
4089
                case PARAMETER_TYPE_VARIABLE:
4090
                default:
4091
                    s = "\"" + param.name() + "\"";
4092
            }
4093
            params.add(s);
4094
        }
4095
        return params;
4096
    }
4097
4098
    @Override
4099
    public List<String> variables_names() {
4100
        List<String> vars = new ArrayList<>();
4101
        for (Variable var : this.variables()) {
4102
            vars.add(var.name());
4103
        }
4104
        Collections.sort(vars);
4105
        return vars;
4106
    }
4107
4108
    protected String[] aggregateFunctionNames = new String[] {
4109
        "MAX",
4110
        "MIN",
4111
        "COUNT",
4112
        "SUM"
4113
    };
4114
4115
    @Override
4116
    public boolean isAggregateFunction(String funcname) {
4117
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
4118
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
4119
                return true;
4120
            }
4121
        }
4122
        return false;
4123
    }
4124
4125
    @Override
4126
    public int getMaxRecomendedSQLLength() {
4127
        return DEFAULT_RECOMENDED_SQL_LENGTH;
4128
    }
4129
4130
    public String getConstrainName(TableNameBuilder table, String columnName, String constrainType) {
4131
        // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
4132
        String constraint_name = table.getName() + "_" + constrainType + "_" + columnName;
4133
        return constraint_name;
4134
    }
4135
}