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

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
            return this.name.name();
773
        }
774

    
775
        @Override
776
        public String getAlias() {
777
            return this.alias;
778
        }
779

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

    
785
        @Override
786
        public String toString() {
787
            return this.toString(formatter());
788
        }
789

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

    
826
    public class OrderByBuilderBase
827
            extends AbstractStatementPart
828
            implements OrderByBuilder {
829

    
830
        protected Value value;
831
        protected String custom;
832
        protected boolean ascending;
833

    
834
        public OrderByBuilderBase() {
835
            this.ascending = true;
836
        }
837

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

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

    
866
        @Override
867
        public OrderByBuilder ascending() {
868
            this.ascending = true;
869
            return this;
870
        }
871

    
872
        @Override
873
        public OrderByBuilder ascending(boolean asc) {
874
            this.ascending = asc;
875
            return this;
876
        }
877

    
878
        @Override
879
        public OrderByBuilder descending() {
880
            this.ascending = false;
881
            return this;
882
        }
883

    
884
        @Override
885
        public String toString() {
886
            return this.toString(formatter());
887
        }
888

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

    
904
    public class SelectBuilderBase
905
            extends AbstractStatement
906
            implements SelectBuilder {
907

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

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

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

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

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

    
1014
        @Override
1015
        public SelectBuilder distinct() {
1016
            this.distinct = true;
1017
            return this;
1018
        }
1019

    
1020
        @Override
1021
        public SelectColumnBuilder column() {
1022
            SelectColumnBuilder builder = createSelectColumnBuilder();
1023
            this.columns.add(builder);
1024
            return builder;
1025
        }
1026

    
1027
        @Override
1028
        public SelectBuilder remove_all_columns() {
1029
            this.columns = new ArrayList<>();
1030
            return this;
1031
        }
1032
        
1033
        @Override
1034
        public boolean has_column(String name) {
1035
            for (SelectColumnBuilder column : columns) {
1036
                if (name.equals(column.getName())) {
1037
                    return true;
1038
                }
1039
            }
1040
            return false;
1041
        }
1042

    
1043
        @Override
1044
        public FromBuilder from() {
1045
            if (this.from == null) {
1046
                this.from = createFromBuilder();
1047
            }
1048
            return this.from;
1049
        }
1050

    
1051
        @Override
1052
        public boolean has_from() {
1053
            return this.from != null;
1054
        }
1055

    
1056
        @Override
1057
        public GeometryExpressionBuilder where() {
1058
            if (this.where == null) {
1059
                this.where = createExpressionBuilder();
1060
            }
1061
            return this.where;
1062
        }
1063

    
1064
        @Override
1065
        public boolean has_where() {
1066
            if (this.where == null) {
1067
                return false;
1068
            }
1069
            return this.where.value() != null;
1070
        }
1071

    
1072
        @Override
1073
        public SelectBuilder limit(long limit) {
1074
            this.limit = limit;
1075
            return this;
1076
        }
1077

    
1078
        @Override
1079
        public SelectBuilder limit(Long limit) {
1080
            if (limit == null) {
1081
                this.limit = 0;
1082
            } else {
1083
                this.limit = limit;
1084
            }
1085
            return this;
1086
        }
1087

    
1088
        @Override
1089
        public boolean has_limit() {
1090
            return this.limit > 0;
1091
        }
1092

    
1093
        @Override
1094
        public SelectBuilder offset(long offset) {
1095
            this.offset = offset;
1096
            return this;
1097
        }
1098

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

    
1104
        @Override
1105
        public OrderByBuilder order_by() {
1106
            if (this.order_by == null) {
1107
                this.order_by = new ArrayList<>();
1108
            }
1109
            OrderByBuilder order = createOrderByBuilder();
1110
            this.order_by.add(order);
1111
            return order;
1112
        }
1113

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

    
1152
        @Override
1153
        public String toString() {
1154
            return this.toString(formatter());
1155
        }
1156

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

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

    
1209
            if (this.has_limit()) {
1210
                builder.append(" LIMIT ");
1211
                builder.append(this.limit);
1212
            }
1213
            if (this.has_offset()) {
1214
                builder.append(" OFFSET ");
1215
                builder.append(this.offset);
1216
            }
1217
            return builder.toString();
1218

    
1219
        }
1220
    }
1221

    
1222
    public class DropTableBuilderBase
1223
            extends AbstractStatement
