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

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

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

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

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

    
73
    protected abstract class AbstractStatementPart extends AbstractValue {
74

    
75
    }
76

    
77
    protected abstract class AbstractStatement extends AbstractStatementPart {
78

    
79
    }
80

    
81
    protected class ColumnDescriptorBase implements ColumnDescriptor {
82

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
320
    public class ColumnBase extends AbstractValue implements Column {
321

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

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

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

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

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

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

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

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

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

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

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

    
391
        public TableNameBuilderBase() {
392
        }
393

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

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

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

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

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

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

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

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

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

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

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

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

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

    
502
    }
503

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

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

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

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

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

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

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

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

    
561
    }
562

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

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

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

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

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

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

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

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

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

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

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

    
684
    }
685

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

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

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

    
709
        @Override
710
        public void replace(Value target, Value replacement) {
711
            if (this.name!=null ) {
712
                if( this.name == target) {
713
                    this.name = (Variable) replacement;
714
                }
715
            }
716
            if( this.value!=null ) {
717
                if (this.value == target) {
718
                    this.value = replacement;
719
                } else {
720
                    this.value.replace(target, replacement);
721
                }
722
            }
723
        }
724

    
725
        @Override
726
        public SelectColumnBuilder name(String name) {
727
            return this.name(null, name);
728
        }
729

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

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

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

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

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

    
771
        @Override
772
        public String getName() {
773
            if (this.name==null) {
774
                return null;
775
            }
776
            return this.name.name();
777
        }
778

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

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

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

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

    
830
    public class OrderByBuilderBase
831
            extends AbstractStatementPart
832
            implements OrderByBuilder {
833

    
834
        protected Value value;
835
        protected String custom;
836
        protected boolean ascending;
837

    
838
        public OrderByBuilderBase() {
839
            this.ascending = true;
840
        }
841

    
842
        @Override
843
        public void accept(Visitor visitor, VisitorFilter filter) {
844
            if (filter==null || filter.accept(this)) {
845
                visitor.visit(this);
846
            }
847
            if (this.value!=null) {
848
                this.value.accept(visitor, filter);
849
            }
850
        }
851

    
852
        @Override
853
        public OrderByBuilder column(String name) {
854
            this.value = expression().variable(name);
855
            return this;
856
        }
857
        
858
        @Override
859
        public OrderByBuilder column(Value name) {
860
            this.value = name;
861
            return this;
862
        }
863
        
864
        @Override
865
        public OrderByBuilder custom(String order) {
866
            this.custom = order;
867
            return this;
868
        }
869

    
870
        @Override
871
        public OrderByBuilder ascending() {
872
            this.ascending = true;
873
            return this;
874
        }
875

    
876
        @Override
877
        public OrderByBuilder ascending(boolean asc) {
878
            this.ascending = asc;
879
            return this;
880
        }
881

    
882
        @Override
883
        public OrderByBuilder descending() {
884
            this.ascending = false;
885
            return this;
886
        }
887

    
888
        @Override
889
        public String toString() {
890
            return this.toString(formatter());
891
        }
892

    
893
        @Override
894
        public String toString(Formatter<Value> formatter) {
895
            if (formatter!=null && formatter.canApply(this)) {
896
                return formatter.format(this);
897
            }
898
            if (!StringUtils.isEmpty(this.custom)) {
899
                return this.custom;
900
            }
901
            if (this.ascending) {
902
                return this.value.toString() + " ASC";
903
            }
904
            return this.value.toString() + " DESC";
905
        }
906
    }
907

    
908
    public class SelectBuilderBase
909
            extends AbstractStatement
910
            implements SelectBuilder {
911

    
912
        protected FromBuilder from;
913
        protected GeometryExpressionBuilder where;
914
        protected long limit = -1;
915
        protected long offset = -1;
916
        protected List<SelectColumnBuilder> columns;
917
        protected List<OrderByBuilder> order_by;
918
        protected boolean distinct;
919
        protected List<Value> groupColumn;
920
        protected boolean check_order_and_offset = true;
921

    
922
        public SelectBuilderBase() {
923
            this.columns = new ArrayList<>();
924
            this.distinct = false;
925
        }
926
        @Override
927
        public List<Value> getGroups() {
928
            return this.groupColumn;
929
        }
930
        
931
        public List<SelectColumnBuilder> getColumns() {
932
            return Collections.unmodifiableList(this.columns);
933
    }
934

    
935
        @Override
936
        public SelectBuilder group_by(Value... columns) {
937
            if( this.groupColumn==null ) {
938
                this.groupColumn = new ArrayList<>();
939
            }
940
            for (Value column : columns) {
941
                this.groupColumn.add(column);
942
            }
943
            return this;
944
        }
945

    
946
        @Override
947
        public void accept(Visitor visitor, VisitorFilter filter) {
948
            if (filter==null || filter.accept(this)) {
949
                visitor.visit(this);
950
            }
951
            for (SelectColumnBuilder column : columns) {
952
                column.accept(visitor, filter);
953
            }
954
            if (this.has_from()) {
955
                this.from.accept(visitor, filter);
956
            }
957
            if (this.has_where()) {
958
                this.where.accept(visitor, filter);
959
            }
960
            if (this.has_order_by()) {
961
                for (OrderByBuilder order : order_by) {
962
                    order.accept(visitor, filter);
963
                }
964
            }
965
            if (this.has_group_by()) {
966
                for (Value group : groupColumn) {
967
                    group.accept(visitor, filter);
968
                }
969
            }
970
        }
971

    
972
        @Override
973
        public void replace(Value target, Value replacement) {
974
            if( this.columns!=null ) {
975
                for (int i = 0; i < columns.size(); i++) {
976
                    SelectColumnBuilder column = columns.get(i);
977
                    if( column == target ) {
978
                        columns.set(i, (SelectColumnBuilder) replacement);
979
                    } else {
980
                        column.replace(target, replacement);
981
                    }
982
                }
983
            }
984
            if (this.has_from()) {
985
                if( this.from == target ) {
986
                    this.from = (FromBuilder) replacement;
987
                } else {
988
                    this.from.replace(target, replacement);
989
                }
990
            }
991
            if (this.has_where()) {
992
                if( this.where == target ) {
993
                    this.where = (GeometryExpressionBuilder) replacement;
994
                } else if( this.where.value() == target ) {
995
                    this.where.value(replacement);
996
                } else {
997
                    this.where.value().replace(target, replacement);
998
                }
999
            }
1000
            if (this.has_order_by()) {
1001
                for (int i = 0; i < order_by.size(); i++) {
1002
                    OrderByBuilder order = order_by.get(i);
1003
                    if( order == target ) {
1004
                        order_by.set(i, (OrderByBuilder) replacement);
1005
                    } else {
1006
                        order.replace(target, replacement);
1007
                    }
1008
                }
1009
            }
1010
            if (this.has_group_by()) {
1011
                for (int i = 0; i < groupColumn.size(); i++) {
1012
                    Value group = groupColumn.get(i);
1013
                    if( group == target ) {
1014
                        groupColumn.set(i, replacement);
1015
                    } else {
1016
                        group.replace(target, replacement);
1017
                    }
1018
                }
1019
            }
1020
        }
1021

    
1022
        @Override
1023
        public SelectBuilder distinct() {
1024
            this.distinct = true;
1025
            return this;
1026
        }
1027

    
1028
        @Override
1029
        public SelectColumnBuilder column() {
1030
            SelectColumnBuilder builder = createSelectColumnBuilder();
1031
            this.columns.add(builder);
1032
            return builder;
1033
        }
1034

    
1035
        @Override
1036
        public SelectBuilder remove_all_columns() {
1037
            this.columns = new ArrayList<>();
1038
            return this;
1039
        }
1040
        
1041
        @Override
1042
        public boolean has_column(String name) {
1043
            for (SelectColumnBuilder column : columns) {
1044
                if (StringUtils.equals(name, column.getName())) {
1045
                    return true;
1046
                }
1047
                if (StringUtils.equals(name, column.getAlias())) {
1048
                    return true;
1049
                }
1050
            }
1051
            return false;
1052
        }
1053

    
1054
        @Override
1055
        public FromBuilder from() {
1056
            if (this.from == null) {
1057
                this.from = createFromBuilder();
1058
            }
1059
            return this.from;
1060
        }
1061

    
1062
        @Override
1063
        public boolean has_from() {
1064
            return this.from != null;
1065
        }
1066

    
1067
        @Override
1068
        public GeometryExpressionBuilder where() {
1069
            if (this.where == null) {
1070
                this.where = createExpressionBuilder();
1071
            }
1072
            return this.where;
1073
        }
1074

    
1075
        @Override
1076
        public boolean has_where() {
1077
            if (this.where == null) {
1078
                return false;
1079
            }
1080
            return this.where.value() != null;
1081
        }
1082

    
1083
        @Override
1084
        public SelectBuilder limit(long limit) {
1085
            this.limit = limit;
1086
            return this;
1087
        }
1088

    
1089
        @Override
1090
        public SelectBuilder limit(Long limit) {
1091
            if (limit == null) {
1092
                this.limit = 0;
1093
            } else {
1094
                this.limit = limit;
1095
            }
1096
            return this;
1097
        }
1098

    
1099
        @Override
1100
        public boolean has_limit() {
1101
            return this.limit > 0;
1102
        }
1103

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

    
1110
        @Override
1111
        public boolean has_offset() {
1112
            return this.offset > 0;
1113
        }
1114

    
1115
        @Override
1116
        public OrderByBuilder order_by() {
1117
            if (this.order_by == null) {
1118
                this.order_by = new ArrayList<>();
1119
            }
1120
            OrderByBuilder order = createOrderByBuilder();
1121
            this.order_by.add(order);
1122
            return order;
1123
        }
1124

    
1125
        @Override
1126
        public boolean has_order_by() {
1127
            if (this.order_by == null) {
1128
                return false;
1129
            }
1130
            return !this.order_by.isEmpty();
1131
        }
1132
        
1133
        @Override
1134
        public boolean has_group_by() {
1135
            if (this.groupColumn == null) {
1136
                return false;
1137
            }
1138
            return !this.groupColumn.isEmpty();
1139
        }
1140
        
1141
        @Override
1142
        public void disable_check_order_and_offset() {
1143
          this.check_order_and_offset = false;
1144
        }
1145
        
1146
        protected boolean isValid(StringBuilder message) {
1147
            if (message == null) {
1148
                message = new StringBuilder();
1149
            }
1150
            if( this.check_order_and_offset ) {
1151
              if (this.has_offset() && !this.has_order_by()) {
1152
                  // Algunos gestores de BBDD requieren que se especifique un
1153
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1154
                  // asegurar que siempre tengamos los mismo resultados, lo exijimos
1155
                  // siempre.
1156
                  message.append("Can't use OFFSET without an ORDER BY.");
1157
                  return false;
1158
              }
1159
            }
1160
            return true;
1161
        }
1162

    
1163
        @Override
1164
        public String toString() {
1165
            return this.toString(formatter());
1166
        }
1167

    
1168
        @Override
1169
        public String toString(Formatter<Value> formatter) {
1170
            if (formatter!=null && formatter.canApply(this)) {
1171
                return formatter.format(this);
1172
            }
1173
            StringBuilder builder = new StringBuilder();
1174
            if (!this.isValid(builder)) {
1175
                throw new IllegalStateException(builder.toString());
1176
            }
1177
            builder.append("SELECT ");
1178
            if (this.distinct) {
1179
                builder.append("DISTINCT ");
1180
            }
1181
            boolean first = true;
1182
            for (SelectColumnBuilder column : columns) {
1183
                if (first) {
1184
                    first = false;
1185
                } else {
1186
                    builder.append(", ");
1187
                }
1188
                builder.append(column.toString(formatter));
1189
            }
1190

    
1191
            if (this.has_from()) {
1192
                builder.append(" FROM ");
1193
                builder.append(this.from.toString(formatter));
1194
            }
1195
            if (this.has_where()) {
1196
                builder.append(" WHERE ");
1197
                builder.append(this.where.toString(formatter));
1198
            }
1199
            if( this.has_group_by() ) {
1200
                builder.append(" GROUP BY ");
1201
                builder.append(this.groupColumn.get(0).toString(formatter));
1202
                for (int i = 1; i < groupColumn.size(); i++) {
1203
                    builder.append(", ");
1204
                    builder.append(this.groupColumn.get(i).toString(formatter));
1205
                }
1206
            }
1207
            if (this.has_order_by()) {
1208
                builder.append(" ORDER BY ");
1209
                first = true;
1210
                for (OrderByBuilder item : this.order_by) {
1211
                    if (first) {
1212
                        first = false;
1213
                    } else {
1214
                        builder.append(", ");
1215
                    }
1216
                    builder.append(item.toString(formatter));
1217
                }
1218
            }
1219

    
1220
            if (this.has_limit()) {
1221
                builder.append(" LIMIT ");
1222
                builder.append(this.limit);
1223
            }
1224
            if (this.has_offset()) {
1225
                builder.append(" OFFSET ");
1226
                builder.append(this.offset);
1227
            }
1228
            return builder.toString();
1229

    
1230
        }
1231
    }
