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

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

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

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

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

    
72
    protected abstract class AbstractStatementPart extends AbstractValue {
73

    
74
    }
75

    
76
    protected abstract class AbstractStatement extends AbstractStatementPart {
77

    
78
    }
79

    
80
    protected class ColumnDescriptorBase implements ColumnDescriptor {
81

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
319
    public class ColumnBase extends AbstractValue implements Column {
320

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

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

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

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

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

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

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

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

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

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

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

    
390
        public TableNameBuilderBase() {
391
        }
392

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

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

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

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

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

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

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

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

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

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

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

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

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

    
501
    }
502

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

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

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

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

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

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

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

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

    
560
    }
561

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

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

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

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

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

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

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

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

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

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

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

    
683
    }
684

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
921
        public SelectBuilderBase() {
922
            this.columns = new ArrayList<>();
923
            this.distinct = false;
924
        }
925
        @Override
926
        public List<Value> getGroups() {
927
            return this.groupColumn;
928
        }
929

    
930
        @Override
931
        public SelectBuilder group_by(Value... columns) {
932
            if( this.groupColumn==null ) {
933
                this.groupColumn = new ArrayList<>();
934
            }
935
            for (Value column : columns) {
936
                this.groupColumn.add(column);
937
            }
938
            return this;
939
        }
940

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

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

    
1017
        @Override
1018
        public SelectBuilder distinct() {
1019
            this.distinct = true;
1020
            return this;
1021
        }
1022

    
1023
        @Override
1024
        public SelectColumnBuilder column() {
1025
            SelectColumnBuilder builder = createSelectColumnBuilder();
1026
            this.columns.add(builder);
1027
            return builder;
1028
        }
1029

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

    
1049
        @Override
1050
        public FromBuilder from() {
1051
            if (this.from == null) {
1052
                this.from = createFromBuilder();
1053
            }
1054
            return this.from;
1055
        }
1056

    
1057
        @Override
1058
        public boolean has_from() {
1059
            return this.from != null;
1060
        }
1061

    
1062
        @Override
1063
        public GeometryExpressionBuilder where() {
1064
            if (this.where == null) {
1065
                this.where = createExpressionBuilder();
1066
            }
1067
            return this.where;
1068
        }
1069

    
1070
        @Override
1071
        public boolean has_where() {
1072
            if (this.where == null) {
1073
                return false;
1074
            }
1075
            return this.where.value() != null;
1076
        }
1077

    
1078
        @Override
1079
        public SelectBuilder limit(long limit) {
1080
            this.limit = limit;
1081
            return this;
1082
        }
1083

    
1084
        @Override
1085
        public SelectBuilder limit(Long limit) {
1086
            if (limit == null) {
1087
                this.limit = 0;
1088
            } else {
1089
                this.limit = limit;
1090
            }
1091
            return this;
1092
        }
1093

    
1094
        @Override
1095
        public boolean has_limit() {
1096
            return this.limit > 0;
1097
        }
1098

    
1099
        @Override
1100
        public SelectBuilder offset(long offset) {
1101
            this.offset = offset;
1102
            return this;
1103
        }
1104

    
1105
        @Override
1106
        public boolean has_offset() {
1107
            return this.offset > 0;
1108
        }
1109

    
1110
        @Override
1111
        public OrderByBuilder order_by() {
1112
            if (this.order_by == null) {
1113
                this.order_by = new ArrayList<>();
1114
            }
1115
            OrderByBuilder order = createOrderByBuilder();
1116
            this.order_by.add(order);
1117
            return order;
1118
        }
1119

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

    
1158
        @Override
1159
        public String toString() {
1160
            return this.toString(formatter());
1161
        }
1162

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

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

    
1215
            if (this.has_limit()) {
1216
                builder.append(" LIMIT ");
1217
                builder.append(this.limit);
1218
            }
1219
            if (this.has_offset()) {
1220
                builder.append(" OFFSET ");
1221
                builder.append(this.offset);
1222
            }
1223
            return builder.toString();
1224

    
1225
        }
1226
    }
1227

    
1228
    public class DropTableBuilderBase
1229
            extends AbstractStatement
