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

History | View | Annotate | Download (105 KB)

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

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

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

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

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

    
75
    protected abstract class AbstractStatementPart extends AbstractValue {
76

    
77
    }
78

    
79
    protected abstract class AbstractStatement extends AbstractStatementPart {
80

    
81
    }
82

    
83
    protected class ColumnDescriptorBase implements ColumnDescriptor {
84

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
322
    public class ColumnBase extends AbstractValue implements Column {
323

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

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

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

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

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

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

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

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

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

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

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

    
393
        public TableNameBuilderBase() {
394
        }
395

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

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

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

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

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

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

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

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

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

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

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

    
476
        @Override
477
        public boolean equals(Object obj) {
478
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
479
                return false;
480
            }
481
            TableNameBuilder other = (TableNameBuilder) obj;
482
            
483
            if (this.has_database() != other.has_database()) {
484
                return false;
485
            }
486
            String thisSchema = null;
487
            String otherSchema = null;
488
            if(support_schemas()) {
489
                thisSchema = this.schemaName;
490
                if (StringUtils.isBlank(thisSchema)) {
491
                    thisSchema = default_schema();
492
                }
493
                otherSchema = other.getSchema();
494
                if (StringUtils.isBlank(otherSchema)) {
495
                    otherSchema = default_schema();
496
                }
497
            }
498
            if (this.has_database()) {
499
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
500
                           StringUtils.equals(thisSchema, otherSchema) &&
501
                           StringUtils.equals(this.tableName,other.getName());
502
            } else {
503
                    return StringUtils.equals(thisSchema, otherSchema) &&
504
                           StringUtils.equals(this.tableName,other.getName());
505
            }
506
        }
507

    
508
        @Override
509
        public int hashCode() {
510
            int hash = 7;
511
            hash = 37 * hash + Objects.hashCode(this.toString());
512
            return hash;
513
        }
514

    
515
    }
516

    
517
    public class CountBuilderBase
518
            extends AbstractStatementPart
519
            implements CountBuilder {
520

    
521
        protected Value value;
522
        protected boolean distinct;
523
        protected boolean all;
524

    
525
        public CountBuilderBase() {
526
            this.value = null;
527
            this.distinct = false;
528
            this.all = false;
529
        }
530

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

    
537
        @Override
538
        public CountBuilder column(Value value) {
539
            this.value = value;
540
            return this;
541
        }
542

    
543
        @Override
544
        public CountBuilder distinct() {
545
            this.distinct = true;
546
            return this;
547
        }
548

    
549
        @Override
550
        public String toString() {
551
            return this.toString(formatter());
552
        }
553

    
554
        @Override
555
        public String toString(Formatter formatter) {
556
            if (formatter!=null && formatter.canApply(this)) {
557
                return formatter.format(this);
558
            }
559
            if (this.all) {
560
                return "COUNT(*)";
561
            }
562
            if (this.distinct) {
563
                return MessageFormat.format(
564
                        "COUNT(DISTINCT {0})",
565
                        value.toString(formatter)
566
                );
567
            }
568
            return MessageFormat.format(
569
                    "COUNT({0})",
570
                    value.toString(formatter)
571
            );
572
        }
573

    
574
    }
575

    
576
    protected class JoinBase 
577
            extends AbstractStatementPart
578
            implements StatementPart 
579
        {
580
        protected String type;
581
        protected TableNameBuilder table;
582
        protected Value expression;
583
        
584
        public JoinBase(String type, TableNameBuilder table, Value expression) {
585
            this.type = type;
586
            this.table = table;
587
            this.expression = expression;
588
        }
589

    
590
        @Override
591
        public String toString() {
592
            return this.toString(formatter());
593
        }
594

    
595
        @Override
596
        public String toString(Formatter<Value> formatter) {
597
            if (formatter!=null && formatter.canApply(this)) {
598
                return formatter.format(this);
599
            }
600
            StringBuilder builder = new StringBuilder();
601
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
602
            builder.append(this.type.toUpperCase());
603
            builder.append(" JOIN ");
604
            builder.append(this.table.toString(formatter));
605
            builder.append(" ON ");
606
            builder.append(this.expression.toString(formatter));
607
            return builder.toString();
608
        }
609
        
610
        
611
    }
612
    
613
    public class FromBuilderBase
614
            extends AbstractStatementPart
615
            implements FromBuilder {
616

    
617
        protected TableNameBuilder tableName;
618
        protected String subquery;
619
        protected String passthrough;
620
        protected List<JoinBase> joins;
621

    
622
        public FromBuilderBase() {
623
            this.tableName = null;
624
            this.subquery = null;
625
            this.passthrough = null;
626
            this.joins = null;
627
        }
628

    
629
        @Override
630
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
631
            JoinBase join = createJoin("LEFT", table, expression);
632
            if( this.joins==null ) {
633
                this.joins = new ArrayList<>();
634
            }
635
            this.joins.add(join);
636
            return this;
637
        }
638
        
639
        @Override
640
        public TableNameBuilder table() {
641
            if (tableName == null) {
642
                this.tableName = createTableNameBuilder();
643
            }
644
            return this.tableName;
645
        }
646

    
647
        @Override
648
        public void accept(Visitor visitor, VisitorFilter filter) {
649
            if (filter==null || filter.accept(this)) {
650
                visitor.visit(this);
651
            }
652
            if (this.tableName != null) {
653
                this.tableName.accept(visitor, filter);
654
            }
655
        }
656

    
657
        @Override
658
        public FromBuilder custom(String passthrough) {
659
            this.passthrough = passthrough;
660
            return this;
661
        }
662

    
663
        @Override
664
        public FromBuilder subquery(String subquery) {
665
            this.subquery = subquery;
666
            return this;
667
        }
668

    
669
        @Override
670
        public String toString() {
671
            return this.toString(formatter());
672
        }
673

    
674
        @Override
675
        public String toString(Formatter<Value> formatter) {
676
            if (formatter!=null && formatter.canApply(this)) {
677
                return formatter.format(this);
678
            }
679
            if (!StringUtils.isEmpty(passthrough)) {
680
                return passthrough;
681
            }
682
            if (!StringUtils.isEmpty(subquery)) {
683
                return "( " + this.subquery + ") as _subquery_alias_ ";
684
            }
685
            if( this.joins==null || this.joins.isEmpty() ) {
686
                return this.tableName.toString(formatter);
687
            }
688
            StringBuilder builder = new StringBuilder();
689
            builder.append(this.tableName.toString(formatter));
690
            for (JoinBase join : this.joins) {
691
                builder.append(" ");
692
                builder.append(join.toString(formatter));
693
            }
694
            return builder.toString();
695
        }
696

    
697
    }
698

    
699
    public class SelectColumnBuilderBase
700
            extends AbstractStatementPart
701
            implements SelectColumnBuilder {
702

    
703
        protected Variable name = null;
704
        protected String alias = null;
705
        protected Value value = null;
706
        protected boolean asGeometry = false;
707
        protected TableNameBuilder table;
708

    
709
        @Override
710
        public void accept(Visitor visitor, VisitorFilter filter) {
711
            if (filter==null || filter.accept(this)) {
712
                visitor.visit(this);
713
            }
714
            if (this.name != null) {
715
                this.name.accept(visitor, filter);
716
            }
717
            if (this.value != null) {
718
                this.value.accept(visitor, filter);
719
            }
720
        }
721

    
722
        @Override
723
        public void replace(Value target, Value replacement) {
724
            if (this.name!=null ) {
725
                if( this.name == target) {
726
                    this.name = (Variable) replacement;
727
                }
728
            }
729
            if( this.value!=null ) {
730
                if (this.value == target) {
731
                    this.value = replacement;
732
                } else {
733
                    this.value.replace(target, replacement);
734
                }
735
            }
736
        }
737

    
738
        @Override
739
        public SelectColumnBuilder name(String name) {
740
            return this.name(null, name);
741
        }
742

    
743
        @Override
744
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
745
            String quote = quote_for_identifiers();
746
            if (name.startsWith(quote)) {
747
                // Remove quotes
748
                name = name.substring(1, name.length() - 1);
749
            }
750
            this.name = expression().variable(name);
751
            this.table = table;
752
            this.value = null;
753
            this.asGeometry = false;
754
            return this;
755
        }
756

    
757
        @Override
758
        public SelectColumnBuilder all() {
759
            this.name = null;
760
            this.value = expression().custom("*");
761
            this.asGeometry = false;
762
            return this;
763
        }
764

    
765
        @Override
766
        public SelectColumnBuilder as_geometry() {
767
            this.asGeometry = true;
768
            return this;
769
        }
770

    
771
        @Override
772
        public SelectColumnBuilder value(Value value) {
773
            this.value = value;
774
            this.name = null;
775
            return this;
776
        }
777

    
778
        @Override
779
        public SelectColumnBuilder as(String alias) {
780
            this.alias = alias;
781
            return this;
782
        }
783

    
784
        @Override
785
        public String getName() {
786
            if (this.name==null) {
787
                return null;
788
            }
789
            return this.name.name();
790
        }
791

    
792
        @Override
793
        public String getAlias() {
794
            return this.alias;
795
        }
796

    
797
        @Override
798
        public String getValue() {
799
            return this.alias;
800
        }
801

    
802
        @Override
803
        public String toString() {
804
            return this.toString(formatter());
805
        }
806

    
807
        @Override
808
        public String toString(Formatter<Value> formatter) {
809
            if (formatter!=null && formatter.canApply(this)) {
810
                return formatter.format(this);
811
            }
812
            StringBuilder builder = new StringBuilder();
813
            if (this.asGeometry) {
814
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
815
            } else {
816
                if (this.name != null) {
817
                    if( this.table==null ) {
818
                        builder.append(this.name.toString(formatter));
819
                    } else {
820
                        builder.append(this.table.toString(formatter));
821
                        builder.append(".");
822
                        builder.append(this.name.toString(formatter));
823
                    }
824
                } else {
825
                    builder.append(this.value.toString(formatter));
826
                }
827
            }
828
            if (this.alias != null) {
829
                builder.append(" AS ");
830
                builder.append(as_identifier(this.alias));
831
            }
832
            return builder.toString();
833
        }