1232

    
1233
    public class DropTableBuilderBase
1234
            extends AbstractStatement
1235
            implements DropTableBuilder {
1236

    
1237
        protected TableNameBuilder table;
1238

    
1239
        @Override
1240
        public TableNameBuilder table() {
1241
            if (table == null) {
1242
                table = createTableNameBuilder();
1243
            }
1244
            return table;
1245
        }
1246

    
1247
        @Override
1248
        public void accept(Visitor visitor, VisitorFilter filter) {
1249
            if (filter==null || filter.accept(this)) {
1250
                visitor.visit(this);
1251
            }
1252
            this.table.accept(visitor, filter);
1253
        }
1254

    
1255
        @Override
1256
        public String toString() {
1257
            return this.toString(formatter());
1258
        }
1259

    
1260
        @Override
1261
        public String toString(Formatter<Value> formatter) {
1262
            if (formatter!=null && formatter.canApply(this)) {
1263
                return formatter.format(this);
1264
            }
1265
            StringBuilder builder = new StringBuilder();
1266
            boolean first = true;
1267
            for (String sql : toStrings(formatter)) {
1268
                if (StringUtils.isEmpty(sql)) {
1269
                    continue;
1270
                }
1271
                if (first) {
1272
                    first = false;
1273
                } else {
1274
                    builder.append("; ");
1275
                }
1276
                builder.append(sql);
1277
            }
1278
            return builder.toString();
1279
        }
1280

    
1281
        @Override
1282
        public List<String> toStrings() {
1283
            return this.toStrings(formatter());
1284
        }
1285

    
1286
        @Override
1287
        public List<String> toStrings(Formatter formatter) {
1288
            List<String> sqls = new ArrayList<>();
1289

    
1290
            sqls.add(
1291
                    MessageFormat.format(
1292
                            STMT_DROP_TABLE_table,
1293
                            this.table.toString(formatter)
1294
                    )
1295
            );
1296
            String sql;
1297
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1298
                if (this.table.has_schema()) {
1299
                    sql = MessageFormat.format(
1300
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1301
                            as_string(this.table.getSchema()),
1302
                            as_string(this.table.getName())
1303
                    );
1304
                } else {
1305
                    sql = MessageFormat.format(
1306
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1307
                            as_identifier(this.table.getName())
1308
                    );
1309
                }
1310
                if (!StringUtils.isEmpty(sql)) {
1311
                    sqls.add(sql);
1312
                }
1313
            }
1314
            return sqls;
1315
        }
1316
    }
1317

    
1318
    public class GrantRoleBuilderBase
1319
            extends AbstractStatementPart
1320
            implements GrantRoleBuilder {
1321

    
1322
        protected TableNameBuilder table;
1323
        protected String role;
1324
        protected Set<Privilege> privileges;
1325

    
1326
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1327
            this.table = table;
1328
            this.role = role;
1329
            this.privileges = new HashSet<>();
1330
        }
1331

    
1332
        @Override
1333
        public GrantRoleBuilder privilege(Privilege privilege) {
1334
            privileges.add(privilege);
1335
            return this;
1336
        }
1337

    
1338
        @Override
1339
        public GrantRoleBuilder select() {
1340
            privileges.add(Privilege.SELECT);
1341
            return this;
1342
        }
1343

    
1344
        @Override
1345
        public GrantRoleBuilder update() {
1346
            privileges.add(Privilege.UPDATE);
1347
            return this;
1348
        }
1349

    
1350
        @Override
1351
        public GrantRoleBuilder insert() {
1352
            privileges.add(Privilege.INSERT);
1353
            return this;
1354
        }
1355

    
1356
        @Override
1357
        public GrantRoleBuilder delete() {
1358
            privileges.add(Privilege.DELETE);
1359
            return this;
1360
        }
1361

    
1362
        @Override
1363
        public GrantRoleBuilder truncate() {
1364
            privileges.add(Privilege.TRUNCATE);
1365
            return this;
1366
        }