1230
            implements DropTableBuilder {
1231

    
1232
        protected TableNameBuilder table;
1233

    
1234
        @Override
1235
        public TableNameBuilder table() {
1236
            if (table == null) {
1237
                table = createTableNameBuilder();
1238
            }
1239
            return table;
1240
        }
1241

    
1242
        @Override
1243
        public void accept(Visitor visitor, VisitorFilter filter) {
1244
            if (filter==null || filter.accept(this)) {
1245
                visitor.visit(this);
1246
            }
1247
            this.table.accept(visitor, filter);
1248
        }
1249

    
1250
        @Override
1251
        public String toString() {
1252
            return this.toString(formatter());
1253
        }
1254

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

    
1276
        @Override
1277
        public List<String> toStrings() {
1278
            return this.toStrings(formatter());
1279
        }
1280

    
1281
        @Override
1282
        public List<String> toStrings(Formatter formatter) {
1283
            List<String> sqls = new ArrayList<>();
1284

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

    
1313
    public class GrantRoleBuilderBase
1314
            extends AbstractStatementPart
1315
            implements GrantRoleBuilder {
1316

    
1317
        protected TableNameBuilder table;
1318
        protected String role;
1319
        protected Set<Privilege> privileges;
1320

    
1321
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1322
            this.table = table;
1323
            this.role = role;
1324
            this.privileges = new HashSet<>();
1325
        }
1326

    
1327
        @Override
1328
        public GrantRoleBuilder privilege(Privilege privilege) {
1329
            privileges.add(privilege);
1330
            return this;
1331
        }
1332

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

    
1339
        @Override
1340
        public GrantRoleBuilder update() {
1341
            privileges.add(Privilege.UPDATE);
1342
            return this;
1343
        }
1344

    
1345
        @Override
1346
        public GrantRoleBuilder insert() {
1347
            privileges.add(Privilege.INSERT);
1348
            return this;
1349
        }
1350

    
1351
        @Override
1352
        public GrantRoleBuilder delete() {
1353
            privileges.add(Privilege.DELETE);
1354
            return this;
1355
        }
1356

    
1357
        @Override
1358
        public GrantRoleBuilder truncate() {
1359
            privileges.add(Privilege.TRUNCATE);
1360
            return this;
1361
        }
1362

    
1363
        @Override
1364
        public GrantRoleBuilder reference() {
1365
            privileges.add(Privilege.REFERENCE);
1366
            return this;
1367
        }
1368

    
1369
        @Override
1370
        public GrantRoleBuilder trigger() {
1371
            privileges.add(Privilege.TRIGGER);
1372
            return this;
1373
        }
1374

    
1375
        @Override
1376
        public GrantRoleBuilder all() {
1377
            privileges.add(Privilege.ALL);
1378
            return this;
1379
        }
1380

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

    
1403
        @Override
1404
        public String toString() {
1405
            return this.toString(formatter());
1406
        }
1407

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

    
1433
    public class GrantBuilderBase
1434
            extends AbstractStatement
1435
            implements GrantBuilder {
1436

    
1437
        protected TableNameBuilder table;
1438
        protected Map<String, GrantRoleBuilder> roles;
1439

    
1440
        public GrantBuilderBase() {
1441
            this.roles = new HashMap<>();
1442
        }
1443

    
1444
        @Override
1445
        public TableNameBuilder table() {
1446
            if (table == null) {
1447
                table = createTableNameBuilder();
1448
            }
1449
            return table;
1450
        }
1451

    
1452
        @Override
1453
        public void accept(Visitor visitor, VisitorFilter filter) {
1454
            if (filter==null || filter.accept(this)) {
1455
                visitor.visit(this);
1456
            }
1457
            if (this.table != null) {
1458
                this.table.accept(visitor, filter);
1459
            }
1460
        }
1461

    
1462
        @Override
1463
        public GrantRoleBuilder role(String role) {
1464
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1465
            if (roleBuilder == null) {
1466
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1467
                this.roles.put(role, roleBuilder);
1468
            }
1469
            return roleBuilder;
1470
        }
1471

    
1472
        @Override
1473
        public String toString() {
1474
            return this.toString(formatter());
1475
        }
1476

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

    
1498
        @Override
1499
        public List<String> toStrings() {
1500
            return this.toStrings(formatter());
1501
        }
1502

    
1503
        @Override
1504
        public List<String> toStrings(Formatter formatter) {
1505
            List<String> sqls = new ArrayList<>();
1506
            for (GrantRoleBuilder role : roles.values()) {
1507
                sqls.add(role.toString(formatter));
1508
            }
1509
            return sqls;
1510
        }
1511
    }
1512

    
1513
    public class UpdateColumnBuilderBase
1514
            extends InsertColumnBuilderBase
1515
            implements UpdateColumnBuilder {
1516

    
1517
        public UpdateColumnBuilderBase() {
1518
            super();
1519
        }
1520

    
1521
        @Override
1522
        public UpdateColumnBuilder name(String name) {
1523
            return (UpdateColumnBuilder) super.name(name);
1524
        }
1525

    
1526
        @Override
1527
        public UpdateColumnBuilder with_value(Value value) {
1528
            return (UpdateColumnBuilder) super.with_value(value);
1529
        }
1530

    
1531
    }
1532

    
1533
    public class UpdateBuilderBase
1534
            extends AbstractStatement
1535
            implements UpdateBuilder {
1536

    
1537
        protected GeometryExpressionBuilder where;
1538
        protected List<UpdateColumnBuilder> columns;
1539
        protected TableNameBuilder table;
1540

    
1541
        public UpdateBuilderBase() {
1542
            this.columns = new ArrayList<>();
1543
        }
1544

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

    
1561
        @Override
1562
        public GeometryExpressionBuilder where() {
1563
            if (this.where == null) {
1564
                this.where = createExpressionBuilder();
1565
            }
1566
            return this.where;
1567
        }
1568

    
1569
        @Override
1570
        public TableNameBuilder table() {
1571
            if (table == null) {
1572
                table = createTableNameBuilder();
1573
            }
1574
            return table;
1575
        }
1576

    
1577
        @Override
1578
        public UpdateColumnBuilder column() {
1579
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1580
            this.columns.add(column);
1581
            return column;
1582
        }
1583

    
1584
        @Override
1585
        public boolean has_where() {
1586
            return this.where != null;
1587
        }
1588

    
1589
        @Override
1590
        public String toString() {
1591
            return this.toString(formatter());
1592
        }
1593

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

    
1607
            boolean first = true;
1608
            for (UpdateColumnBuilder column : columns) {
1609
                if (first) {
1610
                    first = false;
1611
                } else {
1612
                    columnsAndValues.append(", ");
1613
                }
1614
                columnsAndValues.append(as_identifier(column.getName()));
1615
                columnsAndValues.append(" = ");
1616
                columnsAndValues.append(column.getValue().toString(formatter));
1617
            }
1618

    
1619
            String sql;
1620
            if (this.has_where()) {
1621
                sql = MessageFormat.format(
1622
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1623
                        this.table.toString(formatter),
1624
                        columnsAndValues.toString(),
1625
                        this.where.toString(formatter)
1626
                );
1627
            } else {
1628
                sql = MessageFormat.format(
1629
                        STMT_UPDATE_table_SET_columnsAndValues,
1630
                        this.table.toString(formatter),
1631
                        columnsAndValues.toString()
1632
                );
1633
            }
1634
            return sql;
1635
        }
1636
    }
1637

    
1638
    public class DeleteBuilderBase
1639
            extends AbstractStatement
1640
            implements DeleteBuilder {
1641

    
1642
        protected GeometryExpressionBuilder where;
1643
        protected TableNameBuilder table;
1644

    
1645
        public DeleteBuilderBase() {
1646
        }
1647

    
1648
        @Override
1649
        public void accept(Visitor visitor, VisitorFilter filter) {
1650
            if (filter==null || filter.accept(this)) {
1651
                visitor.visit(this);
1652
            }
1653
            if (this.table != null) {
1654
                this.table.accept(visitor, filter);
1655
            }
1656
            if (this.has_where()) {
1657
                this.where.accept(visitor, filter);
1658
            }
1659
        }
1660

    
1661
        @Override
1662
        public GeometryExpressionBuilder where() {
1663
            if (this.where == null) {
1664
                this.where = createExpressionBuilder();
1665
            }
1666
            return this.where;
1667
        }
1668

    
1669
        @Override
1670
        public TableNameBuilder table() {
1671
            if (table == null) {
1672
                table = createTableNameBuilder();
1673
            }
1674
            return table;
1675
        }
1676

    
1677
        @Override
1678
        public boolean has_where() {
1679
            return this.where != null;
1680
        }
1681

    
1682
        @Override
1683
        public String toString() {
1684
            return this.toString(formatter());
1685
        }
1686

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

    
1713
    public class CreateIndexBuilderBase
1714
            extends AbstractStatement
1715
            implements CreateIndexBuilder {
1716

    
1717
        protected boolean ifNotExist = false;
1718
        protected boolean isUnique = false;
1719
        protected String indexName;
1720
        protected boolean isSpatial = false;
1721
        protected TableNameBuilder table;
1722
        protected final List<String> columns;
1723

    
1724
        public CreateIndexBuilderBase() {
1725
            this.columns = new ArrayList<>();
1726
        }
1727

    
1728
        @Override
1729
        public CreateIndexBuilder unique() {
1730
            this.isUnique = true;
1731
            return this;
1732
        }
1733

    
1734
        @Override
1735
        public CreateIndexBuilder if_not_exist() {
1736
            this.ifNotExist = true;
1737
            return this;
1738
        }
1739

    
1740
        @Override
1741
        public CreateIndexBuilder name(String name) {
1742
            this.indexName = name;
1743
            return this;
1744
        }
1745

    
1746
        @Override
1747
        public CreateIndexBuilder spatial() {
1748
            this.isSpatial = true;
1749
            return this;
1750
        }
1751

    
1752
        @Override
1753
        public CreateIndexBuilder column(String name) {
1754
            this.columns.add(name);
1755
            return this;
1756
        }
1757

    
1758
        @Override
1759
        public TableNameBuilder table() {
1760
            if (table == null) {
1761
                table = createTableNameBuilder();
1762
            }
1763
            return table;
1764
        }
1765

    
1766
        @Override
1767
        public void accept(Visitor visitor, VisitorFilter filter) {
1768
            if (filter==null || filter.accept(this)) {
1769
                visitor.visit(this);
1770
            }
1771
            if (this.table != null) {
1772
                this.table.accept(visitor, filter);
1773
            }
1774
        }
1775

    
1776
        @Override
1777
        public String toString() {
1778
            return this.toString(formatter());
1779
        }
1780

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

    
1802
        @Override
1803
        public List<String> toStrings() {
1804
            return this.toStrings(formatter());
1805
        }
1806

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

    
1836
            List<String> sqls = new ArrayList<>();
1837
            sqls.add(builder.toString());
1838
            return sqls;
1839
        }
1840

    
1841
    }
1842

    
1843
    public class AlterTableBuilderBase
1844
            extends AbstractStatement
1845
            implements AlterTableBuilder {
1846

    
1847
        protected TableNameBuilder table;
1848
        protected List<String> drops;
1849
        protected List<ColumnDescriptor> adds;
1850
        protected List<ColumnDescriptor> alters;
1851
        protected List<Pair<String, String>> renames;
1852

    
1853
        public AlterTableBuilderBase() {
1854
            this.drops = new ArrayList<>();
1855
            this.adds = new ArrayList<>();
1856
            this.alters = new ArrayList<>();
1857
            this.renames = new ArrayList<>();
1858
        }
1859

    
1860
        @Override
1861
        public boolean isEmpty() {
1862
            return this.drops.isEmpty()
1863
                    && this.adds.isEmpty()
1864
                    && this.alters.isEmpty()
1865
                    && this.renames.isEmpty();
1866
        }
1867

    
1868
        @Override
1869
        public void accept(Visitor visitor, VisitorFilter filter) {
1870
            if (filter==null || filter.accept(this)) {
1871
                visitor.visit(this);
1872
            }
1873
            if (this.table != null) {
1874
                this.table.accept(visitor, filter);
1875
            }
1876
        }
1877

    
1878
        @Override
1879
        public TableNameBuilder table() {
1880
            if (table == null) {
1881
                table = createTableNameBuilder();
1882
            }
1883
            return table;
1884
        }
1885

    
1886
        @Override
1887
        public AlterTableBuilder drop_column(String columnName) {
1888
            this.drops.add(columnName);
1889
            return this;
1890
        }
1891

    
1892
        @Override
1893
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1894
            this.adds.add(new ColumnDescriptorBase(fad));
1895
            return this;
1896
        }
1897

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

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

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

    
1925
        @Override
1926
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1927
            this.alters.add(new ColumnDescriptorBase(fad));
1928
            return this;
1929
        }