834
        public boolean isGeometry() {
835
            return this.asGeometry;
836
        }
837
        
838
        public TableNameBuilder getTable() {
839
            return this.table;
840
        }
841
    }
842

    
843
    public class OrderByBuilderBase
844
            extends AbstractStatementPart
845
            implements OrderByBuilder {
846

    
847
        protected Value value;
848
        protected String custom;
849
        protected boolean ascending;
850

    
851
        public OrderByBuilderBase() {
852
            this.ascending = true;
853
        }
854

    
855
        @Override
856
        public void accept(Visitor visitor, VisitorFilter filter) {
857
            if (filter==null || filter.accept(this)) {
858
                visitor.visit(this);
859
            }
860
            if (this.value!=null) {
861
                this.value.accept(visitor, filter);
862
            }
863
        }
864

    
865
        @Override
866
        public OrderByBuilder column(String name) {
867
            this.value = expression().variable(name);
868
            return this;
869
        }
870
        
871
        @Override
872
        public boolean isColumn(String name) {
873
            if(this.value instanceof ExpressionBuilder.Variable){
874
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
875
            }
876
            return false;
877
        }
878
        
879
        @Override
880
        public OrderByBuilder value(Value expression) {
881
            this.value = expression;
882
            return this;
883
        }
884
        
885
        @Override
886
        public OrderByBuilder custom(String order) {
887
            this.custom = order;
888
            return this;
889
        }
890

    
891
        @Override
892
        public OrderByBuilder ascending() {
893
            this.ascending = true;
894
            return this;
895
        }
896

    
897
        @Override
898
        public OrderByBuilder ascending(boolean asc) {
899
            this.ascending = asc;
900
            return this;
901
        }
902

    
903
        @Override
904
        public OrderByBuilder descending() {
905
            this.ascending = false;
906
            return this;
907
        }
908

    
909
        @Override
910
        public String toString() {
911
            return this.toString(formatter());
912
        }
913

    
914
        @Override
915
        public String toString(Formatter<Value> formatter) {
916
            if (formatter!=null && formatter.canApply(this)) {
917
                return formatter.format(this);
918
            }
919
            if (!StringUtils.isEmpty(this.custom)) {
920
                return this.custom;
921
            }
922
            if (this.ascending) {
923
                return this.value.toString(formatter) + " ASC";
924
            }
925
            return this.value.toString(formatter) + " DESC";
926
        }
927
    }
928

    
929
    public class SelectBuilderBase
930
            extends AbstractStatement
931
            implements SelectBuilder {
932

    
933
        protected FromBuilder from;
934
        protected GeometryExpressionBuilder where;
935
        protected long limit = -1;
936
        protected long offset = -1;
937
        protected List<SelectColumnBuilder> columns;
938
        protected List<OrderByBuilder> order_by;
939
        protected boolean distinct;
940
        protected List<Value> groupColumn;
941
        protected boolean check_order_and_offset = true;
942

    
943
        public SelectBuilderBase() {
944
            this.columns = new ArrayList<>();
945
            this.distinct = false;
946
        }
947
        @Override
948
        public List<Value> getGroups() {
949
            return this.groupColumn;
950
        }
951
        
952
        public List<SelectColumnBuilder> getColumns() {
953
            return Collections.unmodifiableList(this.columns);
954
    }
955

    
956
        @Override
957
        public SelectBuilder group_by(Value... columns) {
958
            if( this.groupColumn==null ) {
959
                this.groupColumn = new ArrayList<>();
960
            }
961
            for (Value column : columns) {
962
                this.groupColumn.add(column);
963
            }
964
            return this;
965
        }
966

    
967
        @Override
968
        public void accept(Visitor visitor, VisitorFilter filter) {
969
            if (filter==null || filter.accept(this)) {
970
                visitor.visit(this);
971
            }
972
            for (SelectColumnBuilder column : columns) {
973
                column.accept(visitor, filter);
974
            }
975
            if (this.has_from()) {
976
                this.from.accept(visitor, filter);
977
            }
978
            if (this.has_where()) {
979
                this.where.accept(visitor, filter);
980
            }
981
            if (this.has_order_by()) {
982
                for (OrderByBuilder order : order_by) {
983
                    order.accept(visitor, filter);
984
                }
985
            }
986
            if (this.has_group_by()) {
987
                for (Value group : groupColumn) {
988
                    group.accept(visitor, filter);
989
                }
990
            }
991
        }
992

    
993
        @Override
994
        public void replace(Value target, Value replacement) {
995
            if( this.columns!=null ) {
996
                for (int i = 0; i < columns.size(); i++) {
997
                    SelectColumnBuilder column = columns.get(i);
998
                    if( column == target ) {
999
                        columns.set(i, (SelectColumnBuilder) replacement);
1000
                    } else {
1001
                        column.replace(target, replacement);
1002
                    }
1003
                }
1004
            }
1005
            if (this.has_from()) {
1006
                if( this.from == target ) {
1007
                    this.from = (FromBuilder) replacement;
1008
                } else {
1009
                    this.from.replace(target, replacement);
1010
                }
1011
            }
1012
            if (this.has_where()) {
1013
                if( this.where == target ) {
1014
                    this.where = (GeometryExpressionBuilder) replacement;
1015
                } else if( this.where.value() == target ) {
1016
                    this.where.value(replacement);
1017
                } else {
1018
                    this.where.value().replace(target, replacement);
1019
                }
1020
            }
1021
            if (this.has_order_by()) {
1022
                for (int i = 0; i < order_by.size(); i++) {
1023
                    OrderByBuilder order = order_by.get(i);
1024
                    if( order == target ) {
1025
                        order_by.set(i, (OrderByBuilder) replacement);
1026
                    } else {
1027
                        order.replace(target, replacement);
1028
                    }
1029
                }
1030
            }
1031
            if (this.has_group_by()) {
1032
                for (int i = 0; i < groupColumn.size(); i++) {
1033
                    Value group = groupColumn.get(i);
1034
                    if( group == target ) {
1035
                        groupColumn.set(i, replacement);
1036
                    } else {
1037
                        group.replace(target, replacement);
1038
                    }
1039
                }
1040
            }
1041
        }
1042

    
1043
        @Override
1044
        public SelectBuilder distinct() {
1045
            this.distinct = true;
1046
            return this;
1047
        }
1048

    
1049
        @Override
1050
        public SelectColumnBuilder column() {
1051
            SelectColumnBuilder builder = createSelectColumnBuilder();
1052
            this.columns.add(builder);
1053
            return builder;
1054
        }
1055

    
1056
        @Override
1057
        public SelectBuilder remove_all_columns() {
1058
            this.columns = new ArrayList<>();
1059
            return this;
1060
        }
1061
        
1062
        @Override
1063
        public boolean has_column(String name) {
1064
            for (SelectColumnBuilder column : columns) {
1065
                if (StringUtils.equals(name, column.getName())) {
1066
                    return true;
1067
                }
1068
                if (StringUtils.equals(name, column.getAlias())) {
1069
                    return true;
1070
                }
1071
            }
1072
            return false;
1073
        }
1074

    
1075
        @Override
1076
        public FromBuilder from() {
1077
            if (this.from == null) {
1078
                this.from = createFromBuilder();
1079
            }
1080
            return this.from;
1081
        }
1082

    
1083
        @Override
1084
        public boolean has_from() {
1085
            return this.from != null;
1086
        }
1087

    
1088
        @Override
1089
        public GeometryExpressionBuilder where() {
1090
            if (this.where == null) {
1091
                this.where = createExpressionBuilder();
1092
            }
1093
            return this.where;
1094
        }
1095

    
1096
        @Override
1097
        public boolean has_where() {
1098
            if (this.where == null) {
1099
                return false;
1100
            }
1101
            return this.where.value() != null;
1102
        }
1103

    
1104
        @Override
1105
        public SelectBuilder limit(long limit) {
1106
            this.limit = limit;
1107
            return this;
1108
        }
1109

    
1110
        @Override
1111
        public SelectBuilder limit(Long limit) {
1112
            if (limit == null) {
1113
                this.limit = 0;
1114
            } else {
1115
                this.limit = limit;
1116
            }
1117
            return this;
1118
        }
1119

    
1120
        @Override
1121
        public boolean has_limit() {
1122
            return this.limit > 0;
1123
        }
1124

    
1125
        @Override
1126
        public SelectBuilder offset(long offset) {
1127
            this.offset = offset;
1128
            return this;
1129
        }
1130

    
1131
        @Override
1132
        public boolean has_offset() {
1133
            return this.offset > 0;
1134
        }
1135

    
1136
        @Override
1137
        public OrderByBuilder order_by() {
1138
            if (this.order_by == null) {
1139
                this.order_by = new ArrayList<>();
1140
            }
1141
            OrderByBuilder order = createOrderByBuilder();
1142
            this.order_by.add(order);
1143
            return order;
1144
        }
1145
        
1146
        public OrderByBuilder getOrderBy(String column) {
1147
            if(this.order_by == null){
1148
                return null;
1149
            }
1150
            for (OrderByBuilder orderByBuilder : this.order_by) {
1151
                if(orderByBuilder.isColumn(column)){
1152
                    return orderByBuilder;
1153
                }
1154
            }
1155
            return null;
1156
        }
1157

    
1158
        @Override
1159
        public boolean has_order_by() {
1160
            if (this.order_by == null) {
1161
                return false;
1162
            }
1163
            return !this.order_by.isEmpty();
1164
        }
1165
        
1166
        @Override
1167
        public boolean has_group_by() {
1168
            if (this.groupColumn == null) {
1169
                return false;
1170
            }
1171
            return !this.groupColumn.isEmpty();
1172
        }
1173
        
1174
        @Override
1175
        public void disable_check_order_and_offset() {
1176
          this.check_order_and_offset = false;
1177
        }
1178
        
1179
        protected boolean isValid(StringBuilder message) {
1180
            if (message == null) {
1181
                message = new StringBuilder();
1182
            }
1183
            if( this.check_order_and_offset ) {
1184
              if (this.has_offset() && !this.has_order_by()) {
1185
                  // Algunos gestores de BBDD requieren que se especifique un
1186
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1187
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1188
                  // siempre.
1189
                  message.append("Can't use OFFSET without an ORDER BY.");
1190
                  return false;
1191
              }
1192
            }
1193
            return true;
1194
        }
1195

    
1196
        @Override
1197
        public String toString() {
1198
            return this.toString(formatter());
1199
        }
1200

    
1201
        @Override
1202
        public String toString(Formatter<Value> formatter) {
1203
            if (formatter!=null && formatter.canApply(this)) {
1204
                return formatter.format(this);
1205
            }
1206
            StringBuilder builder = new StringBuilder();
1207
            if (!this.isValid(builder)) {
1208
                throw new IllegalStateException(builder.toString());
1209
            }
1210
            builder.append("SELECT ");
1211
            if (this.distinct) {
1212
                builder.append("DISTINCT ");
1213
            }
1214
            boolean first = true;
1215
            for (SelectColumnBuilder column : columns) {
1216
                if (first) {
1217
                    first = false;
1218
                } else {
1219
                    builder.append(", ");
1220
                }
1221
                builder.append(column.toString(formatter));
1222
            }
1223

    
1224
            if (this.has_from()) {
1225
                builder.append(" FROM ");
1226
                builder.append(this.from.toString(formatter));
1227
            }
1228
            if (this.has_where()) {
1229
                builder.append(" WHERE ");
1230
                builder.append(this.where.toString(formatter));
1231
            }
1232
            if( this.has_group_by() ) {
1233
                builder.append(" GROUP BY ");
1234
                builder.append(this.groupColumn.get(0).toString(formatter));
1235
                for (int i = 1; i < groupColumn.size(); i++) {
1236
                    builder.append(", ");
1237
                    builder.append(this.groupColumn.get(i).toString(formatter));
1238
                }
1239
            }
1240
            if (this.has_order_by()) {
1241
                builder.append(" ORDER BY ");
1242
                first = true;
1243
                for (OrderByBuilder item : this.order_by) {
1244
                    if (first) {
1245
                        first = false;
1246
                    } else {
1247
                        builder.append(", ");
1248
                    }
1249
                    builder.append(item.toString(formatter));
1250
                }
1251
            }
1252

    
1253
            if (this.has_limit()) {
1254
                builder.append(" LIMIT ");
1255
                builder.append(this.limit);
1256
            }
1257
            if (this.has_offset()) {
1258
                builder.append(" OFFSET ");
1259
                builder.append(this.offset);
1260
            }
1261
            return builder.toString();
1262

    
1263
        }
1264
    }