1224
            implements DropTableBuilder {
1225

    
1226
        protected TableNameBuilder table;
1227

    
1228
        @Override
1229
        public TableNameBuilder table() {
1230
            if (table == null) {
1231
                table = createTableNameBuilder();
1232
            }
1233
            return table;
1234
        }
1235

    
1236
        @Override
1237
        public void accept(Visitor visitor, VisitorFilter filter) {
1238
            if (filter==null || filter.accept(this)) {
1239
                visitor.visit(this);
1240
            }
1241
            this.table.accept(visitor, filter);
1242
        }
1243

    
1244
        @Override
1245
        public String toString() {
1246
            return this.toString(formatter());
1247
        }
1248

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

    
1270
        @Override
1271
        public List<String> toStrings() {
1272
            return this.toStrings(formatter());
1273
        }
1274

    
1275
        @Override
1276
        public List<String> toStrings(Formatter formatter) {
1277
            List<String> sqls = new ArrayList<>();
1278

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

    
1307
    public class GrantRoleBuilderBase
1308
            extends AbstractStatementPart
1309
            implements GrantRoleBuilder {
1310

    
1311
        protected TableNameBuilder table;
1312
        protected String role;
1313
        protected Set<Privilege> privileges;
1314

    
1315
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1316
            this.table = table;
1317
            this.role = role;
1318
            this.privileges = new HashSet<>();
1319
        }
1320

    
1321
        @Override
1322
        public GrantRoleBuilder privilege(Privilege privilege) {
1323
            privileges.add(privilege);
1324
            return this;
1325
        }
1326

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

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

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

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

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

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

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

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

    
1375
        protected String getPrivilegeName(Privilege privilege) {
1376
            switch (privilege) {
1377
                case DELETE:
1378
                    return "DELETE";
1379
                case INSERT:
1380
                    return "INSERT";
1381
                case REFERENCE:
1382
                    return "REFERENCE";
1383
                case SELECT:
1384
                    return "SELECT";
1385
                case TRIGGER:
1386
                    return "TRIGGER";
1387
                case TRUNCATE:
1388
                    return "TRUNCATE";
1389
                case UPDATE:
1390
                    return "UPDATE";
1391
                case ALL:
1392
                default:
1393
                    return "ALL";
1394
            }
1395
        }
1396

    
1397
        @Override
1398
        public String toString() {
1399
            return this.toString(formatter());
1400
        }
1401

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

    
1427
    public class GrantBuilderBase
1428
            extends AbstractStatement
1429
            implements GrantBuilder {
1430

    
1431
        protected TableNameBuilder table;
1432
        protected Map<String, GrantRoleBuilder> roles;
1433

    
1434
        public GrantBuilderBase() {
1435
            this.roles = new HashMap<>();
1436
        }
1437

    
1438
        @Override
1439
        public TableNameBuilder table() {
1440
            if (table == null) {
1441
                table = createTableNameBuilder();
1442
            }
1443
            return table;
1444
        }
1445

    
1446
        @Override
1447
        public void accept(Visitor visitor, VisitorFilter filter) {
1448
            if (filter==null || filter.accept(this)) {
1449
                visitor.visit(this);
1450
            }
1451
            if (this.table != null) {
1452
                this.table.accept(visitor, filter);
1453
            }
1454
        }
1455

    
1456
        @Override
1457
        public GrantRoleBuilder role(String role) {
1458
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1459
            if (roleBuilder == null) {
1460
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1461
                this.roles.put(role, roleBuilder);
1462
            }
1463
            return roleBuilder;
1464
        }
1465

    
1466
        @Override
1467
        public String toString() {
1468
            return this.toString(formatter());
1469
        }
1470

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

    
1492
        @Override
1493
        public List<String> toStrings() {
1494
            return this.toStrings(formatter());
1495
        }
1496

    
1497
        @Override
1498
        public List<String> toStrings(Formatter formatter) {
1499
            List<String> sqls = new ArrayList<>();
1500
            for (GrantRoleBuilder role : roles.values()) {
1501
                sqls.add(role.toString(formatter));
1502
            }
1503
            return sqls;
1504
        }
1505
    }
1506

    
1507
    public class UpdateColumnBuilderBase
1508
            extends InsertColumnBuilderBase
1509
            implements UpdateColumnBuilder {
1510

    
1511
        public UpdateColumnBuilderBase() {
1512
            super();
1513
        }
1514

    
1515
        @Override
1516
        public UpdateColumnBuilder name(String name) {
1517
            return (UpdateColumnBuilder) super.name(name);
1518
        }
1519

    
1520
        @Override
1521
        public UpdateColumnBuilder with_value(Value value) {
1522
            return (UpdateColumnBuilder) super.with_value(value);
1523
        }
1524

    
1525
    }
1526

    
1527
    public class UpdateBuilderBase
1528
            extends AbstractStatement
1529
            implements UpdateBuilder {
1530

    
1531
        protected GeometryExpressionBuilder where;
1532
        protected List<UpdateColumnBuilder> columns;
1533
        protected TableNameBuilder table;
1534

    
1535
        public UpdateBuilderBase() {
1536
            this.columns = new ArrayList<>();
1537
        }
1538

    
1539
        @Override
1540
        public void accept(Visitor visitor, VisitorFilter filter) {
1541
            if (filter==null || filter.accept(this)) {
1542
                visitor.visit(this);
1543
            }
1544
            if (this.table != null) {
1545
                this.table.accept(visitor, filter);
1546
            }
1547
            for (UpdateColumnBuilder column : columns) {
1548
                column.accept(visitor, filter);
1549
            }
1550
            if (this.has_where()) {
1551
                this.where.accept(visitor, filter);
1552
            }
1553
        }
1554

    
1555
        @Override
1556
        public GeometryExpressionBuilder where() {
1557
            if (this.where == null) {
1558
                this.where = createExpressionBuilder();
1559
            }
1560
            return this.where;
1561
        }
1562

    
1563
        @Override
1564
        public TableNameBuilder table() {
1565
            if (table == null) {
1566
                table = createTableNameBuilder();
1567
            }
1568
            return table;
1569
        }
1570

    
1571
        @Override
1572
        public UpdateColumnBuilder column() {
1573
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1574
            this.columns.add(column);
1575
            return column;
1576
        }
1577

    
1578
        @Override
1579
        public boolean has_where() {
1580
            return this.where != null;
1581
        }
1582

    
1583
        @Override
1584
        public String toString() {
1585
            return this.toString(formatter());
1586
        }
1587

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

    
1601
            boolean first = true;
1602
            for (UpdateColumnBuilder column : columns) {
1603
                if (first) {
1604
                    first = false;
1605
                } else {
1606
                    columnsAndValues.append(", ");
1607
                }
1608
                columnsAndValues.append(as_identifier(column.getName()));
1609
                columnsAndValues.append(" = ");
1610
                columnsAndValues.append(column.getValue().toString(formatter));
1611
            }
1612

    
1613
            String sql;
1614
            if (this.has_where()) {
1615
                sql = MessageFormat.format(
1616
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1617
                        this.table.toString(formatter),
1618
                        columnsAndValues.toString(),
1619
                        this.where.toString(formatter)
1620
                );
1621
            } else {
1622
                sql = MessageFormat.format(
1623
                        STMT_UPDATE_table_SET_columnsAndValues,
1624
                        this.table.toString(formatter),
1625
                        columnsAndValues.toString()
1626
                );
1627
            }
1628
            return sql;
1629
        }
1630
    }
1631

    
1632
    public class DeleteBuilderBase
1633
            extends AbstractStatement
1634
            implements DeleteBuilder {
1635

    
1636
        protected GeometryExpressionBuilder where;
1637
        protected TableNameBuilder table;
1638

    
1639
        public DeleteBuilderBase() {
1640
        }
1641

    
1642
        @Override
1643
        public void accept(Visitor visitor, VisitorFilter filter) {
1644
            if (filter==null || filter.accept(this)) {
1645
                visitor.visit(this);
1646
            }
1647
            if (this.table != null) {
1648
                this.table.accept(visitor, filter);
1649
            }
1650
            if (this.has_where()) {
1651
                this.where.accept(visitor, filter);
1652
            }
1653
        }
1654

    
1655
        @Override
1656
        public GeometryExpressionBuilder where() {
1657
            if (this.where == null) {
1658
                this.where = createExpressionBuilder();
1659
            }
1660
            return this.where;
1661
        }
1662

    
1663
        @Override
1664
        public TableNameBuilder table() {
1665
            if (table == null) {
1666
                table = createTableNameBuilder();
1667
            }
1668
            return table;
1669
        }
1670

    
1671
        @Override
1672
        public boolean has_where() {
1673
            return this.where != null;
1674
        }
1675

    
1676
        @Override
1677
        public String toString() {
1678
            return this.toString(formatter());
1679
        }
1680

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

    
1707
    public class CreateIndexBuilderBase
1708
            extends AbstractStatement
1709
            implements CreateIndexBuilder {
1710

    
1711
        protected boolean ifNotExist = false;
1712
        protected boolean isUnique = false;
1713
        protected String indexName;
1714
        protected boolean isSpatial = false;
1715
        protected TableNameBuilder table;
1716
        protected final List<String> columns;
1717

    
1718
        public CreateIndexBuilderBase() {
1719
            this.columns = new ArrayList<>();
1720
        }
1721

    
1722
        @Override
1723
        public CreateIndexBuilder unique() {
1724
            this.isUnique = true;
1725
            return this;
1726
        }
1727

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

    
1734
        @Override
1735
        public CreateIndexBuilder name(String name) {
1736
            this.indexName = name;
1737
            return this;
1738
        }
1739

    
1740
        @Override
1741
        public CreateIndexBuilder spatial() {
1742
            this.isSpatial = true;
1743
            return this;
1744
        }
1745

    
1746
        @Override
1747
        public CreateIndexBuilder column(String name) {
1748
            this.columns.add(name);
1749
            return this;
1750
        }
1751

    
1752
        @Override
1753
        public TableNameBuilder table() {
1754
            if (table == null) {
1755
                table = createTableNameBuilder();
1756
            }
1757
            return table;
1758
        }
1759

    
1760
        @Override
1761
        public void accept(Visitor visitor, VisitorFilter filter) {
1762
            if (filter==null || filter.accept(this)) {
1763
                visitor.visit(this);
1764
            }
1765
            if (this.table != null) {
1766
                this.table.accept(visitor, filter);
1767
            }
1768
        }
1769

    
1770
        @Override
1771
        public String toString() {
1772
            return this.toString(formatter());
1773
        }
1774

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

    
1796
        @Override
1797
        public List<String> toStrings() {
1798
            return this.toStrings(formatter());
1799
        }
1800

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

    
1830
            List<String> sqls = new ArrayList<>();
1831
            sqls.add(builder.toString());
1832
            return sqls;
1833
        }
1834

    
1835
    }
1836

    
1837
    public class AlterTableBuilderBase
1838
            extends AbstractStatement
1839
            implements AlterTableBuilder {
1840

    
1841
        protected TableNameBuilder table;
1842
        protected List<String> drops;
1843
        protected List<ColumnDescriptor> adds;
1844
        protected List<ColumnDescriptor> alters;
1845
        protected List<Pair<String, String>> renames;
1846

    
1847
        public AlterTableBuilderBase() {
1848
            this.drops = new ArrayList<>();
1849
            this.adds = new ArrayList<>();
1850
            this.alters = new ArrayList<>();
1851
            this.renames = new ArrayList<>();
1852
        }
1853

    
1854
        @Override
1855
        public boolean isEmpty() {
1856
            return this.drops.isEmpty()
1857
                    && this.adds.isEmpty()
1858
                    && this.alters.isEmpty()
1859
                    && this.renames.isEmpty();
1860
        }
1861

    
1862
        @Override
1863
        public void accept(Visitor visitor, VisitorFilter filter) {
1864
            if (filter==null || filter.accept(this)) {
1865
                visitor.visit(this);
1866
            }
1867
            if (this.table != null) {
1868
                this.table.accept(visitor, filter);
1869
            }
1870
        }
1871

    
1872
        @Override
1873
        public TableNameBuilder table() {
1874
            if (table == null) {
1875
                table = createTableNameBuilder();
1876
            }
1877
            return table;
1878
        }
1879

    
1880
        @Override
1881
        public AlterTableBuilder drop_column(String columnName) {
1882
            this.drops.add(columnName);
1883
            return this;
1884
        }
1885

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

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

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

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

    
1919
        @Override
1920
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1921
            this.alters.add(new ColumnDescriptorBase(fad));
1922
            return this;
1923
        }
1924

    
1925
        @Override
1926
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1927
            if (isPk || isAutomatic) {
1928
                allowNulls = false;
1929
            }
1930
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1931
            return this;
1932
        }