1930

    
1931
        @Override
1932
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1933
            if (isPk || isAutomatic) {
1934
                allowNulls = false;
1935
            }
1936
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1937
            return this;
1938
        }
1939

    
1940
        @Override
1941
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1942
            if (StringUtils.isEmpty(columnName)) {
1943
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1944
            }
1945
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1946
            return this;
1947
        }
1948

    
1949
        @Override
1950
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1951
            if (StringUtils.isEmpty(columnName)) {
1952
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1953
            }
1954
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1955
            return this;
1956
        }
1957

    
1958
        @Override
1959
        public AlterTableBuilder rename_column(String source, String target) {
1960
            this.renames.add(new ImmutablePair(source, target));
1961
            return this;
1962
        }
1963

    
1964
        @Override
1965
        public String toString() {
1966
            return this.toString(formatter());
1967
        }
1968

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

    
1990
        @Override
1991
        public List<String> toStrings() {
1992
            return this.toStrings(formatter());
1993
        }
1994

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

    
2096
    }
2097

    
2098
    public class CreateTableBuilderBase
2099
            extends AbstractStatement
2100
            implements CreateTableBuilder {
2101

    
2102
        protected TableNameBuilder table;
2103
        protected List<ColumnDescriptor> columns;
2104

    
2105
        public CreateTableBuilderBase() {
2106
            this.columns = new ArrayList<>();
2107
        }
2108

    
2109
        @Override
2110
        public void accept(Visitor visitor, VisitorFilter filter) {
2111
            if (filter==null || filter.accept(this)) {
2112
                visitor.visit(this);
2113
            }
2114
            if (this.table != null) {
2115
                this.table.accept(visitor, filter);
2116
            }
2117
        }
2118

    
2119
        @Override
2120
        public TableNameBuilder table() {
2121
            if (table == null) {
2122
                table = createTableNameBuilder();
2123
            }
2124
            return table;
2125
        }
2126

    
2127
        @Override
2128
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2129
            this.columns.add(new ColumnDescriptorBase(fad));
2130
            return this;
2131
        }