1367

    
1368
        @Override
1369
        public GrantRoleBuilder reference() {
1370
            privileges.add(Privilege.REFERENCE);
1371
            return this;
1372
        }
1373

    
1374
        @Override
1375
        public GrantRoleBuilder trigger() {
1376
            privileges.add(Privilege.TRIGGER);
1377
            return this;
1378
        }
1379

    
1380
        @Override
1381
        public GrantRoleBuilder all() {
1382
            privileges.add(Privilege.ALL);
1383
            return this;
1384
        }
1385

    
1386
        protected String getPrivilegeName(Privilege privilege) {
1387
            switch (privilege) {
1388
                case DELETE:
1389
                    return "DELETE";
1390
                case INSERT:
1391
                    return "INSERT";
1392
                case REFERENCE:
1393
                    return "REFERENCE";
1394
                case SELECT:
1395
                    return "SELECT";
1396
                case TRIGGER:
1397
                    return "TRIGGER";
1398
                case TRUNCATE:
1399
                    return "TRUNCATE";
1400
                case UPDATE:
1401
                    return "UPDATE";
1402
                case ALL:
1403
                default:
1404
                    return "ALL";
1405
            }
1406
        }
1407

    
1408
        @Override
1409
        public String toString() {
1410
            return this.toString(formatter());
1411
        }
1412

    
1413
        @Override
1414
        public String toString(Formatter<Value> formatter) {
1415
            if (formatter!=null && formatter.canApply(this)) {
1416
                return formatter.format(this);
1417
            }
1418
            StringBuilder builder = new StringBuilder();
1419
            boolean first = true;
1420
            for (Privilege privilege : privileges) {
1421
                if (first) {
1422
                    first = false;
1423
                } else {
1424
                    builder.append(", ");
1425
                }
1426
                builder.append(this.getPrivilegeName(privilege));
1427
            }
1428
            String sql = MessageFormat.format(
1429
                    STMT_GRANT_privileges_ON_table_TO_role,
1430
                    builder.toString(),
1431
                    table.toString(formatter),
1432
                    role
1433
            );
1434
            return sql;
1435
        }
1436
    }
1437

    
1438
    public class GrantBuilderBase
1439
            extends AbstractStatement
1440
            implements GrantBuilder {
1441

    
1442
        protected TableNameBuilder table;
1443
        protected Map<String, GrantRoleBuilder> roles;
1444

    
1445
        public GrantBuilderBase() {
1446
            this.roles = new HashMap<>();
1447
        }
1448

    
1449
        @Override
1450
        public TableNameBuilder table() {
1451
            if (table == null) {
1452
                table = createTableNameBuilder();
1453
            }
1454
            return table;
1455
        }
1456

    
1457
        @Override
1458
        public void accept(Visitor visitor, VisitorFilter filter) {
1459
            if (filter==null || filter.accept(this)) {
1460
                visitor.visit(this);
1461
            }
1462
            if (this.table != null) {
1463
                this.table.accept(visitor, filter);
1464
            }
1465
        }
1466

    
1467
        @Override
1468
        public GrantRoleBuilder role(String role) {
1469
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1470
            if (roleBuilder == null) {
1471
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1472
                this.roles.put(role, roleBuilder);
1473
            }
1474
            return roleBuilder;
1475
        }
1476

    
1477
        @Override
1478
        public String toString() {
1479
            return this.toString(formatter());
1480
        }
1481

    
1482
        @Override
1483
        public String toString(Formatter<Value> formatter) {
1484
            if (formatter!=null && formatter.canApply(this)) {
1485
                return formatter.format(this);
1486
            }
1487
            StringBuilder builder = new StringBuilder();
1488
            boolean first = true;
1489
            for (String sql : toStrings(formatter)) {
1490
                if (StringUtils.isEmpty(sql)) {
1491
                    continue;
1492
                }
1493
                if (first) {
1494
                    first = false;
1495
                } else {
1496
                    builder.append("; ");
1497
                }
1498
                builder.append(sql);
1499
            }
1500
            return builder.toString();
1501
        }
1502

    
1503
        @Override
1504
        public List<String> toStrings() {
1505
            return this.toStrings(formatter());
1506
        }
1507

    
1508
        @Override
1509
        public List<String> toStrings(Formatter formatter) {
1510
            List<String> sqls = new ArrayList<>();
1511
            for (GrantRoleBuilder role : roles.values()) {
1512
                sqls.add(role.toString(formatter));
1513
            }
1514
            return sqls;
1515
        }
1516
    }
1517

    
1518
    public class UpdateColumnBuilderBase
1519
            extends InsertColumnBuilderBase
1520
            implements UpdateColumnBuilder {
1521

    
1522
        public UpdateColumnBuilderBase() {
1523
            super();
1524
        }
1525

    
1526
        @Override
1527
        public UpdateColumnBuilder name(String name) {
1528
            return (UpdateColumnBuilder) super.name(name);
1529
        }
1530

    
1531
        @Override
1532
        public UpdateColumnBuilder with_value(Value value) {
1533
            return (UpdateColumnBuilder) super.with_value(value);
1534
        }
1535

    
1536
    }
1537

    
1538
    public class UpdateBuilderBase
1539
            extends AbstractStatement
1540
            implements UpdateBuilder {
1541

    
1542
        protected GeometryExpressionBuilder where;
1543
        protected List<UpdateColumnBuilder> columns;
1544
        protected TableNameBuilder table;
1545

    
1546
        public UpdateBuilderBase() {
1547
            this.columns = new ArrayList<>();
1548
        }
1549

    
1550
        @Override
1551
        public void accept(Visitor visitor, VisitorFilter filter) {
1552
            if (filter==null || filter.accept(this)) {
1553
                visitor.visit(this);
1554
            }
1555
            if (this.table != null) {
1556
                this.table.accept(visitor, filter);
1557
            }
1558
            for (UpdateColumnBuilder column : columns) {
1559
                column.accept(visitor, filter);
1560
            }
1561
            if (this.has_where()) {
1562
                this.where.accept(visitor, filter);
1563
            }
1564
        }
1565

    
1566
        @Override
1567
        public GeometryExpressionBuilder where() {
1568
            if (this.where == null) {
1569
                this.where = createExpressionBuilder();
1570
            }
1571
            return this.where;
1572
        }
1573

    
1574
        @Override
1575
        public TableNameBuilder table() {
1576
            if (table == null) {
1577
                table = createTableNameBuilder();
1578
            }
1579
            return table;
1580
        }
1581

    
1582
        @Override
1583
        public UpdateColumnBuilder column() {
1584
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1585
            this.columns.add(column);
1586
            return column;
1587
        }
1588

    
1589
        @Override
1590
        public boolean has_where() {
1591
            return this.where != null;
1592
        }
1593

    
1594
        @Override
1595
        public String toString() {
1596
            return this.toString(formatter());
1597
        }
1598

    
1599
        @Override
1600
        public String toString(Formatter<Value> formatter) {
1601
            if (formatter!=null && formatter.canApply(this)) {
1602
                return formatter.format(this);
1603
            }
1604
            /*
1605
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1606
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1607
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1608
             * output_expression [ AS output_name ] [, ...] ]
1609
             */
1610
            StringBuilder columnsAndValues = new StringBuilder();
1611

    
1612
            boolean first = true;
1613
            for (UpdateColumnBuilder column : columns) {
1614
                if (first) {
1615
                    first = false;
1616
                } else {
1617
                    columnsAndValues.append(", ");
1618
                }
1619
                columnsAndValues.append(as_identifier(column.getName()));
1620
                columnsAndValues.append(" = ");
1621
                columnsAndValues.append(column.getValue().toString(formatter));
1622
            }
1623

    
1624
            String sql;
1625
            if (this.has_where()) {
1626
                sql = MessageFormat.format(
1627
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1628
                        this.table.toString(formatter),
1629
                        columnsAndValues.toString(),
1630
                        this.where.toString(formatter)
1631
                );
1632
            } else {
1633
                sql = MessageFormat.format(
1634
                        STMT_UPDATE_table_SET_columnsAndValues,
1635
                        this.table.toString(formatter),
1636
                        columnsAndValues.toString()
1637
                );
1638
            }
1639
            return sql;
1640
        }
1641
    }
1642

    
1643
    public class DeleteBuilderBase
1644
            extends AbstractStatement