1933

    
1934
        @Override
1935
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1936
            if (StringUtils.isEmpty(columnName)) {
1937
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1938
            }
1939
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1940
            return this;
1941
        }
1942

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

    
1952
        @Override
1953
        public AlterTableBuilder rename_column(String source, String target) {
1954
            this.renames.add(new ImmutablePair(source, target));
1955
            return this;
1956
        }
1957

    
1958
        @Override
1959
        public String toString() {
1960
            return this.toString(formatter());
1961
        }
1962

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

    
1984
        @Override
1985
        public List<String> toStrings() {
1986
            return this.toStrings(formatter());
1987
        }
1988

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

    
2090
    }
2091

    
2092
    public class CreateTableBuilderBase
2093
            extends AbstractStatement
2094
            implements CreateTableBuilder {
2095

    
2096
        protected TableNameBuilder table;
2097
        protected List<ColumnDescriptor> columns;
2098

    
2099
        public CreateTableBuilderBase() {
2100
            this.columns = new ArrayList<>();
2101
        }
2102

    
2103
        @Override
2104
        public void accept(Visitor visitor, VisitorFilter filter) {
2105
            if (filter==null || filter.accept(this)) {
2106
                visitor.visit(this);
2107
            }
2108
            if (this.table != null) {
2109
                this.table.accept(visitor, filter);
2110
            }
2111
        }
2112

    
2113
        @Override
2114
        public TableNameBuilder table() {
2115
            if (table == null) {
2116
                table = createTableNameBuilder();
2117
            }
2118
            return table;
2119
        }
2120

    
2121
        @Override
2122
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2123
            this.columns.add(new ColumnDescriptorBase(fad));
2124
            return this;
2125
        }