2132

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

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

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

    
2163
        @Override
2164
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2165
            if (StringUtils.isEmpty(columnName)) {
2166
                return null;
2167
            }
2168
            for (ColumnDescriptor column : columns) {
2169
                if (columnName.equals(column.getName())) {
2170
                    return column;
2171
                }
2172
            }
2173
            return null;
2174
        }
2175

    
2176
        @Override
2177
        public String toString() {
2178
            return this.toString(formatter());
2179
        }
2180

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

    
2202
        @Override
2203
        public List<String> toStrings() {
2204
            return this.toStrings(formatter());
2205
        }
2206

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

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

    
2288
    public class InsertColumnBuilderBase
2289
            extends AbstractStatement
2290
            implements InsertColumnBuilder {
2291

    
2292
        protected Variable name;
2293
        protected Value value;
2294

    
2295
        public InsertColumnBuilderBase() {
2296
        }
2297

    
2298
        @Override
2299
        public void accept(Visitor visitor, VisitorFilter filter) {
2300
            if (filter==null || filter.accept(this)) {
2301
                visitor.visit(this);
2302
            }
2303
            if (this.name != null) {
2304
                this.name.accept(visitor, filter);
2305
            }
2306
            if (this.value != null) {
2307
                this.value.accept(visitor, filter);
2308
            }
2309
        }
2310

    
2311
        @Override
2312
        public InsertColumnBuilder name(String name) {
2313
            this.name = expression().variable(name);
2314
            return this;
2315
        }
2316

    
2317
        @Override
2318
        public InsertColumnBuilder with_value(Value value) {
2319
            this.value = value;
2320
            return this;
2321
        }
2322

    
2323
        @Override
2324
        public String getName() {
2325
            return this.name.name();
2326
        }
2327

    
2328
        @Override
2329
        public Value getValue() {
2330
            return this.value;
2331
        }
2332

    
2333
        @Override
2334
        public String toString() {
2335
            return this.toString(formatter());
2336
        }
2337

    
2338
        @Override
2339
        public String toString(Formatter<Value> formatter) {
2340
            if (formatter!=null && formatter.canApply(this)) {
2341
                return formatter.format(this);
2342
            }
2343
            return this.value.toString(formatter);
2344
        }
2345
    }