1265

    
1266
    public class DropTableBuilderBase
1267
            extends AbstractStatement
1268
            implements DropTableBuilder {
1269

    
1270
        protected TableNameBuilder table;
1271

    
1272
        @Override
1273
        public TableNameBuilder table() {
1274
            if (table == null) {
1275
                table = createTableNameBuilder();
1276
            }
1277
            return table;
1278
        }
1279

    
1280
        @Override
1281
        public void accept(Visitor visitor, VisitorFilter filter) {
1282
            if (filter==null || filter.accept(this)) {
1283
                visitor.visit(this);
1284
            }
1285
            this.table.accept(visitor, filter);
1286
        }
1287

    
1288
        @Override
1289
        public String toString() {
1290
            return this.toString(formatter());
1291
        }
1292

    
1293
        @Override
1294
        public String toString(Formatter<Value> formatter) {
1295
            if (formatter!=null && formatter.canApply(this)) {
1296
                return formatter.format(this);
1297
            }
1298
            StringBuilder builder = new StringBuilder();
1299
            boolean first = true;
1300
            for (String sql : toStrings(formatter)) {
1301
                if (StringUtils.isEmpty(sql)) {
1302
                    continue;
1303
                }
1304
                if (first) {
1305
                    first = false;
1306
                } else {
1307
                    builder.append("; ");
1308
                }
1309
                builder.append(sql);
1310
            }
1311
            return builder.toString();
1312
        }
1313

    
1314
        @Override
1315
        public List<String> toStrings() {
1316
            return this.toStrings(formatter());
1317
        }
1318

    
1319
        @Override
1320
        public List<String> toStrings(Formatter formatter) {
1321
            List<String> sqls = new ArrayList<>();
1322

    
1323
            sqls.add(
1324
                    MessageFormat.format(
1325
                            STMT_DROP_TABLE_table,
1326
                            this.table.toString(formatter)
1327
                    )
1328
            );
1329
            String sql;
1330
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1331
                if (this.table.has_schema()) {
1332
                    sql = MessageFormat.format(
1333
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1334
                            as_string(this.table.getSchema()),
1335
                            as_string(this.table.getName())
1336
                    );
1337
                } else {
1338
                    sql = MessageFormat.format(
1339
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1340
                            as_identifier(this.table.getName())
1341
                    );
1342
                }
1343
                if (!StringUtils.isEmpty(sql)) {
1344
                    sqls.add(sql);
1345
                }
1346
            }
1347
            return sqls;
1348
        }
1349
    }
1350

    
1351
    public class GrantRoleBuilderBase
1352
            extends AbstractStatementPart
1353
            implements GrantRoleBuilder {
1354

    
1355
        protected TableNameBuilder table;
1356
        protected String role;
1357
        protected Set<Privilege> privileges;
1358

    
1359
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1360
            this.table = table;
1361
            this.role = role;
1362
            this.privileges = new HashSet<>();
1363
        }
1364

    
1365
        @Override
1366
        public GrantRoleBuilder privilege(Privilege privilege) {
1367
            privileges.add(privilege);
1368
            return this;
1369
        }
1370

    
1371
        @Override
1372
        public GrantRoleBuilder select() {
1373
            privileges.add(Privilege.SELECT);
1374
            return this;
1375
        }
1376

    
1377
        @Override
1378
        public GrantRoleBuilder update() {
1379
            privileges.add(Privilege.UPDATE);
1380
            return this;
1381
        }
1382

    
1383
        @Override
1384
        public GrantRoleBuilder insert() {
1385
            privileges.add(Privilege.INSERT);
1386
            return this;
1387
        }
1388

    
1389
        @Override
1390
        public GrantRoleBuilder delete() {
1391
            privileges.add(Privilege.DELETE);
1392
            return this;
1393
        }
1394

    
1395
        @Override
1396
        public GrantRoleBuilder truncate() {
1397
            privileges.add(Privilege.TRUNCATE);
1398
            return this;
1399
        }
1400

    
1401
        @Override
1402
        public GrantRoleBuilder reference() {
1403
            privileges.add(Privilege.REFERENCE);
1404
            return this;
1405
        }
1406

    
1407
        @Override
1408
        public GrantRoleBuilder trigger() {
1409
            privileges.add(Privilege.TRIGGER);
1410
            return this;
1411
        }
1412

    
1413
        @Override
1414
        public GrantRoleBuilder all() {
1415
            privileges.add(Privilege.ALL);
1416
            return this;
1417
        }
1418

    
1419
        protected String getPrivilegeName(Privilege privilege) {
1420
            switch (privilege) {
1421
                case DELETE:
1422
                    return "DELETE";
1423
                case INSERT:
1424
                    return "INSERT";
1425
                case REFERENCE:
1426
                    return "REFERENCE";
1427
                case SELECT:
1428
                    return "SELECT";
1429
                case TRIGGER:
1430
                    return "TRIGGER";
1431
                case TRUNCATE:
1432
                    return "TRUNCATE";
1433
                case UPDATE:
1434
                    return "UPDATE";
1435
                case ALL:
1436
                default:
1437
                    return "ALL";
1438
            }
1439
        }
1440

    
1441
        @Override
1442
        public String toString() {
1443
            return this.toString(formatter());
1444
        }
1445

    
1446
        @Override
1447
        public String toString(Formatter<Value> formatter) {
1448
            if (formatter!=null && formatter.canApply(this)) {
1449
                return formatter.format(this);
1450
            }
1451
            StringBuilder builder = new StringBuilder();
1452
            boolean first = true;
1453
            for (Privilege privilege : privileges) {
1454
                if (first) {
1455
                    first = false;
1456
                } else {
1457
                    builder.append(", ");
1458
                }
1459
                builder.append(this.getPrivilegeName(privilege));
1460
            }
1461
            String sql = MessageFormat.format(
1462
                    STMT_GRANT_privileges_ON_table_TO_role,
1463
                    builder.toString(),
1464
                    table.toString(formatter),
1465
                    role
1466
            );
1467
            return sql;
1468
        }
1469
    }
1470

    
1471
    public class GrantBuilderBase
1472
            extends AbstractStatement