2126

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

    
2139
        @Override
2140
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2141
            if (StringUtils.isEmpty(columnName)) {
2142
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2143
            }
2144
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2145
            return this;
2146
        }
2147

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

    
2157
        @Override
2158
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2159
            if (StringUtils.isEmpty(columnName)) {
2160
                return null;
2161
            }
2162
            for (ColumnDescriptor column : columns) {
2163
                if (columnName.equals(column.getName())) {
2164
                    return column;
2165
                }
2166
            }
2167
            return null;
2168
        }
2169

    
2170
        @Override
2171
        public String toString() {
2172
            return this.toString(formatter());
2173
        }
2174

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

    
2196
        @Override
2197
        public List<String> toStrings() {
2198
            return this.toStrings(formatter());
2199
        }
2200

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

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

    
2282
    public class InsertColumnBuilderBase
2283
            extends AbstractStatement
2284
            implements InsertColumnBuilder {
2285

    
2286
        protected Variable name;
2287
        protected Value value;
2288

    
2289
        public InsertColumnBuilderBase() {
2290
        }
2291

    
2292
        @Override
2293
        public void accept(Visitor visitor, VisitorFilter filter) {
2294
            if (filter==null || filter.accept(this)) {
2295
                visitor.visit(this);
2296
            }
2297
            if (this.name != null) {
2298
                this.name.accept(visitor, filter);
2299
            }
2300
            if (this.value != null) {
2301
                this.value.accept(visitor, filter);
2302
            }
2303
        }
2304

    
2305
        @Override
2306
        public InsertColumnBuilder name(String name) {
2307
            this.name = expression().variable(name);
2308
            return this;
2309
        }
2310

    
2311
        @Override
2312
        public InsertColumnBuilder with_value(Value value) {
2313
            this.value = value;
2314
            return this;
2315
        }
2316

    
2317
        @Override
2318
        public String getName() {
2319
            return this.name.name();
2320
        }
2321

    
2322
        @Override
2323
        public Value getValue() {
2324
            return this.value;
2325
        }
2326

    
2327
        @Override
2328
        public String toString() {
2329
            return this.toString(formatter());
2330
        }
2331

    
2332
        @Override
2333
        public String toString(Formatter<Value> formatter) {
2334
            if (formatter!=null && formatter.canApply(this)) {
2335
                return formatter.format(this);
2336
            }
2337
            return this.value.toString(formatter);
2338
        }
2339
    }