2346

    
2347
    public class InsertBuilderBase
2348
            extends AbstractStatement
2349
            implements InsertBuilder {
2350

    
2351
        protected List<InsertColumnBuilder> columns;
2352
        protected TableNameBuilder table;
2353

    
2354
        public InsertBuilderBase() {
2355
            this.columns = new ArrayList<>();
2356
        }
2357

    
2358
        @Override
2359
        public void accept(Visitor visitor, VisitorFilter filter) {
2360
            if (filter==null || filter.accept(this)) {
2361
                visitor.visit(this);
2362
            }
2363
            if (this.table != null) {
2364
                this.table.accept(visitor, filter);
2365
            }
2366
            for (InsertColumnBuilder column : columns) {
2367
                column.accept(visitor, filter);
2368
            }
2369
        }
2370

    
2371
        @Override
2372
        public TableNameBuilder table() {
2373
            if (table == null) {
2374
                table = createTableNameBuilder();
2375
            }
2376
            return table;
2377
        }
2378

    
2379
        @Override
2380
        public InsertColumnBuilder column() {
2381
            InsertColumnBuilder column = createInsertColumnBuilder();
2382
            this.columns.add(column);
2383
            return column;
2384
        }
2385

    
2386
        @Override
2387
        public String toString() {
2388
            return this.toString(formatter());
2389
        }
2390

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

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

    
2423
            String sql = MessageFormat.format(
2424
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2425
                    this.table.toString(formatter),
2426
                    builderColumns.toString(),
2427
                    builderValues.toString()
2428
            );
2429
            return sql;
2430

    
2431
        }