1473
            implements GrantBuilder {
1474

    
1475
        protected TableNameBuilder table;
1476
        protected Map<String, GrantRoleBuilder> roles;
1477

    
1478
        public GrantBuilderBase() {
1479
            this.roles = new HashMap<>();
1480
        }
1481

    
1482
        @Override
1483
        public TableNameBuilder table() {
1484
            if (table == null) {
1485
                table = createTableNameBuilder();
1486
            }
1487
            return table;
1488
        }
1489

    
1490
        @Override
1491
        public void accept(Visitor visitor, VisitorFilter filter) {
1492
            if (filter==null || filter.accept(this)) {
1493
                visitor.visit(this);
1494
            }
1495
            if (this.table != null) {
1496
                this.table.accept(visitor, filter);
1497
            }
1498
        }
1499

    
1500
        @Override
1501
        public GrantRoleBuilder role(String role) {
1502
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1503
            if (roleBuilder == null) {
1504
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1505
                this.roles.put(role, roleBuilder);
1506
            }
1507
            return roleBuilder;
1508
        }
1509

    
1510
        @Override
1511
        public String toString() {
1512
            return this.toString(formatter());
1513
        }
1514

    
1515
        @Override
1516
        public String toString(Formatter<Value> formatter) {
1517
            if (formatter!=null && formatter.canApply(this)) {
1518
                return formatter.format(this);
1519
            }
1520
            StringBuilder builder = new StringBuilder();
1521
            boolean first = true;
1522
            for (String sql : toStrings(formatter)) {
1523
                if (StringUtils.isEmpty(sql)) {
1524
                    continue;
1525
                }
1526
                if (first) {
1527
                    first = false;
1528
                } else {
1529
                    builder.append("; ");
1530
                }
1531
                builder.append(sql);
1532
            }
1533
            return builder.toString();
1534
        }
1535

    
1536
        @Override
1537
        public List<String> toStrings() {
1538
            return this.toStrings(formatter());
1539
        }
1540

    
1541
        @Override
1542
        public List<String> toStrings(Formatter formatter) {
1543
            List<String> sqls = new ArrayList<>();
1544
            for (GrantRoleBuilder role : roles.values()) {
1545
                sqls.add(role.toString(formatter));
1546
            }
1547
            return sqls;
1548
        }
1549
    }
1550

    
1551
    public class UpdateColumnBuilderBase
1552
            extends InsertColumnBuilderBase
1553
            implements UpdateColumnBuilder {
1554

    
1555
        public UpdateColumnBuilderBase() {
1556
            super();
1557
        }
1558

    
1559
        @Override
1560
        public UpdateColumnBuilder name(String name) {
1561
            return (UpdateColumnBuilder) super.name(name);
1562
        }
1563

    
1564
        @Override
1565
        public UpdateColumnBuilder with_value(Value value) {
1566
            return (UpdateColumnBuilder) super.with_value(value);
1567
        }
1568

    
1569
    }
1570

    
1571
    public class UpdateBuilderBase
1572
            extends AbstractStatement
1573
            implements UpdateBuilder {
1574

    
1575
        protected GeometryExpressionBuilder where;
1576
        protected List<UpdateColumnBuilder> columns;
1577
        protected TableNameBuilder table;
1578

    
1579
        public UpdateBuilderBase() {
1580
            this.columns = new ArrayList<>();
1581
        }
1582

    
1583
        @Override
1584
        public void accept(Visitor visitor, VisitorFilter filter) {
1585
            if (filter==null || filter.accept(this)) {
1586
                visitor.visit(this);
1587
            }
1588
            if (this.table != null) {
1589
                this.table.accept(visitor, filter);
1590
            }
1591
            for (UpdateColumnBuilder column : columns) {
1592
                column.accept(visitor, filter);
1593
            }
1594
            if (this.has_where()) {
1595
                this.where.accept(visitor, filter);
1596
            }
1597
        }
1598

    
1599
        @Override
1600
        public GeometryExpressionBuilder where() {
1601
            if (this.where == null) {
1602
                this.where = createExpressionBuilder();
1603
            }
1604
            return this.where;
1605
        }
1606

    
1607
        @Override
1608
        public TableNameBuilder table() {
1609
            if (table == null) {
1610
                table = createTableNameBuilder();
1611
            }
1612
            return table;
1613
        }
1614

    
1615
        @Override
1616
        public UpdateColumnBuilder column() {
1617
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1618
            this.columns.add(column);
1619
            return column;
1620
        }
1621

    
1622
        @Override
1623
        public boolean has_where() {
1624
            return this.where != null;
1625
        }
1626

    
1627
        @Override
1628
        public String toString() {
1629
            return this.toString(formatter());
1630
        }
1631

    
1632
        @Override
1633
        public String toString(Formatter<Value> formatter) {
1634
            if (formatter!=null && formatter.canApply(this)) {
1635
                return formatter.format(this);
1636
            }
1637
            /*
1638
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1639
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1640
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1641
             * output_expression [ AS output_name ] [, ...] ]
1642
             */
1643
            StringBuilder columnsAndValues = new StringBuilder();
1644

    
1645
            boolean first = true;
1646
            for (UpdateColumnBuilder column : columns) {
1647
                if (first) {
1648
                    first = false;
1649
                } else {
1650
                    columnsAndValues.append(", ");
1651
                }
1652
                columnsAndValues.append(as_identifier(column.getName()));
1653
                columnsAndValues.append(" = ");
1654
                columnsAndValues.append(column.getValue().toString(formatter));
1655
            }
1656

    
1657
            String sql;
1658
            if (this.has_where()) {
1659
                sql = MessageFormat.format(
1660
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1661
                        this.table.toString(formatter),
1662
                        columnsAndValues.toString(),
1663
                        this.where.toString(formatter)
1664
                );
1665
            } else {
1666
                sql = MessageFormat.format(
1667
                        STMT_UPDATE_table_SET_columnsAndValues,
1668
                        this.table.toString(formatter),
1669
                        columnsAndValues.toString()
1670
                );
1671
            }
1672
            return sql;
1673
        }
1674
    }
1675

    
1676
    public class DeleteBuilderBase
1677
            extends AbstractStatement
1678
            implements DeleteBuilder {
1679

    
1680
        protected GeometryExpressionBuilder where;
1681
        protected TableNameBuilder table;
1682

    
1683
        public DeleteBuilderBase() {
1684
        }
1685

    
1686
        @Override
1687
        public void accept(Visitor visitor, VisitorFilter filter) {
1688
            if (filter==null || filter.accept(this)) {
1689
                visitor.visit(this);
1690
            }
1691
            if (this.table != null) {
1692
                this.table.accept(visitor, filter);
1693
            }
1694
            if (this.has_where()) {
1695
                this.where.accept(visitor, filter);
1696
            }
1697
        }
1698

    
1699
        @Override
1700
        public GeometryExpressionBuilder where() {
1701
            if (this.where == null) {
1702
                this.where = createExpressionBuilder();
1703
            }
1704
            return this.where;
1705
        }
1706

    
1707
        @Override
1708
        public TableNameBuilder table() {
1709
            if (table == null) {
1710
                table = createTableNameBuilder();
1711
            }
1712
            return table;
1713
        }
1714

    
1715
        @Override
1716
        public boolean has_where() {
1717
            return this.where != null;
1718
        }
1719

    
1720
        @Override
1721
        public String toString() {
1722
            return this.toString(formatter());
1723
        }
1724

    
1725
        @Override
1726
        public String toString(Formatter<Value> formatter) {
1727
            if (formatter!=null && formatter.canApply(this)) {
1728
                return formatter.format(this);
1729
            }
1730
            /*
1731
             * DELETE FROM table_name
1732
             * WHERE some_column=some_value; 
1733
             */
1734
            String sql;
1735
            if (this.has_where()) {
1736
                sql = MessageFormat.format(
1737
                        STMT_DELETE_FROM_table_WHERE_expresion,
1738
                        this.table.toString(formatter),
1739
                        this.where.toString(formatter)
1740
                );
1741
            } else {
1742
                sql = MessageFormat.format(
1743
                        STMT_DELETE_FROM_table,
1744
                        this.table.toString(formatter)
1745
                );
1746
            }
1747
            return sql;
1748
        }
1749
    }
1750

    
1751
    public class CreateIndexBuilderBase
1752
            extends AbstractStatement
1753
            implements CreateIndexBuilder {
1754

    
1755
        protected boolean ifNotExist = false;
1756
        protected boolean isUnique = false;
1757
        protected String indexName;
1758
        protected boolean isSpatial = false;
1759
        protected TableNameBuilder table;
1760
        protected final List<String> columns;
1761

    
1762
        public CreateIndexBuilderBase() {
1763
            this.columns = new ArrayList<>();
1764
        }
1765

    
1766
        @Override
1767
        public CreateIndexBuilder unique() {
1768
            this.isUnique = true;
1769
            return this;
1770
        }
1771

    
1772
        @Override
1773
        public CreateIndexBuilder if_not_exist() {
1774
            this.ifNotExist = true;
1775
            return this;
1776
        }
1777

    
1778
        @Override
1779
        public CreateIndexBuilder name(String name) {
1780
            this.indexName = name;
1781
            return this;
1782
        }
1783

    
1784
        @Override
1785
        public CreateIndexBuilder spatial() {
1786
            this.isSpatial = true;
1787
            return this;
1788
        }
1789

    
1790
        @Override
1791
        public CreateIndexBuilder column(String name) {
1792
            this.columns.add(name);
1793
            return this;
1794
        }
1795

    
1796
        @Override
1797
        public TableNameBuilder table() {
1798
            if (table == null) {
1799
                table = createTableNameBuilder();
1800
            }
1801
            return table;
1802
        }
1803

    
1804
        @Override
1805
        public void accept(Visitor visitor, VisitorFilter filter) {
1806
            if (filter==null || filter.accept(this)) {
1807
                visitor.visit(this);
1808
            }
1809
            if (this.table != null) {
1810
                this.table.accept(visitor, filter);
1811
            }
1812
        }
1813

    
1814
        @Override
1815
        public String toString() {
1816
            return this.toString(formatter());
1817
        }
1818

    
1819
        @Override
1820
        public String toString(Formatter<Value> formatter) {
1821
            if (formatter!=null && formatter.canApply(this)) {
1822
                return formatter.format(this);
1823
            }
1824
            StringBuilder builder = new StringBuilder();
1825
            boolean first = true;
1826
            for (String sql : toStrings(formatter)) {
1827
                if (StringUtils.isEmpty(sql)) {
1828
                    continue;
1829
                }
1830
                if (first) {
1831
                    first = false;
1832
                } else {
1833
                    builder.append("; ");
1834
                }
1835
                builder.append(sql);
1836
            }
1837
            return builder.toString();
1838
        }
1839

    
1840
        @Override
1841
        public List<String> toStrings() {
1842
            return this.toStrings(formatter());
1843
        }
1844

    
1845
        @Override
1846
        public List<String> toStrings(Formatter formatter) {
1847
            StringBuilder builder = new StringBuilder();
1848
            builder.append("CREATE ");
1849
            if (this.isUnique) {
1850
                builder.append("UNIQUE ");
1851
            }
1852
            builder.append("INDEX ");
1853
            if (this.ifNotExist) {
1854
                builder.append("IF NOT EXISTS ");
1855
            }
1856
            builder.append(as_identifier(this.indexName));
1857
            builder.append(" ON ");
1858
            builder.append(this.table.toString(formatter));
1859
            if (this.isSpatial) {
1860
                builder.append(" USING GIST ");
1861
            }
1862
            builder.append(" ( ");
1863
            boolean is_first_column = true;
1864
            for (String column : this.columns) {
1865
                if (is_first_column) {
1866
                    is_first_column = false;
1867
                } else {
1868
                    builder.append(", ");
1869
                }
1870
                builder.append(column);
1871
            }
1872
            builder.append(" )");
1873

    
1874
            List<String> sqls = new ArrayList<>();
1875
            sqls.add(builder.toString());
1876
            return sqls;
1877
        }
1878

    
1879
    }