2340

    
2341
    public class InsertBuilderBase
2342
            extends AbstractStatement
2343
            implements InsertBuilder {
2344

    
2345
        protected List<InsertColumnBuilder> columns;
2346
        protected TableNameBuilder table;
2347

    
2348
        public InsertBuilderBase() {
2349
            this.columns = new ArrayList<>();
2350
        }
2351

    
2352
        @Override
2353
        public void accept(Visitor visitor, VisitorFilter filter) {
2354
            if (filter==null || filter.accept(this)) {
2355
                visitor.visit(this);
2356
            }
2357
            if (this.table != null) {
2358
                this.table.accept(visitor, filter);
2359
            }
2360
            for (InsertColumnBuilder column : columns) {
2361
                column.accept(visitor, filter);
2362
            }
2363
        }
2364

    
2365
        @Override
2366
        public TableNameBuilder table() {
2367
            if (table == null) {
2368
                table = createTableNameBuilder();
2369
            }
2370
            return table;
2371
        }
2372

    
2373
        @Override
2374
        public InsertColumnBuilder column() {
2375
            InsertColumnBuilder column = createInsertColumnBuilder();
2376
            this.columns.add(column);
2377
            return column;
2378
        }
2379

    
2380
        @Override
2381
        public String toString() {
2382
            return this.toString(formatter());
2383
        }
2384

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

    
2398
            boolean first = true;
2399
            for (InsertColumnBuilder column : columns) {
2400
                if (first) {
2401
                    first = false;
2402
                } else {
2403
                    builderColumns.append(", ");
2404
                }
2405
                builderColumns.append(as_identifier(column.getName()));
2406
            }
2407
            first = true;
2408
            for (InsertColumnBuilder column : columns) {
2409
                if (first) {
2410
                    first = false;
2411
                } else {
2412
                    builderValues.append(", ");
2413
                }
2414
                builderValues.append(column.toString(formatter));
2415
            }
2416

    
2417
            String sql = MessageFormat.format(
2418
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2419
                    this.table.toString(formatter),
2420
                    builderColumns.toString(),
2421
                    builderValues.toString()
2422
            );
2423
            return sql;
2424

    
2425
        }