1645
            implements DeleteBuilder {
1646

    
1647
        protected GeometryExpressionBuilder where;
1648
        protected TableNameBuilder table;
1649

    
1650
        public DeleteBuilderBase() {
1651
        }
1652

    
1653
        @Override
1654
        public void accept(Visitor visitor, VisitorFilter filter) {
1655
            if (filter==null || filter.accept(this)) {
1656
                visitor.visit(this);
1657
            }
1658
            if (this.table != null) {
1659
                this.table.accept(visitor, filter);
1660
            }
1661
            if (this.has_where()) {
1662
                this.where.accept(visitor, filter);
1663
            }
1664
        }
1665

    
1666
        @Override
1667
        public GeometryExpressionBuilder where() {
1668
            if (this.where == null) {
1669
                this.where = createExpressionBuilder();
1670
            }
1671
            return this.where;
1672
        }
1673

    
1674
        @Override
1675
        public TableNameBuilder table() {
1676
            if (table == null) {
1677
                table = createTableNameBuilder();
1678
            }
1679
            return table;
1680
        }
1681

    
1682
        @Override
1683
        public boolean has_where() {
1684
            return this.where != null;
1685
        }
1686

    
1687
        @Override
1688
        public String toString() {
1689
            return this.toString(formatter());
1690
        }
1691

    
1692
        @Override
1693
        public String toString(Formatter<Value> formatter) {
1694
            if (formatter!=null && formatter.canApply(this)) {
1695
                return formatter.format(this);
1696
            }
1697
            /*
1698
             * DELETE FROM table_name
1699
             * WHERE some_column=some_value; 
1700
             */
1701
            String sql;
1702
            if (this.has_where()) {
1703
                sql = MessageFormat.format(
1704
                        STMT_DELETE_FROM_table_WHERE_expresion,
1705
                        this.table.toString(formatter),
1706
                        this.where.toString(formatter)
1707
                );
1708
            } else {
1709
                sql = MessageFormat.format(
1710
                        STMT_DELETE_FROM_table,
1711
                        this.table.toString(formatter)
1712
                );
1713
            }
1714
            return sql;
1715
        }
1716
    }
1717

    
1718
    public class CreateIndexBuilderBase
1719
            extends AbstractStatement
1720
            implements CreateIndexBuilder {
1721

    
1722
        protected boolean ifNotExist = false;
1723
        protected boolean isUnique = false;
1724
        protected String indexName;
1725
        protected boolean isSpatial = false;
1726
        protected TableNameBuilder table;
1727
        protected final List<String> columns;
1728

    
1729
        public CreateIndexBuilderBase() {
1730
            this.columns = new ArrayList<>();
1731
        }
1732

    
1733
        @Override
1734
        public CreateIndexBuilder unique() {
1735
            this.isUnique = true;
1736
            return this;
1737
        }
1738

    
1739
        @Override
1740
        public CreateIndexBuilder if_not_exist() {
1741
            this.ifNotExist = true;
1742
            return this;
1743
        }
1744

    
1745
        @Override
1746
        public CreateIndexBuilder name(String name) {
1747
            this.indexName = name;
1748
            return this;
1749
        }
1750

    
1751
        @Override
1752
        public CreateIndexBuilder spatial() {
1753
            this.isSpatial = true;
1754
            return this;
1755
        }
1756

    
1757
        @Override
1758
        public CreateIndexBuilder column(String name) {
1759
            this.columns.add(name);
1760
            return this;
1761
        }
1762

    
1763
        @Override
1764
        public TableNameBuilder table() {
1765
            if (table == null) {
1766
                table = createTableNameBuilder();
1767
            }
1768
            return table;
1769
        }
1770

    
1771
        @Override
1772
        public void accept(Visitor visitor, VisitorFilter filter) {
1773
            if (filter==null || filter.accept(this)) {
1774
                visitor.visit(this);
1775
            }
1776
            if (this.table != null) {
1777
                this.table.accept(visitor, filter);
1778
            }
1779
        }
1780

    
1781
        @Override
1782
        public String toString() {
1783
            return this.toString(formatter());
1784
        }
1785

    
1786
        @Override
1787
        public String toString(Formatter<Value> formatter) {
1788
            if (formatter!=null && formatter.canApply(this)) {
1789
                return formatter.format(this);
1790
            }
1791
            StringBuilder builder = new StringBuilder();
1792
            boolean first = true;
1793
            for (String sql : toStrings(formatter)) {
1794
                if (StringUtils.isEmpty(sql)) {
1795
                    continue;
1796
                }
1797
                if (first) {
1798
                    first = false;
1799
                } else {
1800
                    builder.append("; ");
1801
                }
1802
                builder.append(sql);
1803
            }
1804
            return builder.toString();
1805
        }
1806

    
1807
        @Override
1808
        public List<String> toStrings() {
1809
            return this.toStrings(formatter());
1810
        }
1811

    
1812
        @Override
1813
        public List<String> toStrings(Formatter formatter) {
1814
            StringBuilder builder = new StringBuilder();
1815
            builder.append("CREATE ");
1816
            if (this.isUnique) {
1817
                builder.append("UNIQUE ");
1818
            }
1819
            builder.append("INDEX ");
1820
            if (this.ifNotExist) {
1821
                builder.append("IF NOT EXISTS ");
1822
            }
1823
            builder.append(as_identifier(this.indexName));
1824
            builder.append(" ON ");
1825
            builder.append(this.table.toString(formatter));
1826
            if (this.isSpatial) {
1827
                builder.append(" USING GIST ");
1828
            }
1829
            builder.append(" ( ");
1830
            boolean is_first_column = true;
1831
            for (String column : this.columns) {
1832
                if (is_first_column) {
1833
                    is_first_column = false;
1834
                } else {
1835
                    builder.append(", ");
1836
                }
1837
                builder.append(column);
1838
            }
1839
            builder.append(" )");
1840

    
1841
            List<String> sqls = new ArrayList<>();
1842
            sqls.add(builder.toString());
1843
            return sqls;
1844
        }
1845

    
1846
    }
1847

    
1848
    public class AlterTableBuilderBase
1849
            extends AbstractStatement
1850
            implements AlterTableBuilder {
1851

    
1852
        protected TableNameBuilder table;
1853
        protected List<String> drops;
1854
        protected List<ColumnDescriptor> adds;
1855
        protected List<ColumnDescriptor> alters;
1856
        protected List<Pair<String, String>> renames;
1857

    
1858
        public AlterTableBuilderBase() {
1859
            this.drops = new ArrayList<>();
1860
            this.adds = new ArrayList<>();
1861
            this.alters = new ArrayList<>();
1862
            this.renames = new ArrayList<>();
1863
        }
1864

    
1865
        @Override
1866
        public boolean isEmpty() {
1867
            return this.drops.isEmpty()
1868
                    && this.adds.isEmpty()
1869
                    && this.alters.isEmpty()
1870
                    && this.renames.isEmpty();
1871
        }
1872

    
1873
        @Override
1874
        public void accept(Visitor visitor, VisitorFilter filter) {
1875
            if (filter==null || filter.accept(this)) {
1876
                visitor.visit(this);
1877
            }
1878
            if (this.table != null) {
1879
                this.table.accept(visitor, filter);
1880
            }
1881
        }
1882

    
1883
        @Override
1884
        public TableNameBuilder table() {
1885
            if (table == null) {
1886
                table = createTableNameBuilder();
1887
            }
1888
            return table;
1889
        }
1890

    
1891
        @Override
1892
        public AlterTableBuilder drop_column(String columnName) {
1893
            this.drops.add(columnName);
1894
            return this;
1895
        }
1896

    
1897
        @Override
1898
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1899
            this.adds.add(new ColumnDescriptorBase(fad));
1900
            return this;
1901
        }
1902

    
1903
        @Override
1904
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1905
            if (isPk || isAutomatic) {
1906
                allowNulls = false;
1907
            }
1908
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1909
            return this;
1910
        }
1911

    
1912
        @Override
1913
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1914
            if (StringUtils.isEmpty(columnName)) {
1915
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1916
            }
1917
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1918
            return this;
1919
        }
1920

    
1921
        @Override
1922
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1923
            if (StringUtils.isEmpty(columnName)) {
1924
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1925
            }
1926
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1927
            return this;
1928
        }
1929

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

    
1936
        @Override
1937
        public AlterTableBuilder alter_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.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1942
            return this;
1943
        }
1944

    
1945
        @Override
1946
        public AlterTableBuilder alter_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.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1951
            return this;
1952
        }
1953

    
1954
        @Override
1955
        public AlterTableBuilder alter_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.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1960
            return this;
1961
        }
1962

    
1963
        @Override