1880

    
1881
    public class AlterTableBuilderBase
1882
            extends AbstractStatement
1883
            implements AlterTableBuilder {
1884

    
1885
        protected TableNameBuilder table;
1886
        protected List<String> drops;
1887
        protected List<ColumnDescriptor> adds;
1888
        protected List<ColumnDescriptor> alters;
1889
        protected List<Pair<String, String>> renames;
1890

    
1891
        public AlterTableBuilderBase() {
1892
            this.drops = new ArrayList<>();
1893
            this.adds = new ArrayList<>();
1894
            this.alters = new ArrayList<>();
1895
            this.renames = new ArrayList<>();
1896
        }
1897

    
1898
        @Override
1899
        public boolean isEmpty() {
1900
            return this.drops.isEmpty()
1901
                    && this.adds.isEmpty()
1902
                    && this.alters.isEmpty()
1903
                    && this.renames.isEmpty();
1904
        }
1905

    
1906
        @Override
1907
        public void accept(Visitor visitor, VisitorFilter filter) {
1908
            if (filter==null || filter.accept(this)) {
1909
                visitor.visit(this);
1910
            }
1911
            if (this.table != null) {
1912
                this.table.accept(visitor, filter);
1913
            }
1914
        }
1915

    
1916
        @Override
1917
        public TableNameBuilder table() {
1918
            if (table == null) {
1919
                table = createTableNameBuilder();
1920
            }
1921
            return table;
1922
        }
1923

    
1924
        @Override
1925
        public AlterTableBuilder drop_column(String columnName) {
1926
            this.drops.add(columnName);
1927
            return this;
1928
        }
1929

    
1930
        @Override
1931
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1932
            this.adds.add(new ColumnDescriptorBase(fad));
1933
            return this;
1934
        }
1935

    
1936
        @Override
1937
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1938
            if (isPk || isAutomatic) {
1939
                allowNulls = false;
1940
            }
1941
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1942
            return this;
1943
        }
1944

    
1945
        @Override
1946
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1947
            if (StringUtils.isEmpty(columnName)) {
1948
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1949
            }
1950
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1951
            return this;
1952
        }
1953

    
1954
        @Override
1955
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1956
            if (StringUtils.isEmpty(columnName)) {
1957
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1958
            }
1959
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1960
            return this;
1961
        }
1962

    
1963
        @Override
1964
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1965
            this.alters.add(new ColumnDescriptorBase(fad));
1966
            return this;
1967
        }
1968

    
1969
        @Override
1970
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1971
            if (isPk || isAutomatic) {
1972
                allowNulls = false;
1973
            }
1974
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1975
            return this;
1976
        }
1977

    
1978
        @Override
1979
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1980
            if (StringUtils.isEmpty(columnName)) {
1981
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1982
            }
1983
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1984
            return this;
1985
        }
1986

    
1987
        @Override
1988
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1989
            if (StringUtils.isEmpty(columnName)) {
1990
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1991
            }
1992
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1993
            return this;
1994
        }
1995

    
1996
        @Override
1997
        public AlterTableBuilder rename_column(String source, String target) {
1998
            this.renames.add(new ImmutablePair(source, target));
1999
            return this;
2000
        }
2001

    
2002
        @Override
2003
        public String toString() {
2004
            return this.toString(formatter());
2005
        }
2006

    
2007
        @Override
2008
        public String toString(Formatter<Value> formatter) {
2009
            if (formatter!=null && formatter.canApply(this)) {
2010
                return formatter.format(this);
2011
            }
2012
            StringBuilder builder = new StringBuilder();
2013
            boolean first = true;
2014
            for (String sql : toStrings(formatter)) {
2015
                if (StringUtils.isEmpty(sql)) {
2016
                    continue;
2017
                }
2018
                if (first) {
2019
                    first = false;
2020
                } else {
2021
                    builder.append("; ");
2022
                }
2023
                builder.append(sql);
2024
            }
2025
            return builder.toString();
2026
        }
2027

    
2028
        @Override
2029
        public List<String> toStrings() {
2030
            return this.toStrings(formatter());
2031
        }
2032

    
2033
        @Override
2034
        public List<String> toStrings(Formatter formatter) {
2035
            List<String> sqls = new ArrayList<>();
2036
            if (this.isEmpty()) {
2037
                return sqls;
2038
            }
2039
            for (String column : drops) {
2040
                StringBuilder builder = new StringBuilder();
2041
                builder.append("ALTER TABLE ");
2042
                builder.append(this.table.toString(formatter));
2043
                builder.append(" DROP COLUMN IF EXISTS ");
2044
                builder.append(as_identifier(column));
2045
                sqls.add(builder.toString());
2046
            }
2047
            for (ColumnDescriptor column : adds) {
2048
                StringBuilder builder = new StringBuilder();
2049
                builder.append("ALTER TABLE ");
2050
                builder.append(this.table.toString(formatter));
2051
                builder.append(" ADD COLUMN ");
2052
                builder.append(as_identifier(column.getName()));
2053
                builder.append(" ");
2054
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2055
                    builder.append(" SERIAL");
2056
                } else {
2057
                    builder.append(
2058
                            sqltype(
2059
                                    column.getType(),
2060
                                    column.getSize(),
2061
                                    column.getPrecision(),
2062
                                    column.getScale(),
2063
                                    column.getGeometryType(),
2064
                                    column.getGeometrySubtype()
2065
                            )
2066
                    );
2067
                }
2068
                if (column.getDefaultValue() == null) {
2069
                    if (column.allowNulls()) {
2070
                        builder.append(" DEFAULT NULL");
2071
                    }
2072
                } else {
2073
                    builder.append(" DEFAULT '");
2074
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2075
                    builder.append("'");
2076
                }
2077
                if (column.allowNulls()) {
2078
                    builder.append(" NULL");
2079
                } else {
2080
                    builder.append(" NOT NULL");
2081
                }
2082
                if (column.isPrimaryKey()) {
2083
                    builder.append(" PRIMARY KEY");
2084
                }
2085
                sqls.add(builder.toString());
2086
            }
2087
            for (ColumnDescriptor column : alters) {
2088
                StringBuilder builder = new StringBuilder();
2089
                builder.append("ALTER TABLE ");
2090
                builder.append(this.table.toString(formatter));
2091
                builder.append(" ALTER COLUMN ");
2092
                builder.append(as_identifier(column.getName()));
2093
                builder.append(" SET DATA TYPE ");
2094
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2095
                    builder.append(" SERIAL");
2096
                } else {
2097
                    builder.append(
2098
                            sqltype(
2099
                                    column.getType(),
2100
                                    column.getSize(),
2101
                                    column.getPrecision(),
2102
                                    column.getScale(),
2103
                                    column.getGeometryType(),
2104
                                    column.getGeometrySubtype()
2105
                            )
2106
                    );
2107
                }
2108
                if (column.getDefaultValue() == null) {
2109
                    if (column.allowNulls()) {
2110
                        builder.append(" DEFAULT NULL");
2111
                    } else {
2112
                        builder.append(" DROP DEFAULT");
2113
                    }
2114
                } else {
2115
                    builder.append(" DEFAULT '");
2116
                    builder.append(column.getDefaultValue().toString());
2117
                    builder.append("'");
2118
                }
2119
                sqls.add(builder.toString());
2120
            }
2121
            for (Pair<String, String> pair : renames) {
2122
                StringBuilder builder = new StringBuilder();
2123
                builder.append("ALTER TABLE ");
2124
                builder.append(this.table.toString(formatter));
2125
                builder.append(" RENAME COLUMN ");
2126
                builder.append(as_identifier(pair.getLeft()));
2127
                builder.append(" TO ");
2128
                builder.append(as_identifier(pair.getRight()));
2129
                sqls.add(builder.toString());
2130
            }
2131
            return sqls;
2132
        }
2133

    
2134
    }
2135

    
2136
    public class CreateTableBuilderBase
2137
            extends AbstractStatement