2426
    }
2427

    
2428
    public class UpdateTableStatisticsBuilderBase
2429
            extends AbstractStatement
2430
            implements UpdateTableStatisticsBuilder {
2431

    
2432
        protected TableNameBuilder table;
2433

    
2434
        @Override
2435
        public void accept(Visitor visitor, VisitorFilter filter) {
2436
            if (filter==null || filter.accept(this)) {
2437
                visitor.visit(this);
2438
            }
2439
            if (this.table != null) {
2440
                this.table.accept(visitor, filter);
2441
            }
2442
        }
2443

    
2444
        @Override
2445
        public TableNameBuilder table() {
2446
            if (table == null) {
2447
                table = createTableNameBuilder();
2448
            }
2449
            return table;
2450
        }
2451

    
2452
        @Override
2453
        public String toString() {
2454
            return this.toString(formatter());
2455
        }
2456

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

    
2478
        @Override
2479
        public List<String> toStrings() {
2480
            return this.toStrings(formatter());
2481
        }
2482

    
2483
        @Override
2484
        public List<String> toStrings(Formatter formatter) {
2485
            List<String> sqls = new ArrayList<>();
2486

    
2487
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2488
                String sql = MessageFormat.format(
2489
                        STMT_UPDATE_TABLE_STATISTICS_table,
2490
                        table.toString(formatter)
2491
                );
2492
                if (!StringUtils.isEmpty(sql)) {
2493
                    sqls.add(sql);
2494
                }
2495
            }
2496
            return sqls;
2497
        }
2498
    }
2499

    
2500
    protected GeometryExpressionBuilder expressionBuilder;
2501

    
2502
    protected String defaultSchema;
2503
    protected boolean supportSchemas;
2504
    protected boolean hasSpatialFunctions;
2505
    protected GeometrySupportType geometrySupportType;
2506
    protected boolean allowAutomaticValues;
2507

    
2508
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2509

    
2510
    protected String constant_true = "(1=1)";
2511
    protected String constant_false = "(1<>1)";
2512

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

    
2535
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2536
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2537
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2538
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2539
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2540
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2541
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2542
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2543
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2544
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2545

    
2546
    public SQLBuilderBase() {
2547
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2548

    
2549
        this.hasSpatialFunctions = false;
2550
        this.supportSchemas = true;
2551
        this.geometrySupportType = GeometrySupportType.WKT;
2552

    
2553
        this.defaultSchema = "public";
2554
        this.allowAutomaticValues = true;
2555

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

    
2570
    public String quote_for_identifiers() {
2571
        return "\"";
2572
    }
2573

    
2574
    public String quote_for_strings() {
2575
        return "'";
2576
    }
2577

    
2578
    @Override
2579
    public String as_identifier(String id) {
2580
        String quote = this.quote_for_identifiers();
2581
//        No se porque no esta disponible wrapIfMissing
2582
//        return StringUtils.wrapIfMissing(id,quote);
2583
        if (id.startsWith(quote)) {
2584
            return id;
2585
        }
2586
        return quote + id + quote;
2587

    
2588
    }
2589

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

    
2600
    }
2601

    
2602
    @Override
2603
    public String as_string(byte[] data) {
2604
        return this.expressionBuilder.bytearray_0x(data);
2605
//        return this.expressionBuilder.bytearray_hex(data);
2606
//        return this.expressionBuilder.bytearray_x(data);
2607
    }
2608
    
2609
    @Override
2610
    public String as_string(boolean value) {
2611
        return value? "TRUE" : "FALSE";
2612
    }
2613

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

    
2644
    @Override
2645
    public boolean has_spatial_functions() {
2646
        return this.hasSpatialFunctions;
2647
    }
2648

    
2649
    @Override
2650
    public GeometrySupportType geometry_support_type() {
2651
        return this.geometrySupportType;
2652
    }
2653

    
2654
    protected GeometryExpressionBuilder createExpressionBuilder() {
2655
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2656
    }
2657

    
2658
    @Override
2659
    public Object srs_id(IProjection projection) {
2660
        String abrev = projection.getAbrev();
2661
        return abrev.split(":")[1].trim();
2662
    }
2663

    
2664
    @Override
2665
    public String default_schema() {
2666
        return this.defaultSchema;
2667
    }
2668

    
2669
    @Override