1964
        public AlterTableBuilder rename_column(String source, String target) {
1965
            this.renames.add(new ImmutablePair(source, target));
1966
            return this;
1967
        }
1968

    
1969
        @Override
1970
        public String toString() {
1971
            return this.toString(formatter());
1972
        }
1973

    
1974
        @Override
1975
        public String toString(Formatter<Value> formatter) {
1976
            if (formatter!=null && formatter.canApply(this)) {
1977
                return formatter.format(this);
1978
            }
1979
            StringBuilder builder = new StringBuilder();
1980
            boolean first = true;
1981
            for (String sql : toStrings(formatter)) {
1982
                if (StringUtils.isEmpty(sql)) {
1983
                    continue;
1984
                }
1985
                if (first) {
1986
                    first = false;
1987
                } else {
1988
                    builder.append("; ");
1989
                }
1990
                builder.append(sql);
1991
            }
1992
            return builder.toString();
1993
        }
1994

    
1995
        @Override
1996
        public List<String> toStrings() {
1997
            return this.toStrings(formatter());
1998
        }
1999

    
2000
        @Override
2001
        public List<String> toStrings(Formatter formatter) {
2002
            List<String> sqls = new ArrayList<>();
2003
            if (this.isEmpty()) {
2004
                return sqls;
2005
            }
2006
            for (String column : drops) {
2007
                StringBuilder builder = new StringBuilder();
2008
                builder.append("ALTER TABLE ");
2009
                builder.append(this.table.toString(formatter));
2010
                builder.append(" DROP COLUMN IF EXISTS ");
2011
                builder.append(as_identifier(column));
2012
                sqls.add(builder.toString());
2013
            }
2014
            for (ColumnDescriptor column : adds) {
2015
                StringBuilder builder = new StringBuilder();
2016
                builder.append("ALTER TABLE ");
2017
                builder.append(this.table.toString(formatter));
2018
                builder.append(" ADD COLUMN ");
2019
                builder.append(as_identifier(column.getName()));
2020
                builder.append(" ");
2021
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2022
                    builder.append(" SERIAL");
2023
                } else {
2024
                    builder.append(
2025
                            sqltype(
2026
                                    column.getType(),
2027
                                    column.getSize(),
2028
                                    column.getPrecision(),
2029
                                    column.getScale(),
2030
                                    column.getGeometryType(),
2031
                                    column.getGeometrySubtype()
2032
                            )
2033
                    );
2034
                }
2035
                if (column.getDefaultValue() == null) {
2036
                    if (column.allowNulls()) {
2037
                        builder.append(" DEFAULT NULL");
2038
                    }
2039
                } else {
2040
                    builder.append(" DEFAULT '");
2041
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2042
                    builder.append("'");
2043
                }
2044
                if (column.allowNulls()) {
2045
                    builder.append(" NULL");
2046
                } else {
2047
                    builder.append(" NOT NULL");
2048
                }
2049
                if (column.isPrimaryKey()) {
2050
                    builder.append(" PRIMARY KEY");
2051
                }
2052
                sqls.add(builder.toString());
2053
            }
2054
            for (ColumnDescriptor column : alters) {
2055
                StringBuilder builder = new StringBuilder();
2056
                builder.append("ALTER TABLE ");
2057
                builder.append(this.table.toString(formatter));
2058
                builder.append(" ALTER COLUMN ");
2059
                builder.append(as_identifier(column.getName()));
2060
                builder.append(" SET DATA TYPE ");
2061
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2062
                    builder.append(" SERIAL");
2063
                } else {
2064
                    builder.append(
2065
                            sqltype(
2066
                                    column.getType(),
2067
                                    column.getSize(),
2068
                                    column.getPrecision(),
2069
                                    column.getScale(),
2070
                                    column.getGeometryType(),
2071
                                    column.getGeometrySubtype()
2072
                            )
2073
                    );
2074
                }
2075
                if (column.getDefaultValue() == null) {
2076
                    if (column.allowNulls()) {
2077
                        builder.append(" DEFAULT NULL");
2078
                    } else {
2079
                        builder.append(" DROP DEFAULT");
2080
                    }
2081
                } else {
2082
                    builder.append(" DEFAULT '");
2083
                    builder.append(column.getDefaultValue().toString());
2084
                    builder.append("'");
2085
                }
2086
                sqls.add(builder.toString());
2087
            }
2088
            for (Pair<String, String> pair : renames) {
2089
                StringBuilder builder = new StringBuilder();
2090
                builder.append("ALTER TABLE ");
2091
                builder.append(this.table.toString(formatter));
2092
                builder.append(" RENAME COLUMN ");
2093
                builder.append(as_identifier(pair.getLeft()));
2094
                builder.append(" TO ");
2095
                builder.append(as_identifier(pair.getRight()));
2096
                sqls.add(builder.toString());
2097
            }
2098
            return sqls;
2099
        }
2100

    
2101
    }
2102

    
2103
    public class CreateTableBuilderBase
2104
            extends AbstractStatement
2105
            implements CreateTableBuilder {
2106

    
2107
        protected TableNameBuilder table;
2108
        protected List<ColumnDescriptor> columns;
2109

    
2110
        public CreateTableBuilderBase() {
2111
            this.columns = new ArrayList<>();
2112
        }
2113

    
2114
        @Override
2115
        public void accept(Visitor visitor, VisitorFilter filter) {
2116
            if (filter==null || filter.accept(this)) {
2117
                visitor.visit(this);
2118
            }
2119
            if (this.table != null) {
2120
                this.table.accept(visitor, filter);
2121
            }
2122
        }
2123

    
2124
        @Override
2125
        public TableNameBuilder table() {
2126
            if (table == null) {
2127
                table = createTableNameBuilder();
2128
            }
2129
            return table;
2130
        }
2131

    
2132
        @Override
2133
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2134
            this.columns.add(new ColumnDescriptorBase(fad));
2135
            return this;
2136
        }
2137

    
2138
        @Override
2139
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2140
            if (StringUtils.isEmpty(columnName)) {
2141
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2142
            }
2143
            if (isPk || isAutomatic) {
2144
                allowNulls = false;
2145
            }
2146
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2147
            return this;
2148
        }
2149

    
2150
        @Override
2151
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2152
            if (StringUtils.isEmpty(columnName)) {
2153
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2154
            }
2155
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2156
            return this;
2157
        }
2158

    
2159
        @Override
2160
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2161
            if (StringUtils.isEmpty(columnName)) {
2162
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2163
            }
2164
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2165
            return this;
2166
        }
2167

    
2168
        @Override
2169
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2170
            if (StringUtils.isEmpty(columnName)) {
2171
                return null;
2172
            }
2173
            for (ColumnDescriptor column : columns) {
2174
                if (columnName.equals(column.getName())) {
2175
                    return column;
2176
                }
2177
            }
2178
            return null;
2179
        }
2180

    
2181
        @Override
2182
        public String toString() {
2183
            return this.toString(formatter());
2184
        }
2185

    
2186
        @Override
2187
        public String toString(Formatter<Value> formatter) {
2188
            if (formatter!=null && formatter.canApply(this)) {
2189
                return formatter.format(this);
2190
            }
2191
            StringBuilder builder = new StringBuilder();
2192
            boolean first = true;
2193
            for (String sql : toStrings(formatter)) {
2194
                if (StringUtils.isEmpty(sql)) {
2195
                    continue;
2196
                }
2197
                if (first) {
2198
                    first = false;
2199
                } else {
2200
                    builder.append("; ");
2201
                }
2202
                builder.append(sql);
2203
            }
2204
            return builder.toString();
2205
        }
2206

    
2207
        @Override
2208
        public List<String> toStrings() {
2209
            return this.toStrings(formatter());
2210
        }
2211

    
2212
        @Override