2138
            implements CreateTableBuilder {
2139

    
2140
        protected TableNameBuilder table;
2141
        protected List<ColumnDescriptor> columns;
2142

    
2143
        public CreateTableBuilderBase() {
2144
            this.columns = new ArrayList<>();
2145
        }
2146

    
2147
        @Override
2148
        public void accept(Visitor visitor, VisitorFilter filter) {
2149
            if (filter==null || filter.accept(this)) {
2150
                visitor.visit(this);
2151
            }
2152
            if (this.table != null) {
2153
                this.table.accept(visitor, filter);
2154
            }
2155
        }
2156

    
2157
        @Override
2158
        public TableNameBuilder table() {
2159
            if (table == null) {
2160
                table = createTableNameBuilder();
2161
            }
2162
            return table;
2163
        }
2164

    
2165
        @Override
2166
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2167
            this.columns.add(new ColumnDescriptorBase(fad));
2168
            return this;
2169
        }
2170

    
2171
        @Override
2172
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2173
            if (StringUtils.isEmpty(columnName)) {
2174
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2175
            }
2176
            if (isPk || isAutomatic) {
2177
                allowNulls = false;
2178
            }
2179
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2180
            return this;
2181
        }
2182

    
2183
        @Override
2184
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2185
            if (StringUtils.isEmpty(columnName)) {
2186
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2187
            }
2188
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2189
            return this;
2190
        }
2191

    
2192
        @Override
2193
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2194
            if (StringUtils.isEmpty(columnName)) {
2195
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2196
            }
2197
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2198
            return this;
2199
        }
2200

    
2201
        @Override
2202
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2203
            if (StringUtils.isEmpty(columnName)) {
2204
                return null;
2205
            }
2206
            for (ColumnDescriptor column : columns) {
2207
                if (columnName.equals(column.getName())) {
2208
                    return column;
2209
                }
2210
            }
2211
            return null;
2212
        }
2213

    
2214
        @Override
2215
        public String toString() {
2216
            return this.toString(formatter());
2217
        }
2218

    
2219
        @Override
2220
        public String toString(Formatter<Value> formatter) {
2221
            if (formatter!=null && formatter.canApply(this)) {
2222
                return formatter.format(this);
2223
            }
2224
            StringBuilder builder = new StringBuilder();
2225
            boolean first = true;
2226
            for (String sql : toStrings(formatter)) {
2227
                if (StringUtils.isEmpty(sql)) {
2228
                    continue;
2229
                }
2230
                if (first) {
2231
                    first = false;
2232
                } else {
2233
                    builder.append("; ");
2234
                }
2235
                builder.append(sql);
2236
            }
2237
            return builder.toString();
2238
        }
2239

    
2240
        @Override
2241
        public List<String> toStrings() {
2242
            return this.toStrings(formatter());
2243
        }
2244

    
2245
        @Override
2246
        public List<String> toStrings(Formatter formatter) {
2247
            List<String> sqls = new ArrayList<>();
2248
            /**
2249
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2250
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2251
             * column_constraint [ ... ] ] | table_constraint | LIKE
2252
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2253
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2254
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2255
             *
2256
             * where column_constraint is:
2257
             *
2258
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2259
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2260
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2261
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2262
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2263
             *
2264
             * and table_constraint is:
2265
             *
2266
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2267
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2268
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2269
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2270
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2271
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2272
             */
2273
            StringBuilder builder = new StringBuilder();
2274

    
2275
            builder.append("CREATE TABLE ");
2276
            builder.append(this.table.toString(formatter));
2277
            builder.append(" (");
2278
            boolean first = true;
2279
            for (ColumnDescriptor column : columns) {
2280
                if (first) {
2281
                    first = false;
2282
                } else {
2283
                    builder.append(", ");
2284
                }
2285
                builder.append(as_identifier(column.getName()));
2286
                builder.append(" ");
2287
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2288
                    builder.append("SERIAL");
2289
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2290
                    builder.append("BIGSERIAL");
2291
                } else {
2292
                    builder.append(sqltype(
2293
                            column.getType(),
2294
                            column.getSize(),
2295
                            column.getPrecision(),
2296
                            column.getScale(),
2297
                            column.getGeometryType(),
2298
                            column.getGeometrySubtype()
2299
                    )
2300
                    );
2301
                }
2302
                if (column.getDefaultValue() == null) {
2303
                    if (column.allowNulls()) {
2304
                        builder.append(" DEFAULT NULL");
2305
                    }
2306
                } else {
2307
                    builder.append(" DEFAULT '");
2308
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2309
                    builder.append("'");
2310
                }
2311
                if (column.allowNulls()) {
2312
                    builder.append(" NULL");
2313
                } else {
2314
                    builder.append(" NOT NULL");
2315
                }
2316
                if (column.isPrimaryKey()) {
2317
                    builder.append(" PRIMARY KEY");
2318
                }
2319
            }
2320
            builder.append(" )");
2321
            sqls.add(builder.toString());
2322
            return sqls;
2323
        }
2324
    }
2325

    
2326
    public class InsertColumnBuilderBase
2327
            extends AbstractStatement
2328
            implements InsertColumnBuilder {
2329

    
2330
        protected Variable name;
2331
        protected Value value;
2332

    
2333
        public InsertColumnBuilderBase() {
2334
        }
2335

    
2336
        @Override
2337
        public void accept(Visitor visitor, VisitorFilter filter) {
2338
            if (filter==null || filter.accept(this)) {
2339
                visitor.visit(this);
2340
            }
2341
            if (this.name != null) {
2342
                this.name.accept(visitor, filter);
2343
            }
2344
            if (this.value != null) {
2345
                this.value.accept(visitor, filter);
2346
            }
2347
        }
2348

    
2349
        @Override
2350
        public InsertColumnBuilder name(String name) {
2351
            this.name = expression().variable(name);
2352
            return this;
2353
        }
2354

    
2355
        @Override
2356
        public InsertColumnBuilder with_value(Value value) {
2357
            this.value = value;
2358
            return this;
2359
        }
2360

    
2361
        @Override
2362
        public String getName() {
2363
            return this.name.name();
2364
        }
2365

    
2366
        @Override
2367
        public Value getValue() {
2368
            return this.value;
2369
        }
2370

    
2371
        @Override
2372
        public String toString() {
2373
            return this.toString(formatter());
2374
        }
2375

    
2376
        @Override
2377
        public String toString(Formatter<Value> formatter) {
2378
            if (formatter!=null && formatter.canApply(this)) {
2379
                return formatter.format(this);
2380
            }
2381
            return this.value.toString(formatter);
2382
        }
2383
    }
2384

    
2385
    public class InsertBuilderBase
2386
            extends AbstractStatement
2387
            implements InsertBuilder {
2388

    
2389
        protected List<InsertColumnBuilder> columns;
2390
        protected TableNameBuilder table;
2391

    
2392
        public InsertBuilderBase() {
2393
            this.columns = new ArrayList<>();
2394
        }
2395

    
2396
        @Override
2397
        public void accept(Visitor visitor, VisitorFilter filter) {
2398
            if (filter==null || filter.accept(this)) {
2399
                visitor.visit(this);
2400
            }
2401
            if (this.table != null) {
2402
                this.table.accept(visitor, filter);
2403
            }
2404
            for (InsertColumnBuilder column : columns) {
2405
                column.accept(visitor, filter);
2406
            }
2407
        }
2408

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

    
2417
        @Override
2418
        public InsertColumnBuilder column() {
2419
            InsertColumnBuilder column = createInsertColumnBuilder();
2420
            this.columns.add(column);
2421
            return column;
2422
        }
2423

    
2424
        @Override
2425
        public String toString() {
2426
            return this.toString(formatter());
2427
        }
2428

    
2429
        @Override
2430
        public String toString(Formatter<Value> formatter) {
2431
            if (formatter!=null && formatter.canApply(this)) {
2432
                return formatter.format(this);
2433
            }
2434
            /*
2435
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2436
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2437
             * output_expression [ AS output_name ] [, ...] ]
2438
             */
2439
            StringBuilder builderColumns = new StringBuilder();
2440
            StringBuilder builderValues = new StringBuilder();
2441

    
2442
            boolean first = true;
2443
            for (InsertColumnBuilder column : columns) {
2444
                if (first) {
2445
                    first = false;
2446
                } else {
2447
                    builderColumns.append(", ");
2448
                }
2449
                builderColumns.append(as_identifier(column.getName()));
2450
            }
2451
            first = true;
2452
            for (InsertColumnBuilder column : columns) {
2453
                if (first) {
2454
                    first = false;
2455
                } else {
2456
                    builderValues.append(", ");
2457
                }
2458
                builderValues.append(column.toString(formatter));
2459
            }
2460

    
2461
            String sql = MessageFormat.format(
2462
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2463
                    this.table.toString(formatter),
2464
                    builderColumns.toString(),
2465
                    builderValues.toString()
2466
            );
2467
            return sql;
2468

    
2469
        }
2470
    }
2471

    
2472
    public class UpdateTableStatisticsBuilderBase
2473
            extends AbstractStatement