2432
    }
2433

    
2434
    public class UpdateTableStatisticsBuilderBase
2435
            extends AbstractStatement
2436
            implements UpdateTableStatisticsBuilder {
2437

    
2438
        protected TableNameBuilder table;
2439

    
2440
        @Override
2441
        public void accept(Visitor visitor, VisitorFilter filter) {
2442
            if (filter==null || filter.accept(this)) {
2443
                visitor.visit(this);
2444
            }
2445
            if (this.table != null) {
2446
                this.table.accept(visitor, filter);
2447
            }
2448
        }
2449

    
2450
        @Override
2451
        public TableNameBuilder table() {
2452
            if (table == null) {
2453
                table = createTableNameBuilder();
2454
            }
2455
            return table;
2456
        }
2457

    
2458
        @Override
2459
        public String toString() {
2460
            return this.toString(formatter());
2461
        }
2462

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

    
2484
        @Override
2485
        public List<String> toStrings() {
2486
            return this.toStrings(formatter());
2487
        }
2488

    
2489
        @Override
2490
        public List<String> toStrings(Formatter formatter) {
2491
            List<String> sqls = new ArrayList<>();
2492

    
2493
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2494
                String sql = MessageFormat.format(
2495
                        STMT_UPDATE_TABLE_STATISTICS_table,
2496
                        table.toString(formatter)
2497
                );
2498
                if (!StringUtils.isEmpty(sql)) {
2499
                    sqls.add(sql);
2500
                }
2501
            }
2502
            return sqls;
2503
        }
2504
    }
2505

    
2506
    protected GeometryExpressionBuilder expressionBuilder;
2507

    
2508
    protected String defaultSchema;
2509
    protected boolean supportSchemas;
2510
    protected boolean hasSpatialFunctions;
2511
    protected GeometrySupportType geometrySupportType;
2512
    protected boolean allowAutomaticValues;
2513

    
2514
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2515

    
2516
    protected String constant_true = "(1=1)";
2517
    protected String constant_false = "(1<>1)";