2213
        public List<String> toStrings(Formatter formatter) {
2214
            List<String> sqls = new ArrayList<>();
2215
            /**
2216
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2217
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2218
             * column_constraint [ ... ] ] | table_constraint | LIKE
2219
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2220
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2221
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2222
             *
2223
             * where column_constraint is:
2224
             *
2225
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2226
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2227
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2228
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2229
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2230
             *
2231
             * and table_constraint is:
2232
             *
2233
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2234
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2235
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2236
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2237
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2238
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2239
             */
2240
            StringBuilder builder = new StringBuilder();
2241

    
2242
            builder.append("CREATE TABLE ");
2243
            builder.append(this.table.toString(formatter));
2244
            builder.append(" (");
2245
            boolean first = true;
2246
            for (ColumnDescriptor column : columns) {
2247
                if (first) {
2248
                    first = false;
2249
                } else {
2250
                    builder.append(", ");
2251
                }
2252
                builder.append(as_identifier(column.getName()));
2253
                builder.append(" ");
2254
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2255
                    builder.append("SERIAL");
2256
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2257
                    builder.append("BIGSERIAL");
2258
                } else {
2259
                    builder.append(sqltype(
2260
                            column.getType(),
2261
                            column.getSize(),
2262
                            column.getPrecision(),
2263
                            column.getScale(),
2264
                            column.getGeometryType(),
2265
                            column.getGeometrySubtype()
2266
                    )
2267
                    );
2268
                }
2269
                if (column.getDefaultValue() == null) {
2270
                    if (column.allowNulls()) {
2271
                        builder.append(" DEFAULT NULL");
2272
                    }
2273
                } else {
2274
                    builder.append(" DEFAULT '");
2275
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2276
                    builder.append("'");
2277
                }
2278
                if (column.allowNulls()) {
2279
                    builder.append(" NULL");
2280
                } else {
2281
                    builder.append(" NOT NULL");
2282
                }
2283
                if (column.isPrimaryKey()) {
2284
                    builder.append(" PRIMARY KEY");
2285
                }
2286
            }
2287
            builder.append(" )");
2288
            sqls.add(builder.toString());
2289
            return sqls;
2290
        }
2291
    }
2292

    
2293
    public class InsertColumnBuilderBase
2294
            extends AbstractStatement
2295
            implements InsertColumnBuilder {
2296

    
2297
        protected Variable name;
2298
        protected Value value;
2299

    
2300
        public InsertColumnBuilderBase() {
2301
        }
2302

    
2303
        @Override
2304
        public void accept(Visitor visitor, VisitorFilter filter) {
2305
            if (filter==null || filter.accept(this)) {
2306
                visitor.visit(this);
2307
            }
2308
            if (this.name != null) {
2309
                this.name.accept(visitor, filter);
2310
            }
2311
            if (this.value != null) {
2312
                this.value.accept(visitor, filter);
2313
            }
2314
        }
2315

    
2316
        @Override
2317
        public InsertColumnBuilder name(String name) {
2318
            this.name = expression().variable(name);
2319
            return this;
2320
        }
2321

    
2322
        @Override
2323
        public InsertColumnBuilder with_value(Value value) {
2324
            this.value = value;
2325
            return this;
2326
        }
2327

    
2328
        @Override
2329
        public String getName() {
2330
            return this.name.name();
2331
        }
2332

    
2333
        @Override
2334
        public Value getValue() {
2335
            return this.value;
2336
        }
2337

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

    
2343
        @Override
2344
        public String toString(Formatter<Value> formatter) {
2345
            if (formatter!=null && formatter.canApply(this)) {
2346
                return formatter.format(this);
2347
            }
2348
            return this.value.toString(formatter);
2349
        }
2350
    }
2351

    
2352
    public class InsertBuilderBase
2353
            extends AbstractStatement
2354
            implements InsertBuilder {
2355

    
2356
        protected List<InsertColumnBuilder> columns;
2357
        protected TableNameBuilder table;
2358

    
2359
        public InsertBuilderBase() {
2360
            this.columns = new ArrayList<>();
2361
        }
2362

    
2363
        @Override
2364
        public void accept(Visitor visitor, VisitorFilter filter) {
2365
            if (filter==null || filter.accept(this)) {
2366
                visitor.visit(this);
2367
            }
2368
            if (this.table != null) {
2369
                this.table.accept(visitor, filter);
2370
            }
2371
            for (InsertColumnBuilder column : columns) {
2372
                column.accept(visitor, filter);
2373
            }
2374
        }
2375

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

    
2384
        @Override
2385
        public InsertColumnBuilder column() {
2386
            InsertColumnBuilder column = createInsertColumnBuilder();
2387
            this.columns.add(column);
2388
            return column;
2389
        }
2390

    
2391
        @Override
2392
        public String toString() {
2393
            return this.toString(formatter());
2394
        }
2395

    
2396
        @Override
2397
        public String toString(Formatter<Value> formatter) {
2398
            if (formatter!=null && formatter.canApply(this)) {
2399
                return formatter.format(this);
2400
            }
2401
            /*
2402
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2403
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2404
             * output_expression [ AS output_name ] [, ...] ]
2405
             */
2406
            StringBuilder builderColumns = new StringBuilder();
2407
            StringBuilder builderValues = new StringBuilder();
2408

    
2409
            boolean first = true;
2410
            for (InsertColumnBuilder column : columns) {
2411
                if (first) {
2412
                    first = false;
2413
                } else {
2414
                    builderColumns.append(", ");
2415
                }
2416
                builderColumns.append(as_identifier(column.getName()));
2417
            }
2418
            first = true;
2419
            for (InsertColumnBuilder column : columns) {
2420
                if (first) {
2421
                    first = false;
2422
                } else {
2423
                    builderValues.append(", ");
2424
                }
2425
                builderValues.append(column.toString(formatter));
2426
            }
2427

    
2428
            String sql = MessageFormat.format(
2429
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2430
                    this.table.toString(formatter),
2431
                    builderColumns.toString(),
2432
                    builderValues.toString()
2433
            );
2434
            return sql;
2435

    
2436
        }
2437
    }
2438

    
2439
    public class UpdateTableStatisticsBuilderBase
2440
            extends AbstractStatement
2441
            implements UpdateTableStatisticsBuilder {
2442

    
2443
        protected TableNameBuilder table;
2444

    
2445
        @Override
2446
        public void accept(Visitor visitor, VisitorFilter filter) {
2447
            if (filter==null || filter.accept(this)) {
2448
                visitor.visit(this);
2449
            }
2450
            if (this.table != null) {
2451
                this.table.accept(visitor, filter);
2452
            }
2453
        }
2454

    
2455
        @Override
2456
        public TableNameBuilder table() {
2457
            if (table == null) {
2458
                table = createTableNameBuilder();
2459
            }
2460
            return table;
2461
        }
2462

    
2463
        @Override
2464
        public String toString() {
2465
            return this.toString(formatter());
2466
        }
2467

    
2468
        @Override
2469
        public String toString(Formatter<Value> formatter) {
2470
            if (formatter!=null && formatter.canApply(this)) {
2471
                return formatter.format(this);
2472
            }
2473
            StringBuilder builder = new StringBuilder();
2474
            boolean first = true;
2475
            for (String sql : toStrings(formatter)) {
2476
                if (StringUtils.isEmpty(sql)) {
2477
                    continue;
2478
                }
2479
                if (first) {
2480
                    first = false;
2481
                } else {
2482
                    builder.append("; ");
2483
                }
2484
                builder.append(sql);
2485
            }
2486
            return builder.toString();
2487
        }
2488

    
2489
        @Override
2490
        public List<String> toStrings() {
2491
            return this.toStrings(formatter());
2492
        }
2493

    
2494
        @Override
2495
        public List<String> toStrings(Formatter formatter) {
2496
            List<String> sqls = new ArrayList<>();
2497

    
2498
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2499
                String sql = MessageFormat.format(
2500
                        STMT_UPDATE_TABLE_STATISTICS_table,
2501
                        table.toString(formatter)
2502
                );
2503
                if (!StringUtils.isEmpty(sql)) {
2504
                    sqls.add(sql);
2505
                }
2506
            }
2507
            return sqls;
2508
        }
2509
    }
2510

    
2511
    protected GeometryExpressionBuilder expressionBuilder;
2512

    
2513
    protected String defaultSchema;
2514
    protected boolean supportSchemas;
2515
    protected boolean hasSpatialFunctions;
2516
    protected GeometrySupportType geometrySupportType;
2517
    protected boolean allowAutomaticValues;
2518

    
2519
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2520

    
2521
    protected String constant_true = "(1=1)";
2522
    protected String constant_false = "(1<>1)";
2523

    
2524
    protected String type_boolean = "BOOLEAN";
2525
    protected String type_byte = "TINYINT";
2526
    protected String type_bytearray = "BYTEA";
2527
    protected String type_geometry = "TEXT";
2528
    protected String type_char = "CHARACTER(1)";
2529
    protected String type_date = "DATE";
2530
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2531
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2532
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2533
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2534
    protected String type_int = "INT";
2535
    protected String type_long = "BIGINT";
2536
    protected String type_string = "TEXT";
2537
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2538
    protected String type_time = "TIME";
2539
    protected String type_timestamp = "TIMESTAMP";
2540
    protected String type_version = "VARCHAR(30)";
2541
    protected String type_URI = "TEXT";