2670
    public boolean support_schemas() {
2671
        return this.supportSchemas;
2672
    }
2673

    
2674
    @Override
2675
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2676
        switch (type) {
2677
            case DataTypes.BOOLEAN:
2678
                return type_boolean;
2679
            case DataTypes.CHAR:
2680
                return type_char;
2681

    
2682

    
2683
            case DataTypes.BYTE:
2684
                return type_byte;
2685
            case DataTypes.INT:
2686
                return type_int;
2687
            case DataTypes.LONG:
2688
                return type_long;
2689

    
2690
            case DataTypes.FLOAT:
2691
                return type_float;
2692
            case DataTypes.DOUBLE:
2693
                return type_double;
2694
            case DataTypes.DECIMAL:
2695
                if (precision < 1) {
2696
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2697
                }
2698
                if (scale < 1) {
2699
                  return MessageFormat.format(type_decimal_p, precision);
2700
                }
2701
                return MessageFormat.format(type_decimal_ps, precision, scale);
2702

    
2703
                
2704
            case DataTypes.STRING:
2705
                if (size < 0) {
2706
                    return type_string;
2707
                } else if (size < 4096) {
2708
                    return MessageFormat.format(type_string_p, size);
2709
                }
2710
                return type_string;
2711

    
2712
                
2713
            case DataTypes.DATE:
2714
                return type_date;
2715
            case DataTypes.TIME:
2716
                return type_time;
2717
            case DataTypes.TIMESTAMP:
2718
                return type_timestamp;
2719

    
2720
            case DataTypes.BYTEARRAY:
2721
                return type_bytearray;
2722

    
2723
            case DataTypes.GEOMETRY:
2724
                return type_geometry;
2725

    
2726
            case DataTypes.VERSION:
2727
                return type_version;
2728
            case DataTypes.URI:
2729
                return type_URI;
2730
            case DataTypes.URL:
2731
                return type_URL;
2732
            case DataTypes.FILE:
2733
                return type_FILE;
2734
            case DataTypes.FOLDER:
2735
                return type_FOLDER;
2736
            default:
2737
                return null;
2738
        }
2739
    }
2740

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

    
2753
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2754
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2755
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2756
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2757

    
2758
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2759
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2760
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2761
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2762

    
2763
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2764
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2765
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2766
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2767

    
2768
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2769
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2770
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2771
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2772

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

    
2778
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2779
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2780
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2781
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2782

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

    
2788
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2789
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2790
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2791
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2792
        }
2793
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2794
    }
2795

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

    
2814
    @Override
2815
    public TableNameBuilder createTableNameBuilder() {
2816
        return new TableNameBuilderBase();
2817
    }
2818

    
2819
    protected SelectColumnBuilder createSelectColumnBuilder() {
2820
        return new SelectColumnBuilderBase();
2821
    }
2822

    
2823
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2824
        return new UpdateColumnBuilderBase();
2825
    }
2826

    
2827
    protected InsertColumnBuilder createInsertColumnBuilder() {
2828
        return new InsertColumnBuilderBase();
2829
    }
2830

    
2831
    protected OrderByBuilder createOrderByBuilder() {
2832
        return new OrderByBuilderBase();
2833
    }
2834

    
2835
    protected FromBuilder createFromBuilder() {
2836
        return new FromBuilderBase();
2837
    }
2838

    
2839
    protected SelectBuilder createSelectBuilder() {
2840
        return new SelectBuilderBase();
2841
    }
2842

    
2843
    protected UpdateBuilder createUpdateBuilder() {
2844
        return new UpdateBuilderBase();
2845
    }
2846

    
2847
    protected DeleteBuilder createDeleteBuilder() {
2848
        return new DeleteBuilderBase();
2849
    }
2850

    
2851
    protected GrantBuilder createGrantBuilder() {
2852
        return new GrantBuilderBase();
2853
    }
2854

    
2855
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2856
        return new GrantRoleBuilderBase(table, role);
2857
    }
2858

    
2859
    protected DropTableBuilder createDropTableBuilder() {
2860
        return new DropTableBuilderBase();
2861
    }
2862

    
2863
    protected CreateTableBuilder createCreateTableBuilder() {
2864
        return new CreateTableBuilderBase();
2865
    }
2866

    
2867
    protected AlterTableBuilder createAlterTableBuilder() {
2868
        return new AlterTableBuilderBase();
2869
    }
2870

    
2871
    protected InsertBuilder createInsertBuilder() {
2872
        return new InsertBuilderBase();
2873
    }
2874

    
2875
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2876
        return new UpdateTableStatisticsBuilderBase();
2877
    }