2518

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

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

    
2552
    public SQLBuilderBase() {
2553
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2554

    
2555
        this.hasSpatialFunctions = false;
2556
        this.supportSchemas = true;
2557
        this.geometrySupportType = GeometrySupportType.WKT;
2558

    
2559
        this.defaultSchema = "public";
2560
        this.allowAutomaticValues = true;
2561

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

    
2576
    public String quote_for_identifiers() {
2577
        return "\"";
2578
    }
2579

    
2580
    public String quote_for_strings() {
2581
        return "'";
2582
    }
2583

    
2584
    @Override
2585
    public String as_identifier(String id) {
2586
        String quote = this.quote_for_identifiers();
2587
//        No se porque no esta disponible wrapIfMissing
2588
//        return StringUtils.wrapIfMissing(id,quote);
2589
        if (id.startsWith(quote)) {
2590
            return id;
2591
        }
2592
        return quote + id + quote;
2593

    
2594
    }
2595

    
2596
    @Override
2597
    public String as_string(String s) {
2598
        String quote = this.quote_for_strings();
2599
//        No se porque no esta disponible wrapIfMissing
2600
//        return StringUtils.wrapIfMissing(id,quote);
2601
        if (s.startsWith(quote)) {
2602
            return s;
2603
        }
2604
        return quote + s + quote;
2605

    
2606
    }
2607

    
2608
    @Override
2609
    public String as_string(byte[] data) {
2610
        return this.expressionBuilder.bytearray_0x(data);
2611
//        return this.expressionBuilder.bytearray_hex(data);
2612
//        return this.expressionBuilder.bytearray_x(data);
2613
    }
2614
    
2615
    @Override
2616
    public String as_string(boolean value) {
2617
        return value? "TRUE" : "FALSE";
2618
    }
2619

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

    
2650
    @Override
2651
    public boolean has_spatial_functions() {
2652
        return this.hasSpatialFunctions;
2653
    }
2654

    
2655
    @Override
2656
    public GeometrySupportType geometry_support_type() {
2657
        return this.geometrySupportType;
2658
    }
2659

    
2660
    protected GeometryExpressionBuilder createExpressionBuilder() {
2661
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2662
    }
2663

    
2664
    @Override
2665
    public Object srs_id(IProjection projection) {
2666
        String abrev = projection.getAbrev();
2667
        return abrev.split(":")[1].trim();
2668
    }
2669

    
2670
    @Override
2671
    public String default_schema() {
2672
        return this.defaultSchema;
2673
    }
2674

    
2675
    @Override
2676
    public boolean support_schemas() {
2677
        return this.supportSchemas;
2678
    }
2679

    
2680
    @Override
2681
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2682
        switch (type) {
2683
            case DataTypes.BOOLEAN:
2684
                return type_boolean;
2685
            case DataTypes.CHAR:
2686
                return type_char;
2687

    
2688

    
2689
            case DataTypes.BYTE:
2690
                return type_byte;
2691
            case DataTypes.INT:
2692
                return type_int;
2693
            case DataTypes.LONG:
2694
                return type_long;
2695

    
2696
            case DataTypes.FLOAT:
2697
                return type_float;
2698
            case DataTypes.DOUBLE:
2699
                return type_double;
2700
            case DataTypes.DECIMAL:
2701
                if (precision < 1) {
2702
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2703
                }
2704
                if (scale < 1) {
2705
                  return MessageFormat.format(type_decimal_p, precision);
2706
                }
2707
                return MessageFormat.format(type_decimal_ps, precision, scale);
2708

    
2709
                
2710
            case DataTypes.STRING:
2711
                if (size < 0) {
2712
                    return type_string;
2713
                } else if (size < 4096) {
2714
                    return MessageFormat.format(type_string_p, size);
2715
                }
2716
                return type_string;
2717

    
2718
                
2719
            case DataTypes.DATE:
2720
                return type_date;
2721
            case DataTypes.TIME:
2722
                return type_time;
2723
            case DataTypes.TIMESTAMP:
2724
                return type_timestamp;
2725

    
2726
            case DataTypes.BYTEARRAY:
2727
                return type_bytearray;
2728

    
2729
            case DataTypes.GEOMETRY:
2730
                return type_geometry;
2731

    
2732
            case DataTypes.VERSION:
2733
                return type_version;
2734
            case DataTypes.URI:
2735
                return type_URI;
2736
            case DataTypes.URL:
2737
                return type_URL;
2738
            case DataTypes.FILE:
2739
                return type_FILE;
2740
            case DataTypes.FOLDER:
2741
                return type_FOLDER;
2742
            default:
2743
                return null;
2744
        }
2745
    }
2746

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

    
2759
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2760
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2761
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2762
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2763

    
2764
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2765
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2766
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2767
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2768

    
2769
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2770
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2771
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2772
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2773

    
2774
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2775
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2776
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2777
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2778

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

    
2784
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2785
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2786
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2787
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2788

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

    
2794
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2795
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2796
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2797
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2798
        }
2799
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2800
    }
2801

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

    
2820
    @Override
2821
    public TableNameBuilder createTableNameBuilder() {
2822
        return new TableNameBuilderBase();
2823
    }
2824

    
2825
    protected SelectColumnBuilder createSelectColumnBuilder() {
2826
        return new SelectColumnBuilderBase();
2827
    }
2828

    
2829
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2830
        return new UpdateColumnBuilderBase();
2831
    }
2832

    
2833
    protected InsertColumnBuilder createInsertColumnBuilder() {
2834
        return new InsertColumnBuilderBase();
2835
    }
2836

    
2837
    protected OrderByBuilder createOrderByBuilder() {
2838
        return new OrderByBuilderBase();
2839
    }
2840

    
2841
    protected FromBuilder createFromBuilder() {
2842
        return new FromBuilderBase();
2843
    }
2844

    
2845
    protected SelectBuilder createSelectBuilder() {
2846
        return new SelectBuilderBase();
2847
    }
2848

    
2849
    protected UpdateBuilder createUpdateBuilder() {
2850
        return new UpdateBuilderBase();
2851
    }
2852

    
2853
    protected DeleteBuilder createDeleteBuilder() {
2854
        return new DeleteBuilderBase();
2855
    }
2856

    
2857
    protected GrantBuilder createGrantBuilder() {
2858
        return new GrantBuilderBase();
2859
    }
2860

    
2861
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2862
        return new GrantRoleBuilderBase(table, role);
2863
    }
2864

    
2865
    protected DropTableBuilder createDropTableBuilder() {
2866
        return new DropTableBuilderBase();
2867
    }
2868

    
2869
    protected CreateTableBuilder createCreateTableBuilder() {
2870
        return new CreateTableBuilderBase();
2871
    }