2542
    protected String type_URL = "TEXT";
2543
    protected String type_FILE = "TEXT";
2544
    protected String type_FOLDER = "TEXT";
2545

    
2546
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2547
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2548
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2549
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2550
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2551
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2552
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2553
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2554
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2555
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2556

    
2557
    public SQLBuilderBase() {
2558
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2559

    
2560
        this.hasSpatialFunctions = false;
2561
        this.supportSchemas = true;
2562
        this.geometrySupportType = GeometrySupportType.WKT;
2563

    
2564
        this.defaultSchema = "public";
2565
        this.allowAutomaticValues = true;
2566

    
2567
    }
2568
    
2569
    @Override
2570
    public void setProperties(Class filter, final Object... values) {
2571
        this.accept(new Visitor() {
2572
            @Override
2573
            public void visit(Visitable v) {
2574
                for (int i = 0; i < values.length; i+=2) {
2575
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2576
                }
2577
            }
2578
        }, new ClassVisitorFilter(filter) );
2579
    }
2580

    
2581
    public String quote_for_identifiers() {
2582
        return "\"";
2583
    }
2584

    
2585
    public String quote_for_strings() {
2586
        return "'";
2587
    }
2588

    
2589
    @Override
2590
    public String as_identifier(String id) {
2591
        String quote = this.quote_for_identifiers();
2592
//        No se porque no esta disponible wrapIfMissing
2593
//        return StringUtils.wrapIfMissing(id,quote);
2594
        if (id.startsWith(quote)) {
2595
            return id;
2596
        }
2597
        return quote + id + quote;
2598

    
2599
    }
2600

    
2601
    @Override
2602
    public String as_string(String s) {
2603
        String quote = this.quote_for_strings();
2604
//        No se porque no esta disponible wrapIfMissing
2605
//        return StringUtils.wrapIfMissing(id,quote);
2606
        if (s.startsWith(quote)) {
2607
            return s;
2608
        }
2609
        return quote + s + quote;
2610

    
2611
    }
2612

    
2613
    @Override
2614
    public String as_string(byte[] data) {
2615
        return this.expressionBuilder.bytearray_0x(data);
2616
//        return this.expressionBuilder.bytearray_hex(data);
2617
//        return this.expressionBuilder.bytearray_x(data);
2618
    }
2619
    
2620
    @Override
2621
    public String as_string(boolean value) {
2622
        return value? "TRUE" : "FALSE";
2623
    }
2624

    
2625
    @Override
2626
    public String as_string(Number value) {
2627
        return Objects.toString(value);
2628
    }
2629
    
2630
    @Override
2631
    public String as_string(Object value) {
2632
        if( value == null ) {
2633
            return "NULL";
2634
        }
2635
        if( value instanceof CharSequence ) {
2636
            return as_string(value.toString());
2637
        }
2638
        if( value instanceof Number ) {
2639
            return as_string((Number)value);
2640
        }
2641
        if( value instanceof Boolean ) {
2642
            return as_string((boolean)value);
2643
        }
2644
        if( value instanceof byte[] ) {
2645
            return as_string((byte[])value);
2646
        }
2647
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2648
    }
2649
    
2650
    @Override
2651
    public GeometryExpressionBuilder expression() {
2652
        return this.expressionBuilder;
2653
    }
2654

    
2655
    @Override
2656
    public boolean has_spatial_functions() {
2657
        return this.hasSpatialFunctions;
2658
    }
2659

    
2660
    @Override
2661
    public GeometrySupportType geometry_support_type() {
2662
        return this.geometrySupportType;
2663
    }
2664

    
2665
    protected GeometryExpressionBuilder createExpressionBuilder() {
2666
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2667
    }
2668

    
2669
    @Override
2670
    public Object srs_id(IProjection projection) {
2671
        String abrev = projection.getAbrev();
2672
        return abrev.split(":")[1].trim();
2673
    }
2674

    
2675
    @Override
2676
    public String default_schema() {
2677
        return this.defaultSchema;
2678
    }
2679

    
2680
    @Override
2681
    public boolean support_schemas() {
2682
        return this.supportSchemas;
2683
    }
2684

    
2685
    @Override
2686
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2687
        switch (type) {
2688
            case DataTypes.BOOLEAN:
2689
                return type_boolean;
2690
            case DataTypes.CHAR:
2691
                return type_char;
2692

    
2693

    
2694
            case DataTypes.BYTE:
2695
                return type_byte;
2696
            case DataTypes.INT:
2697
                return type_int;
2698
            case DataTypes.LONG:
2699
                return type_long;
2700

    
2701
            case DataTypes.FLOAT:
2702
                return type_float;
2703
            case DataTypes.DOUBLE:
2704
                return type_double;
2705
            case DataTypes.DECIMAL:
2706
                if (precision < 1) {
2707
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2708
                }
2709
                if (scale < 1) {
2710
                  return MessageFormat.format(type_decimal_p, precision);
2711
                }
2712
                return MessageFormat.format(type_decimal_ps, precision, scale);
2713

    
2714
                
2715
            case DataTypes.STRING:
2716
                if (size < 0) {
2717
                    return type_string;
2718
                } else if (size < 4096) {
2719
                    return MessageFormat.format(type_string_p, size);
2720
                }
2721
                return type_string;
2722

    
2723
                
2724
            case DataTypes.DATE:
2725
                return type_date;
2726
            case DataTypes.TIME:
2727
                return type_time;
2728
            case DataTypes.TIMESTAMP:
2729
                return type_timestamp;
2730

    
2731
            case DataTypes.BYTEARRAY:
2732
                return type_bytearray;
2733

    
2734
            case DataTypes.GEOMETRY:
2735
                return type_geometry;
2736

    
2737
            case DataTypes.VERSION:
2738
                return type_version;
2739
            case DataTypes.URI:
2740
                return type_URI;
2741
            case DataTypes.URL:
2742
                return type_URL;
2743
            case DataTypes.FILE:
2744
                return type_FILE;
2745
            case DataTypes.FOLDER:
2746
                return type_FOLDER;
2747
            default:
2748
                return null;
2749
        }
2750
    }
2751

    
2752
    @Override
2753
    public Object sqlgeometrytype(int type, int subtype) {
2754
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2755
        // identificadores numericos para el tipo y otros strings.
2756
        // Por defecto vamos a devolver strings.
2757
        if (sqlgeometrytypes == null) {
2758
            sqlgeometrytypes = new HashMap<>();
2759
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2760
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2761
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2762
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2763

    
2764
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2765
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2766
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2767
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2768

    
2769
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2770
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2771
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2772
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2773

    
2774
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2775
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2776
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2777
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2778

    
2779
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2780
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2781
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2782
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2783

    
2784
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2785
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2786
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2787
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2788

    
2789
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2790
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2791
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2792
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2793

    
2794
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2795
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2796
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2797
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2798

    
2799
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2800
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2801
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2802
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2803
        }
2804
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2805
    }
2806

    
2807
    @Override
2808
    public Object sqlgeometrydimension(int type, int subtype) {
2809
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2810
        // identificadores numericos para las dimensiones y otros strings.
2811
        // Por defecto vamos a devolver enteros.
2812
        switch (subtype) {
2813
            case Geometry.SUBTYPES.GEOM3D:
2814
                return 3;
2815
            case Geometry.SUBTYPES.GEOM2DM:
2816
                return 3;
2817
            case Geometry.SUBTYPES.GEOM3DM:
2818
                return 4;
2819
            case Geometry.SUBTYPES.GEOM2D:
2820
            default:
2821
                return 2;
2822
        }
2823
    }
2824

    
2825
    @Override
2826
    public TableNameBuilder createTableNameBuilder() {
2827
        return new TableNameBuilderBase();
2828
    }
2829

    
2830
    protected SelectColumnBuilder createSelectColumnBuilder() {
2831
        return new SelectColumnBuilderBase();
2832
    }
2833

    
2834
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2835
        return new UpdateColumnBuilderBase();
2836
    }
2837

    
2838
    protected InsertColumnBuilder createInsertColumnBuilder() {
2839
        return new InsertColumnBuilderBase();
2840
    }
2841

    
2842
    protected OrderByBuilder createOrderByBuilder() {
2843
        return new OrderByBuilderBase();
2844
    }
2845

    
2846
    protected FromBuilder createFromBuilder() {
2847
        return new FromBuilderBase();
2848
    }
2849

    
2850
    protected SelectBuilder createSelectBuilder() {
2851
        return new SelectBuilderBase();
2852
    }