2878

    
2879
    protected CreateIndexBuilder createCreateIndexBuilder() {
2880
        return new CreateIndexBuilderBase();
2881
    }
2882

    
2883
    @Override
2884
    public SelectBuilder select() {
2885
        if (this.select == null) {
2886
            this.select = this.createSelectBuilder();
2887
        }
2888
        return this.select;
2889
    }
2890

    
2891
    @Override
2892
    public UpdateBuilder update() {
2893
        if (this.update == null) {
2894
            this.update = this.createUpdateBuilder();
2895
        }
2896
        return this.update;
2897
    }
2898

    
2899
    @Override
2900
    public UpdateTableStatisticsBuilder update_table_statistics() {
2901
        if (this.update_table_statistics == null) {
2902
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2903
        }
2904
        return this.update_table_statistics;
2905
    }
2906

    
2907
    @Override
2908
    public DropTableBuilder drop_table() {
2909
        if (this.drop_table == null) {
2910
            this.drop_table = this.createDropTableBuilder();
2911
        }
2912
        return this.drop_table;
2913
    }
2914

    
2915
    @Override
2916
    public CreateIndexBuilder create_index() {
2917
        if (this.create_index == null) {
2918
            this.create_index = this.createCreateIndexBuilder();
2919
        }
2920
        return this.create_index;
2921
    }
2922

    
2923
    @Override
2924
    public DeleteBuilder delete() {
2925
        if (this.delete == null) {
2926
            this.delete = this.createDeleteBuilder();
2927
        }
2928
        return this.delete;
2929
    }
2930

    
2931
    @Override
2932
    public InsertBuilder insert() {
2933
        if (this.insert == null) {
2934
            this.insert = this.createInsertBuilder();
2935
        }
2936
        return this.insert;
2937
    }
2938

    
2939
    @Override
2940
    public TableNameBuilder table_name() {
2941
        if (this.table_name == null) {
2942
            this.table_name = this.createTableNameBuilder();
2943
        }
2944
        return this.table_name;
2945
    }
2946

    
2947
    
2948
    @Override
2949
    public AlterTableBuilder alter_table() {
2950
        if (this.alter_table == null) {
2951
            this.alter_table = this.createAlterTableBuilder();
2952
        }
2953
        return this.alter_table;
2954
    }
2955

    
2956
    @Override
2957
    public CreateTableBuilder create_table() {
2958
        if (this.create_table == null) {
2959
            this.create_table = this.createCreateTableBuilder();
2960
        }
2961
        return this.create_table;
2962
    }
2963

    
2964
    @Override
2965
    public GrantBuilder grant() {
2966
        if (this.grant == null) {
2967
            this.grant = this.createGrantBuilder();
2968
        }
2969
        return this.grant;
2970
    }
2971
    
2972
    @Override
2973
    public Column column(String name) {
2974
        ColumnBase col = new ColumnBase(null, name);
2975
        return col;
2976
    }
2977

    
2978
    @Override
2979
    public Column column(TableNameBuilder table, String name) {
2980
        ColumnBase col = new ColumnBase(table, name);
2981
        return col;
2982
    }
2983
    
2984
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2985
        return new JoinBase(type, table, expression);
2986
    }
2987

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

    
3015
    protected Formatter formatter() {
3016
        return expression().formatter();
3017
    }
3018

    
3019
    @Override
3020
    public String toString() {
3021
        return this.toString(formatter());
3022
    }
3023

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

    
3056
    @Override
3057
    public CountBuilder count() {
3058
        return new CountBuilderBase();
3059
    }
3060

    
3061
    @Override
3062
    public List<Parameter> parameters() {
3063
        final List<Parameter> params = new ArrayList<>();
3064
        this.accept(new Visitor() {
3065
            @Override
3066
            public void visit(Visitable value) {
3067
                params.add((Parameter) value);
3068
            }
3069
        }, new ClassVisitorFilter(Parameter.class));
3070
        return params;
3071
    }
3072

    
3073
    @Override
3074
    public List<Variable> variables() {
3075
        final List<Variable> vars = new ArrayList<>();
3076
        this.accept(new Visitor() {
3077
            @Override
3078
            public void visit(Visitable value) {
3079
                if (!vars.contains((Variable) value)) {
3080
                    vars.add((Variable) value);
3081
                }
3082
            }
3083
        }, new ClassVisitorFilter(Variable.class));
3084
        return vars;
3085
    }
3086

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

    
3112
    @Override
3113
    public List<String> variables_names() {
3114
        List<String> vars = new ArrayList<>();
3115
        for (Variable var : this.variables()) {
3116
            vars.add(var.name());
3117
        }
3118
        Collections.sort(vars);
3119
        return vars;
3120
    }
3121
}