2872

    
2873
    protected AlterTableBuilder createAlterTableBuilder() {
2874
        return new AlterTableBuilderBase();
2875
    }
2876

    
2877
    protected InsertBuilder createInsertBuilder() {
2878
        return new InsertBuilderBase();
2879
    }
2880

    
2881
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2882
        return new UpdateTableStatisticsBuilderBase();
2883
    }
2884

    
2885
    protected CreateIndexBuilder createCreateIndexBuilder() {
2886
        return new CreateIndexBuilderBase();
2887
    }
2888

    
2889
    @Override
2890
    public SelectBuilder select() {
2891
        if (this.select == null) {
2892
            this.select = this.createSelectBuilder();
2893
        }
2894
        return this.select;
2895
    }
2896

    
2897
    @Override
2898
    public UpdateBuilder update() {
2899
        if (this.update == null) {
2900
            this.update = this.createUpdateBuilder();
2901
        }
2902
        return this.update;
2903
    }
2904

    
2905
    @Override
2906
    public UpdateTableStatisticsBuilder update_table_statistics() {
2907
        if (this.update_table_statistics == null) {
2908
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2909
        }
2910
        return this.update_table_statistics;
2911
    }
2912

    
2913
    @Override
2914
    public DropTableBuilder drop_table() {
2915
        if (this.drop_table == null) {
2916
            this.drop_table = this.createDropTableBuilder();
2917
        }
2918
        return this.drop_table;
2919
    }
2920

    
2921
    @Override
2922
    public CreateIndexBuilder create_index() {
2923
        if (this.create_index == null) {
2924
            this.create_index = this.createCreateIndexBuilder();
2925
        }
2926
        return this.create_index;
2927
    }
2928

    
2929
    @Override
2930
    public DeleteBuilder delete() {
2931
        if (this.delete == null) {
2932
            this.delete = this.createDeleteBuilder();
2933
        }
2934
        return this.delete;
2935
    }
2936

    
2937
    @Override
2938
    public InsertBuilder insert() {
2939
        if (this.insert == null) {
2940
            this.insert = this.createInsertBuilder();
2941
        }
2942
        return this.insert;
2943
    }
2944

    
2945
    @Override
2946
    public TableNameBuilder table_name() {
2947
        if (this.table_name == null) {
2948
            this.table_name = this.createTableNameBuilder();
2949
        }
2950
        return this.table_name;
2951
    }
2952

    
2953
    
2954
    @Override
2955
    public AlterTableBuilder alter_table() {
2956
        if (this.alter_table == null) {
2957
            this.alter_table = this.createAlterTableBuilder();
2958
        }
2959
        return this.alter_table;
2960
    }
2961

    
2962
    @Override
2963
    public CreateTableBuilder create_table() {
2964
        if (this.create_table == null) {
2965
            this.create_table = this.createCreateTableBuilder();
2966
        }
2967
        return this.create_table;
2968
    }
2969

    
2970
    @Override
2971
    public GrantBuilder grant() {
2972
        if (this.grant == null) {
2973
            this.grant = this.createGrantBuilder();
2974
        }
2975
        return this.grant;
2976
    }
2977
    
2978
    @Override
2979
    public Column column(String name) {
2980
        ColumnBase col = new ColumnBase(null, name);
2981
        return col;
2982
    }
2983

    
2984
    @Override
2985
    public Column column(TableNameBuilder table, String name) {
2986
        ColumnBase col = new ColumnBase(table, name);
2987
        return col;
2988
    }
2989
    
2990
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2991
        return new JoinBase(type, table, expression);
2992
    }
2993

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

    
3021
    protected Formatter formatter() {
3022
        return expression().formatter();
3023
    }
3024

    
3025
    @Override
3026
    public String toString() {
3027
        return this.toString(formatter());
3028
    }
3029

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

    
3062
    @Override
3063
    public CountBuilder count() {
3064
        return new CountBuilderBase();
3065
    }
3066

    
3067
    @Override
3068
    public List<Parameter> parameters() {
3069
        final List<Parameter> params = new ArrayList<>();
3070
        this.accept(new Visitor() {
3071
            @Override
3072
            public void visit(Visitable value) {
3073
                params.add((Parameter) value);
3074
            }
3075
        }, new ClassVisitorFilter(Parameter.class));
3076
        return params;
3077
    }
3078

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

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

    
3118
    @Override
3119
    public List<String> variables_names() {
3120
        List<String> vars = new ArrayList<>();
3121
        for (Variable var : this.variables()) {
3122
            vars.add(var.name());
3123
        }
3124
        Collections.sort(vars);
3125
        return vars;
3126
    }
3127
}