2474
            implements UpdateTableStatisticsBuilder {
2475

    
2476
        protected TableNameBuilder table;
2477

    
2478
        @Override
2479
        public void accept(Visitor visitor, VisitorFilter filter) {
2480
            if (filter==null || filter.accept(this)) {
2481
                visitor.visit(this);
2482
            }
2483
            if (this.table != null) {
2484
                this.table.accept(visitor, filter);
2485
            }
2486
        }
2487

    
2488
        @Override
2489
        public TableNameBuilder table() {
2490
            if (table == null) {
2491
                table = createTableNameBuilder();
2492
            }
2493
            return table;
2494
        }
2495

    
2496
        @Override
2497
        public String toString() {
2498
            return this.toString(formatter());
2499
        }
2500

    
2501
        @Override
2502
        public String toString(Formatter<Value> formatter) {
2503
            if (formatter!=null && formatter.canApply(this)) {
2504
                return formatter.format(this);
2505
            }
2506
            StringBuilder builder = new StringBuilder();
2507
            boolean first = true;
2508
            for (String sql : toStrings(formatter)) {
2509
                if (StringUtils.isEmpty(sql)) {
2510
                    continue;
2511
                }
2512
                if (first) {
2513
                    first = false;
2514
                } else {
2515
                    builder.append("; ");
2516
                }
2517
                builder.append(sql);
2518
            }
2519
            return builder.toString();
2520
        }
2521

    
2522
        @Override
2523
        public List<String> toStrings() {
2524
            return this.toStrings(formatter());
2525
        }
2526

    
2527
        @Override
2528
        public List<String> toStrings(Formatter formatter) {
2529
            List<String> sqls = new ArrayList<>();
2530

    
2531
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2532
                String sql = MessageFormat.format(
2533
                        STMT_UPDATE_TABLE_STATISTICS_table,
2534
                        table.toString(formatter)
2535
                );
2536
                if (!StringUtils.isEmpty(sql)) {
2537
                    sqls.add(sql);
2538
                }
2539
            }
2540
            return sqls;
2541
        }
2542
    }
2543

    
2544
    protected GeometryExpressionBuilder expressionBuilder;
2545

    
2546
    protected String defaultSchema;
2547
    protected boolean supportSchemas;
2548
    protected boolean hasSpatialFunctions;
2549
    protected GeometrySupportType geometrySupportType;
2550
    protected boolean allowAutomaticValues;
2551

    
2552
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2553

    
2554
    protected String constant_true = "(1=1)";
2555
    protected String constant_false = "(1<>1)";
2556

    
2557
    protected String type_boolean = "BOOLEAN";
2558
    protected String type_byte = "TINYINT";
2559
    protected String type_bytearray = "BYTEA";
2560
    protected String type_geometry = "TEXT";
2561
    protected String type_char = "CHARACTER(1)";
2562
    protected String type_date = "DATE";
2563
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2564
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2565
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2566
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2567
    protected String type_int = "INT";
2568
    protected String type_long = "BIGINT";
2569
    protected String type_string = "TEXT";
2570
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2571
    protected String type_time = "TIME";
2572
    protected String type_timestamp = "TIMESTAMP";
2573
    protected String type_version = "VARCHAR(30)";
2574
    protected String type_URI = "TEXT";
2575
    protected String type_URL = "TEXT";
2576
    protected String type_FILE = "TEXT";
2577
    protected String type_FOLDER = "TEXT";
2578

    
2579
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2580
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2581
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2582
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2583
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2584
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2585
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2586
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2587
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2588
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2589

    
2590
    public SQLBuilderBase() {
2591
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2592

    
2593
        this.hasSpatialFunctions = false;
2594
        this.supportSchemas = true;
2595
        this.geometrySupportType = GeometrySupportType.WKT;
2596

    
2597
        this.defaultSchema = "public";
2598
        this.allowAutomaticValues = true;
2599

    
2600
    }
2601
    
2602
    @Override
2603
    public void setProperties(Class filter, final Object... values) {
2604
        this.expressionBuilder.setProperties(filter, values);
2605
        this.accept(new Visitor() {
2606
            @Override
2607
            public void visit(Visitable v) {
2608
                for (int i = 0; i < values.length; i+=2) {
2609
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2610
                }
2611
            }
2612
        }, new ClassVisitorFilter(filter) );
2613
    }
2614

    
2615
    public String quote_for_identifiers() {
2616
        return "\"";
2617
    }
2618

    
2619
    public String quote_for_strings() {
2620
        return "'";
2621
    }
2622

    
2623
    @Override
2624
    public String as_identifier(String id) {
2625
        String quote = this.quote_for_identifiers();
2626
//        No se porque no esta disponible wrapIfMissing
2627
//        return StringUtils.wrapIfMissing(id,quote);
2628
        if (id.startsWith(quote)) {
2629
            return id;
2630
        }
2631
        return quote + id + quote;
2632

    
2633
    }
2634

    
2635
    @Override
2636
    public String as_string(String s) {
2637
        String quote = this.quote_for_strings();
2638
//        No se porque no esta disponible wrapIfMissing
2639
//        return StringUtils.wrapIfMissing(id,quote);
2640
        if (s.startsWith(quote)) {
2641
            return s;
2642
        }
2643
        return quote + s + quote;
2644

    
2645
    }
2646

    
2647
    @Override
2648
    public String as_string(byte[] data) {
2649
        return this.expressionBuilder.bytearray_0x(data);
2650
//        return this.expressionBuilder.bytearray_hex(data);
2651
//        return this.expressionBuilder.bytearray_x(data);
2652
    }
2653
    
2654
    @Override
2655
    public String as_string(boolean value) {
2656
        return value? "TRUE" : "FALSE";
2657
    }
2658

    
2659
    @Override
2660
    public String as_string(Number value) {
2661
        return Objects.toString(value);
2662
    }
2663
    
2664
    @Override
2665
    public String as_string(Object value) {
2666
        if( value == null ) {
2667
            return "NULL";
2668
        }
2669
        if( value instanceof CharSequence ) {
2670
            return as_string(value.toString());
2671
        }
2672
        if( value instanceof Number ) {
2673
            return as_string((Number)value);
2674
        }
2675
        if( value instanceof Boolean ) {
2676
            return as_string((boolean)value);
2677
        }
2678
        if( value instanceof byte[] ) {
2679
            return as_string((byte[])value);
2680
        }
2681
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2682
    }
2683
    
2684
    @Override
2685
    public GeometryExpressionBuilder expression() {
2686
        return this.expressionBuilder;
2687
    }
2688

    
2689
    @Override
2690
    public boolean has_spatial_functions() {
2691
        return this.hasSpatialFunctions;
2692
    }
2693

    
2694
    @Override
2695
    public GeometrySupportType geometry_support_type() {
2696
        return this.geometrySupportType;
2697
    }
2698

    
2699
    protected GeometryExpressionBuilder createExpressionBuilder() {
2700
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2701
    }
2702

    
2703
    @Override
2704
    public Object srs_id(IProjection projection) {
2705
        String abrev = projection.getAbrev();
2706
        return abrev.split(":")[1].trim();
2707
    }
2708

    
2709
    @Override
2710
    public String default_schema() {
2711
        return this.defaultSchema;
2712
    }
2713

    
2714
    @Override
2715
    public boolean support_schemas() {
2716
        return this.supportSchemas;
2717
    }
2718

    
2719
    @Override
2720
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2721
        switch (type) {
2722
            case DataTypes.BOOLEAN:
2723
                return type_boolean;
2724
            case DataTypes.CHAR:
2725
                return type_char;
2726

    
2727

    
2728
            case DataTypes.BYTE:
2729
                return type_byte;
2730
            case DataTypes.INT:
2731
                return type_int;
2732
            case DataTypes.LONG:
2733
                return type_long;
2734

    
2735
            case DataTypes.FLOAT:
2736
                return type_float;
2737
            case DataTypes.DOUBLE:
2738
                return type_double;
2739
            case DataTypes.DECIMAL:
2740
                if (precision < 1) {
2741
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2742
                }
2743
                if (scale < 1) {
2744
                  return MessageFormat.format(type_decimal_p, precision);
2745
                }
2746
                return MessageFormat.format(type_decimal_ps, precision, scale);
2747

    
2748
                
2749
            case DataTypes.STRING:
2750
                if (size < 0) {
2751
                    return type_string;
2752
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
2753
                    return MessageFormat.format(type_string_p, size);
2754
                }
2755
                return type_string;
2756

    
2757
                
2758
            case DataTypes.DATE:
2759
                return type_date;
2760
            case DataTypes.TIME:
2761
                return type_time;
2762
            case DataTypes.TIMESTAMP:
2763
                return type_timestamp;
2764

    
2765
            case DataTypes.BYTEARRAY:
2766
                return type_bytearray;
2767

    
2768
            case DataTypes.GEOMETRY:
2769
                return type_geometry;
2770

    
2771
            case DataTypes.VERSION:
2772
                return type_version;
2773
            case DataTypes.URI:
2774
                return type_URI;
2775
            case DataTypes.URL:
2776
                return type_URL;
2777
            case DataTypes.FILE:
2778
                return type_FILE;
2779
            case DataTypes.FOLDER:
2780
                return type_FOLDER;
2781
            default:
2782
                return null;
2783
        }
2784
    }
2785

    
2786
    @Override
2787
    public Object sqlgeometrytype(int type, int subtype) {
2788
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2789
        // identificadores numericos para el tipo y otros strings.
2790
        // Por defecto vamos a devolver strings.
2791
        if (sqlgeometrytypes == null) {
2792
            sqlgeometrytypes = new HashMap<>();
2793
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2794
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2795
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2796
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2797

    
2798
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2799
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2800
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2801
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2802

    
2803
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2804
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2805
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2806
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2807

    
2808
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2809
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2810
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2811
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2812

    
2813
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2814
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2815
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2816
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2817

    
2818
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2819
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2820
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2821
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2822

    
2823
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2824
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2825
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2826
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2827

    
2828
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2829
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2830
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2831
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2832

    
2833
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2834
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2835
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2836
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2837
        }
2838
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2839
    }
2840

    
2841
    @Override
2842
    public Object sqlgeometrydimension(int type, int subtype) {
2843
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2844
        // identificadores numericos para las dimensiones y otros strings.
2845
        // Por defecto vamos a devolver enteros.
2846
        switch (subtype) {
2847
            case Geometry.SUBTYPES.GEOM3D:
2848
                return 3;
2849
            case Geometry.SUBTYPES.GEOM2DM:
2850
                return 3;
2851
            case Geometry.SUBTYPES.GEOM3DM:
2852
                return 4;
2853
            case Geometry.SUBTYPES.GEOM2D:
2854
            default:
2855
                return 2;
2856
        }
2857
    }