2853

    
2854
    protected UpdateBuilder createUpdateBuilder() {
2855
        return new UpdateBuilderBase();
2856
    }
2857

    
2858
    protected DeleteBuilder createDeleteBuilder() {
2859
        return new DeleteBuilderBase();
2860
    }
2861

    
2862
    protected GrantBuilder createGrantBuilder() {
2863
        return new GrantBuilderBase();
2864
    }
2865

    
2866
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2867
        return new GrantRoleBuilderBase(table, role);
2868
    }
2869

    
2870
    protected DropTableBuilder createDropTableBuilder() {
2871
        return new DropTableBuilderBase();
2872
    }
2873

    
2874
    protected CreateTableBuilder createCreateTableBuilder() {
2875
        return new CreateTableBuilderBase();
2876
    }
2877

    
2878
    protected AlterTableBuilder createAlterTableBuilder() {
2879
        return new AlterTableBuilderBase();
2880
    }
2881

    
2882
    protected InsertBuilder createInsertBuilder() {
2883
        return new InsertBuilderBase();
2884
    }
2885

    
2886
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2887
        return new UpdateTableStatisticsBuilderBase();
2888
    }
2889

    
2890
    protected CreateIndexBuilder createCreateIndexBuilder() {
2891
        return new CreateIndexBuilderBase();
2892
    }
2893

    
2894
    @Override
2895
    public SelectBuilder select() {
2896
        if (this.select == null) {
2897
            this.select = this.createSelectBuilder();
2898
        }
2899
        return this.select;
2900
    }
2901

    
2902
    @Override
2903
    public UpdateBuilder update() {
2904
        if (this.update == null) {
2905
            this.update = this.createUpdateBuilder();
2906
        }
2907
        return this.update;
2908
    }
2909

    
2910
    @Override
2911
    public UpdateTableStatisticsBuilder update_table_statistics() {
2912
        if (this.update_table_statistics == null) {
2913
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2914
        }
2915
        return this.update_table_statistics;
2916
    }
2917

    
2918
    @Override
2919
    public DropTableBuilder drop_table() {
2920
        if (this.drop_table == null) {
2921
            this.drop_table = this.createDropTableBuilder();
2922
        }
2923
        return this.drop_table;
2924
    }
2925

    
2926
    @Override
2927
    public CreateIndexBuilder create_index() {
2928
        if (this.create_index == null) {
2929
            this.create_index = this.createCreateIndexBuilder();
2930
        }
2931
        return this.create_index;
2932
    }
2933

    
2934
    @Override
2935
    public DeleteBuilder delete() {
2936
        if (this.delete == null) {
2937
            this.delete = this.createDeleteBuilder();
2938
        }
2939
        return this.delete;
2940
    }
2941

    
2942
    @Override
2943
    public InsertBuilder insert() {
2944
        if (this.insert == null) {
2945
            this.insert = this.createInsertBuilder();
2946
        }
2947
        return this.insert;
2948
    }
2949

    
2950
    @Override
2951
    public TableNameBuilder table_name() {
2952
        if (this.table_name == null) {
2953
            this.table_name = this.createTableNameBuilder();
2954
        }
2955
        return this.table_name;
2956
    }
2957

    
2958
    
2959
    @Override
2960
    public AlterTableBuilder alter_table() {
2961
        if (this.alter_table == null) {
2962
            this.alter_table = this.createAlterTableBuilder();
2963
        }
2964
        return this.alter_table;
2965
    }
2966

    
2967
    @Override
2968
    public CreateTableBuilder create_table() {
2969
        if (this.create_table == null) {
2970
            this.create_table = this.createCreateTableBuilder();
2971
        }
2972
        return this.create_table;
2973
    }
2974

    
2975
    @Override
2976
    public GrantBuilder grant() {
2977
        if (this.grant == null) {
2978
            this.grant = this.createGrantBuilder();
2979
        }
2980
        return this.grant;
2981
    }
2982
    
2983
    @Override
2984
    public Column column(String name) {
2985
        ColumnBase col = new ColumnBase(null, name);
2986
        return col;
2987
    }
2988

    
2989
    @Override
2990
    public Column column(TableNameBuilder table, String name) {
2991
        ColumnBase col = new ColumnBase(table, name);
2992
        return col;
2993
    }
2994
    
2995
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2996
        return new JoinBase(type, table, expression);
2997
    }
2998

    
2999
    public void accept(Visitor visitor, VisitorFilter filter) {
3000
        if (this.select != null) {
3001
            this.select.accept(visitor, filter);
3002
        }
3003
        if (this.update != null) {
3004
            this.update.accept(visitor, filter);
3005
        }
3006
        if (this.insert != null) {
3007
            this.insert.accept(visitor, filter);
3008
        }
3009
        if (this.delete != null) {
3010
            this.delete.accept(visitor, filter);
3011
        }
3012
        if (this.alter_table != null) {
3013
            this.alter_table.accept(visitor, filter);
3014
        }
3015
        if (this.create_table != null) {
3016
            this.create_table.accept(visitor, filter);
3017
        }
3018
        if (this.drop_table != null) {
3019
            this.drop_table.accept(visitor, filter);
3020
        }
3021
        if (this.table_name != null) {
3022
            this.table_name.accept(visitor, filter);
3023
        }
3024
    }
3025

    
3026
    protected Formatter formatter() {
3027
        return expression().formatter();
3028
    }
3029

    
3030
    @Override
3031
    public String toString() {
3032
        return this.toString(formatter());
3033
    }
3034

    
3035
    @Override
3036
    public String toString(Formatter formatter) {
3037
        if (this.select != null) {
3038
            return this.select.toString(formatter);
3039
        }
3040
        if (this.update != null) {
3041
            return this.update.toString(formatter);
3042
        }
3043
        if (this.insert != null) {
3044
            return this.insert.toString(formatter);
3045
        }
3046
        if (this.delete != null) {
3047
            return this.delete.toString(formatter);
3048
        }
3049
        if (this.alter_table != null) {
3050
            return this.alter_table.toString(formatter);
3051
        }
3052
        if (this.create_table != null) {
3053
            return this.create_table.toString(formatter);
3054
        }
3055
        if (this.drop_table != null) {
3056
            return this.drop_table.toString(formatter);
3057
        }
3058
        if (this.update_table_statistics != null) {
3059
            return this.update_table_statistics.toString(formatter);
3060
        }
3061
        if (this.table_name != null) {
3062
            return this.table_name.toString(formatter);
3063
        }
3064
        return "";
3065
    }
3066

    
3067
    @Override
3068
    public CountBuilder count() {
3069
        return new CountBuilderBase();
3070
    }
3071

    
3072
    @Override
3073
    public List<Parameter> parameters() {
3074
        final List<Parameter> params = new ArrayList<>();
3075
        this.accept(new Visitor() {
3076
            @Override
3077
            public void visit(Visitable value) {
3078
                params.add((Parameter) value);
3079
            }
3080
        }, new ClassVisitorFilter(Parameter.class));
3081
        return params;
3082
    }
3083

    
3084
    @Override
3085
    public List<Variable> variables() {
3086
        final List<Variable> vars = new ArrayList<>();
3087
        this.accept(new Visitor() {
3088
            @Override
3089
            public void visit(Visitable value) {
3090
                if (!vars.contains((Variable) value)) {
3091
                    vars.add((Variable) value);
3092
                }
3093
            }
3094
        }, new ClassVisitorFilter(Variable.class));
3095
        return vars;
3096
    }
3097

    
3098
    @Override
3099
    public List<String> parameters_names() {
3100
        List<String> params = new ArrayList<>();
3101
        for (Parameter param : parameters()) {
3102
            String s;
3103
            switch (param.type()) {
3104
                case PARAMETER_TYPE_CONSTANT:
3105
                    Object theValue = param.value();
3106
                    if (theValue == null) {
3107
                        s = "null";
3108
                    } else if (theValue instanceof String) {
3109
                        s = "'" + (String) theValue + "'";
3110
                    } else {
3111
                        s = theValue.toString();
3112
                    }
3113
                    break;
3114
                case PARAMETER_TYPE_VARIABLE:
3115
                default:
3116
                    s = "\"" + param.name() + "\"";
3117
            }
3118
            params.add(s);
3119
        }
3120
        return params;
3121
    }
3122

    
3123
    @Override
3124
    public List<String> variables_names() {
3125
        List<String> vars = new ArrayList<>();
3126
        for (Variable var : this.variables()) {
3127
            vars.add(var.name());
3128
        }
3129
        Collections.sort(vars);
3130
        return vars;
3131
    }    
3132
}