2858

    
2859
    @Override
2860
    public TableNameBuilder createTableNameBuilder() {
2861
        return new TableNameBuilderBase();
2862
    }
2863

    
2864
    protected SelectColumnBuilder createSelectColumnBuilder() {
2865
        return new SelectColumnBuilderBase();
2866
    }
2867

    
2868
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2869
        return new UpdateColumnBuilderBase();
2870
    }
2871

    
2872
    protected InsertColumnBuilder createInsertColumnBuilder() {
2873
        return new InsertColumnBuilderBase();
2874
    }
2875

    
2876
    protected OrderByBuilder createOrderByBuilder() {
2877
        return new OrderByBuilderBase();
2878
    }
2879

    
2880
    protected FromBuilder createFromBuilder() {
2881
        return new FromBuilderBase();
2882
    }
2883

    
2884
    protected SelectBuilder createSelectBuilder() {
2885
        return new SelectBuilderBase();
2886
    }
2887

    
2888
    protected UpdateBuilder createUpdateBuilder() {
2889
        return new UpdateBuilderBase();
2890
    }
2891

    
2892
    protected DeleteBuilder createDeleteBuilder() {
2893
        return new DeleteBuilderBase();
2894
    }
2895

    
2896
    protected GrantBuilder createGrantBuilder() {
2897
        return new GrantBuilderBase();
2898
    }
2899

    
2900
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2901
        return new GrantRoleBuilderBase(table, role);
2902
    }
2903

    
2904
    protected DropTableBuilder createDropTableBuilder() {
2905
        return new DropTableBuilderBase();
2906
    }
2907

    
2908
    protected CreateTableBuilder createCreateTableBuilder() {
2909
        return new CreateTableBuilderBase();
2910
    }
2911

    
2912
    protected AlterTableBuilder createAlterTableBuilder() {
2913
        return new AlterTableBuilderBase();
2914
    }
2915

    
2916
    protected InsertBuilder createInsertBuilder() {
2917
        return new InsertBuilderBase();
2918
    }
2919

    
2920
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2921
        return new UpdateTableStatisticsBuilderBase();
2922
    }
2923

    
2924
    protected CreateIndexBuilder createCreateIndexBuilder() {
2925
        return new CreateIndexBuilderBase();
2926
    }
2927

    
2928
    @Override
2929
    public SelectBuilder select() {
2930
        if (this.select == null) {
2931
            this.select = this.createSelectBuilder();
2932
        }
2933
        return this.select;
2934
    }
2935

    
2936
    @Override
2937
    public UpdateBuilder update() {
2938
        if (this.update == null) {
2939
            this.update = this.createUpdateBuilder();
2940
        }
2941
        return this.update;
2942
    }
2943

    
2944
    @Override
2945
    public UpdateTableStatisticsBuilder update_table_statistics() {
2946
        if (this.update_table_statistics == null) {
2947
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2948
        }
2949
        return this.update_table_statistics;
2950
    }
2951

    
2952
    @Override
2953
    public DropTableBuilder drop_table() {
2954
        if (this.drop_table == null) {
2955
            this.drop_table = this.createDropTableBuilder();
2956
        }
2957
        return this.drop_table;
2958
    }
2959

    
2960
    @Override
2961
    public CreateIndexBuilder create_index() {
2962
        if (this.create_index == null) {
2963
            this.create_index = this.createCreateIndexBuilder();
2964
        }
2965
        return this.create_index;
2966
    }
2967

    
2968
    @Override
2969
    public DeleteBuilder delete() {
2970
        if (this.delete == null) {
2971
            this.delete = this.createDeleteBuilder();
2972
        }
2973
        return this.delete;
2974
    }
2975

    
2976
    @Override
2977
    public InsertBuilder insert() {
2978
        if (this.insert == null) {
2979
            this.insert = this.createInsertBuilder();
2980
        }
2981
        return this.insert;
2982
    }
2983

    
2984
    @Override
2985
    public TableNameBuilder table_name() {
2986
        if (this.table_name == null) {
2987
            this.table_name = this.createTableNameBuilder();
2988
        }
2989
        return this.table_name;
2990
    }
2991

    
2992
    
2993
    @Override
2994
    public AlterTableBuilder alter_table() {
2995
        if (this.alter_table == null) {
2996
            this.alter_table = this.createAlterTableBuilder();
2997
        }
2998
        return this.alter_table;
2999
    }
3000

    
3001
    @Override
3002
    public CreateTableBuilder create_table() {
3003
        if (this.create_table == null) {
3004
            this.create_table = this.createCreateTableBuilder();
3005
        }
3006
        return this.create_table;
3007
    }
3008

    
3009
    @Override
3010
    public GrantBuilder grant() {
3011
        if (this.grant == null) {
3012
            this.grant = this.createGrantBuilder();
3013
        }
3014
        return this.grant;
3015
    }
3016
    
3017
    @Override
3018
    public Column column(String name) {
3019
        ColumnBase col = new ColumnBase(null, name);
3020
        return col;
3021
    }
3022

    
3023
    @Override
3024
    public Column column(TableNameBuilder table, String name) {
3025
        ColumnBase col = new ColumnBase(table, name);
3026
        return col;
3027
    }
3028
    
3029
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3030
        return new JoinBase(type, table, expression);
3031
    }
3032

    
3033
    public void accept(Visitor visitor, VisitorFilter filter) {
3034
        if (this.select != null) {
3035
            this.select.accept(visitor, filter);
3036
        }
3037
        if (this.update != null) {
3038
            this.update.accept(visitor, filter);
3039
        }
3040
        if (this.insert != null) {
3041
            this.insert.accept(visitor, filter);
3042
        }
3043
        if (this.delete != null) {
3044
            this.delete.accept(visitor, filter);
3045
        }
3046
        if (this.alter_table != null) {
3047
            this.alter_table.accept(visitor, filter);
3048
        }
3049
        if (this.create_table != null) {
3050
            this.create_table.accept(visitor, filter);
3051
        }
3052
        if (this.drop_table != null) {
3053
            this.drop_table.accept(visitor, filter);
3054
        }
3055
        if (this.table_name != null) {
3056
            this.table_name.accept(visitor, filter);
3057
        }
3058
    }
3059

    
3060
    protected Formatter formatter() {
3061
        return expression().formatter();
3062
    }
3063

    
3064
    @Override
3065
    public String toString() {
3066
        return this.toString(formatter());
3067
    }
3068

    
3069
    @Override
3070
    public String toString(Formatter formatter) {
3071
        if (this.select != null) {
3072
            return this.select.toString(formatter);
3073
        }
3074
        if (this.update != null) {
3075
            return this.update.toString(formatter);
3076
        }
3077
        if (this.insert != null) {
3078
            return this.insert.toString(formatter);
3079
        }
3080
        if (this.delete != null) {
3081
            return this.delete.toString(formatter);
3082
        }
3083
        if (this.alter_table != null) {
3084
            return this.alter_table.toString(formatter);
3085
        }
3086
        if (this.create_table != null) {
3087
            return this.create_table.toString(formatter);
3088
        }
3089
        if (this.drop_table != null) {
3090
            return this.drop_table.toString(formatter);
3091
        }
3092
        if (this.update_table_statistics != null) {
3093
            return this.update_table_statistics.toString(formatter);
3094
        }
3095
        if (this.table_name != null) {
3096
            return this.table_name.toString(formatter);
3097
        }
3098
        return "";
3099
    }
3100

    
3101
    @Override
3102
    public CountBuilder count() {
3103
        return new CountBuilderBase();
3104
    }
3105

    
3106
    @Override
3107
    public List<Parameter> parameters() {
3108
        final List<Parameter> params = new ArrayList<>();
3109
        this.accept(new Visitor() {
3110
            @Override
3111
            public void visit(Visitable value) {
3112
                params.add((Parameter) value);
3113
            }
3114
        }, new ClassVisitorFilter(Parameter.class));
3115
        return params;
3116
    }
3117

    
3118
    @Override
3119
    public List<Variable> variables() {
3120
        final List<Variable> vars = new ArrayList<>();
3121
        this.accept(new Visitor() {
3122
            @Override
3123
            public void visit(Visitable value) {
3124
                if (!vars.contains((Variable) value)) {
3125
                    vars.add((Variable) value);
3126
                }
3127
            }
3128
        }, new ClassVisitorFilter(Variable.class));
3129
        return vars;
3130
    }
3131

    
3132
    @Override
3133
    public List<String> parameters_names() {
3134
        List<String> params = new ArrayList<>();
3135
        for (Parameter param : parameters()) {
3136
            String s;
3137
            switch (param.type()) {
3138
                case PARAMETER_TYPE_CONSTANT:
3139
                    Object theValue = param.value();
3140
                    if (theValue == null) {
3141
                        s = "null";
3142
                    } else if (theValue instanceof String) {
3143
                        s = "'" + (String) theValue + "'";
3144
                    } else {
3145
                        s = theValue.toString();
3146
                    }
3147
                    break;
3148
                case PARAMETER_TYPE_VARIABLE:
3149
                default:
3150
                    s = "\"" + param.name() + "\"";
3151
            }
3152
            params.add(s);
3153
        }
3154
        return params;
3155
    }
3156

    
3157
    @Override
3158
    public List<String> variables_names() {
3159
        List<String> vars = new ArrayList<>();
3160
        for (Variable var : this.variables()) {
3161
            vars.add(var.name());
3162
        }
3163
        Collections.sort(vars);
3164
        return vars;
3165
    }    
3166
}