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

History | View | Annotate | Download (102 KB)

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

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

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

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

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

    
73
    protected abstract class AbstractStatementPart extends AbstractValue {
74

    
75
    }
76

    
77
    protected abstract class AbstractStatement extends AbstractStatementPart {
78

    
79
    }
80

    
81
    protected class ColumnDescriptorBase implements ColumnDescriptor {
82

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
320
    public class ColumnBase extends AbstractValue implements Column {
321

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

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

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

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

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

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

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

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

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

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

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

    
391
        public TableNameBuilderBase() {
392
        }
393

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

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

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

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

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

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

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

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

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

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

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

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

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

    
502
    }
503

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

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

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

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

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

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

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

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

    
561
    }
562

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

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

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

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

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

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

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

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

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

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

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

    
684
    }
685

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

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

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

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

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

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

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

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

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

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

    
771
        @Override
772
        public String getName() {
773
            return this.name.name();
774
        }
775

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

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

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

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

    
820
    public class OrderByBuilderBase
821
            extends AbstractStatementPart
822
            implements OrderByBuilder {
823

    
824
        protected String value;
825
        protected String custom;
826
        protected boolean ascending;
827

    
828
        public OrderByBuilderBase() {
829
            this.ascending = true;
830
        }
831

    
832
        @Override
833
        public void accept(Visitor visitor, VisitorFilter filter) {
834
            if (filter.accept(this)) {
835
                visitor.visit(this);
836
            }
837
        }
838

    
839
        @Override
840
        public OrderByBuilder column(String name) {
841
            this.value = name;
842
            return this;
843
        }
844

    
845
        @Override
846
        public OrderByBuilder custom(String order) {
847
            this.custom = order;
848
            return this;
849
        }
850

    
851
        @Override
852
        public OrderByBuilder ascending() {
853
            this.ascending = true;
854
            return this;
855
        }
856

    
857
        @Override
858
        public OrderByBuilder ascending(boolean asc) {
859
            this.ascending = asc;
860
            return this;
861
        }
862

    
863
        @Override
864
        public OrderByBuilder descending() {
865
            this.ascending = false;
866
            return this;
867
        }
868

    
869
        @Override
870
        public String toString() {
871
            return this.toString(formatter());
872
        }
873

    
874
        @Override
875
        public String toString(Formatter<Value> formatter) {
876
            if (formatter!=null && formatter.canApply(this)) {
877
                return formatter.format(this);
878
            }
879
            if (!StringUtils.isEmpty(this.custom)) {
880
                return this.custom;
881
            }
882
            if (this.ascending) {
883
                return as_identifier(this.value) + " ASC";
884
            }
885
            return as_identifier(this.value) + " DESC";
886
        }
887
    }
888

    
889
    public class SelectBuilderBase
890
            extends AbstractStatement
891
            implements SelectBuilder {
892

    
893
        protected FromBuilder from;
894
        protected GeometryExpressionBuilder where;
895
        protected long limit = -1;
896
        protected long offset = -1;
897
        protected List<SelectColumnBuilder> columns;
898
        protected List<OrderByBuilder> order_by;
899
        protected boolean distinct;
900
        protected List<Variable> groupColumn;
901
        protected boolean check_order_and_offset = true;
902

    
903
        public SelectBuilderBase() {
904
            this.columns = new ArrayList<>();
905
            this.distinct = false;
906
        }
907

    
908
        @Override
909
        public SelectBuilder group_by(Variable... columns) {
910
            if( this.groupColumn==null ) {
911
                this.groupColumn = new ArrayList<>();
912
            }
913
            for (Variable column : columns) {
914
                this.groupColumn.add(column);
915
            }
916
            return this;
917
        }
918

    
919
        @Override
920
        public void accept(Visitor visitor, VisitorFilter filter) {
921
            if (filter.accept(this)) {
922
                visitor.visit(this);
923
            }
924
            for (SelectColumnBuilder column : columns) {
925
                column.accept(visitor, filter);
926
            }
927
            if (this.has_from()) {
928
                this.from.accept(visitor, filter);
929
            }
930
            if (this.has_where()) {
931
                this.where.accept(visitor, filter);
932
            }
933
            if (this.has_order_by()) {
934
                for (OrderByBuilder order : order_by) {
935
                    order.accept(visitor, filter);
936
                }
937
            }
938
        }
939

    
940
        @Override
941
        public void replace(Value target, Value replacement) {
942
            if( this.columns!=null ) {
943
                for (int i = 0; i < columns.size(); i++) {
944
                    SelectColumnBuilder column = columns.get(i);
945
                    if( column == target ) {
946
                        columns.set(i, (SelectColumnBuilder) replacement);
947
                    } else {
948
                        column.replace(target, replacement);
949
                    }
950
                }
951
            }
952
            if (this.has_from()) {
953
                if( this.from == target ) {
954
                    this.from = (FromBuilder) replacement;
955
                } else {
956
                    this.from.replace(target, replacement);
957
                }
958
            }
959
            if (this.has_where()) {
960
                if( this.where == target ) {
961
                    this.where = (GeometryExpressionBuilder) replacement;
962
                } else if( this.where.value() == target ) {
963
                    this.where.value(replacement);
964
                } else {
965
                    this.where.value().replace(target, replacement);
966
                }
967
            }
968
            if (this.has_order_by()) {
969
                for (int i = 0; i < order_by.size(); i++) {
970
                    OrderByBuilder order = order_by.get(i);
971
                    if( order == target ) {
972
                        order_by.set(i, (OrderByBuilder) replacement);
973
                    } else {
974
                        order.replace(target, replacement);
975
                    }
976
                }
977
            }
978
        }
979

    
980
        @Override
981
        public SelectBuilder distinct() {
982
            this.distinct = true;
983
            return this;
984
        }
985

    
986
        @Override
987
        public SelectColumnBuilder column() {
988
            SelectColumnBuilder builder = createSelectColumnBuilder();
989
            this.columns.add(builder);
990
            return builder;
991
        }
992

    
993
        @Override
994
        public SelectBuilder remove_all_columns() {
995
            this.columns = new ArrayList<>();
996
            return this;
997
        }
998
        
999
        @Override
1000
        public boolean has_column(String name) {
1001
            for (SelectColumnBuilder column : columns) {
1002
                if (name.equals(column.getName())) {
1003
                    return true;
1004
                }
1005
            }
1006
            return false;
1007
        }
1008

    
1009
        @Override
1010
        public FromBuilder from() {
1011
            if (this.from == null) {
1012
                this.from = createFromBuilder();
1013
            }
1014
            return this.from;
1015
        }
1016

    
1017
        @Override
1018
        public boolean has_from() {
1019
            return this.from != null;
1020
        }
1021

    
1022
        @Override
1023
        public GeometryExpressionBuilder where() {
1024
            if (this.where == null) {
1025
                this.where = createExpressionBuilder();
1026
            }
1027
            return this.where;
1028
        }
1029

    
1030
        @Override
1031
        public boolean has_where() {
1032
            if (this.where == null) {
1033
                return false;
1034
            }
1035
            return this.where.value() != null;
1036
        }
1037

    
1038
        @Override
1039
        public SelectBuilder limit(long limit) {
1040
            this.limit = limit;
1041
            return this;
1042
        }
1043

    
1044
        @Override
1045
        public SelectBuilder limit(Long limit) {
1046
            if (limit == null) {
1047
                this.limit = 0;
1048
            } else {
1049
                this.limit = limit;
1050
            }
1051
            return this;
1052
        }
1053

    
1054
        @Override
1055
        public boolean has_limit() {
1056
            return this.limit > 0;
1057
        }
1058

    
1059
        @Override
1060
        public SelectBuilder offset(long offset) {
1061
            this.offset = offset;
1062
            return this;
1063
        }
1064

    
1065
        @Override
1066
        public boolean has_offset() {
1067
            return this.offset > 0;
1068
        }
1069

    
1070
        @Override
1071
        public OrderByBuilder order_by() {
1072
            if (this.order_by == null) {
1073
                this.order_by = new ArrayList<>();
1074
            }
1075
            OrderByBuilder order = createOrderByBuilder();
1076
            this.order_by.add(order);
1077
            return order;
1078
        }
1079

    
1080
        @Override
1081
        public boolean has_order_by() {
1082
            if (this.order_by == null) {
1083
                return false;
1084
            }
1085
            return !this.order_by.isEmpty();
1086
        }
1087
        
1088
        @Override
1089
        public boolean has_group_by() {
1090
            if (this.groupColumn == null) {
1091
                return false;
1092
            }
1093
            return !this.groupColumn.isEmpty();
1094
        }
1095
        
1096
        @Override
1097
        public void disable_check_order_and_offset() {
1098
          this.check_order_and_offset = false;
1099
        }
1100
        
1101
        protected boolean isValid(StringBuilder message) {
1102
            if (message == null) {
1103
                message = new StringBuilder();
1104
            }
1105
            if( this.check_order_and_offset ) {
1106
              if (this.has_offset() && !this.has_order_by()) {
1107
                  // Algunos gestores de BBDD requieren que se especifique un
1108
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1109
                  // asegurar que siempre tengamos los mismo resultados, lo exijimos
1110
                  // siempre.
1111
                  message.append("Can't use OFFSET without an ORDER BY.");
1112
                  return false;
1113
              }
1114
            }
1115
            return true;
1116
        }
1117

    
1118
        @Override
1119
        public String toString() {
1120
            return this.toString(formatter());
1121
        }
1122

    
1123
        @Override
1124
        public String toString(Formatter<Value> formatter) {
1125
            if (formatter!=null && formatter.canApply(this)) {
1126
                return formatter.format(this);
1127
            }
1128
            StringBuilder builder = new StringBuilder();
1129
            if (!this.isValid(builder)) {
1130
                throw new IllegalStateException(builder.toString());
1131
            }
1132
            builder.append("SELECT ");
1133
            if (this.distinct) {
1134
                builder.append("DISTINCT ");
1135
            }
1136
            boolean first = true;
1137
            for (SelectColumnBuilder column : columns) {
1138
                if (first) {
1139
                    first = false;
1140
                } else {
1141
                    builder.append(", ");
1142
                }
1143
                builder.append(column.toString(formatter));
1144
            }
1145

    
1146
            if (this.has_from()) {
1147
                builder.append(" FROM ");
1148
                builder.append(this.from.toString(formatter));
1149
            }
1150
            if (this.has_where()) {
1151
                builder.append(" WHERE ");
1152
                builder.append(this.where.toString(formatter));
1153
            }
1154
            if( this.has_group_by() ) {
1155
                builder.append(" GROUP BY ");
1156
                builder.append(this.groupColumn.get(0).toString(formatter));
1157
                for (int i = 1; i < groupColumn.size(); i++) {
1158
                    builder.append(", ");
1159
                    builder.append(this.groupColumn.get(i).toString(formatter));
1160
                }
1161
            }
1162
            if (this.has_order_by()) {
1163
                builder.append(" ORDER BY ");
1164
                first = true;
1165
                for (OrderByBuilder item : this.order_by) {
1166
                    if (first) {
1167
                        first = false;
1168
                    } else {
1169
                        builder.append(", ");
1170
                    }
1171
                    builder.append(item.toString(formatter));
1172
                }
1173
            }
1174

    
1175
            if (this.has_limit()) {
1176
                builder.append(" LIMIT ");
1177
                builder.append(this.limit);
1178
            }
1179
            if (this.has_offset()) {
1180
                builder.append(" OFFSET ");
1181
                builder.append(this.offset);
1182
            }
1183
            return builder.toString();
1184

    
1185
        }
1186
    }
1187

    
1188
    public class DropTableBuilderBase
1189
            extends AbstractStatement
1190
            implements DropTableBuilder {
1191

    
1192
        protected TableNameBuilder table;
1193

    
1194
        @Override
1195
        public TableNameBuilder table() {
1196
            if (table == null) {
1197
                table = createTableNameBuilder();
1198
            }
1199
            return table;
1200
        }
1201

    
1202
        @Override
1203
        public void accept(Visitor visitor, VisitorFilter filter) {
1204
            if (filter.accept(this)) {
1205
                visitor.visit(this);
1206
            }
1207
            this.table.accept(visitor, filter);
1208
        }
1209

    
1210
        @Override
1211
        public String toString() {
1212
            return this.toString(formatter());
1213
        }
1214

    
1215
        @Override
1216
        public String toString(Formatter<Value> formatter) {
1217
            if (formatter!=null && formatter.canApply(this)) {
1218
                return formatter.format(this);
1219
            }
1220
            StringBuilder builder = new StringBuilder();
1221
            boolean first = true;
1222
            for (String sql : toStrings(formatter)) {
1223
                if (StringUtils.isEmpty(sql)) {
1224
                    continue;
1225
                }
1226
                if (first) {
1227
                    first = false;
1228
                } else {
1229
                    builder.append("; ");
1230
                }
1231
                builder.append(sql);
1232
            }
1233
            return builder.toString();
1234
        }
1235

    
1236
        @Override
1237
        public List<String> toStrings() {
1238
            return this.toStrings(formatter());
1239
        }
1240

    
1241
        @Override
1242
        public List<String> toStrings(Formatter formatter) {
1243
            List<String> sqls = new ArrayList<>();
1244

    
1245
            sqls.add(
1246
                    MessageFormat.format(
1247
                            STMT_DROP_TABLE_table,
1248
                            this.table.toString(formatter)
1249
                    )
1250
            );
1251
            String sql;
1252
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1253
                if (this.table.has_schema()) {
1254
                    sql = MessageFormat.format(
1255
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1256
                            as_string(this.table.getSchema()),
1257
                            as_string(this.table.getName())
1258
                    );
1259
                } else {
1260
                    sql = MessageFormat.format(
1261
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1262
                            as_identifier(this.table.getName())
1263
                    );
1264
                }
1265
                if (!StringUtils.isEmpty(sql)) {
1266
                    sqls.add(sql);
1267
                }
1268
            }
1269
            return sqls;
1270
        }
1271
    }
1272

    
1273
    public class GrantRoleBuilderBase
1274
            extends AbstractStatementPart
1275
            implements GrantRoleBuilder {
1276

    
1277
        protected TableNameBuilder table;
1278
        protected String role;
1279
        protected Set<Privilege> privileges;
1280

    
1281
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1282
            this.table = table;
1283
            this.role = role;
1284
            this.privileges = new HashSet<>();
1285
        }
1286

    
1287
        @Override
1288
        public GrantRoleBuilder privilege(Privilege privilege) {
1289
            privileges.add(privilege);
1290
            return this;
1291
        }
1292

    
1293
        @Override
1294
        public GrantRoleBuilder select() {
1295
            privileges.add(Privilege.SELECT);
1296
            return this;
1297
        }
1298

    
1299
        @Override
1300
        public GrantRoleBuilder update() {
1301
            privileges.add(Privilege.UPDATE);
1302
            return this;
1303
        }
1304

    
1305
        @Override
1306
        public GrantRoleBuilder insert() {
1307
            privileges.add(Privilege.INSERT);
1308
            return this;
1309
        }
1310

    
1311
        @Override
1312
        public GrantRoleBuilder delete() {
1313
            privileges.add(Privilege.DELETE);
1314
            return this;
1315
        }
1316

    
1317
        @Override
1318
        public GrantRoleBuilder truncate() {
1319
            privileges.add(Privilege.TRUNCATE);
1320
            return this;
1321
        }
1322

    
1323
        @Override
1324
        public GrantRoleBuilder reference() {
1325
            privileges.add(Privilege.REFERENCE);
1326
            return this;
1327
        }
1328

    
1329
        @Override
1330
        public GrantRoleBuilder trigger() {
1331
            privileges.add(Privilege.TRIGGER);
1332
            return this;
1333
        }
1334

    
1335
        @Override
1336
        public GrantRoleBuilder all() {
1337
            privileges.add(Privilege.ALL);
1338
            return this;
1339
        }
1340

    
1341
        protected String getPrivilegeName(Privilege privilege) {
1342
            switch (privilege) {
1343
                case DELETE:
1344
                    return "DELETE";
1345
                case INSERT:
1346
                    return "INSERT";
1347
                case REFERENCE:
1348
                    return "REFERENCE";
1349
                case SELECT:
1350
                    return "SELECT";
1351
                case TRIGGER:
1352
                    return "TRIGGER";
1353
                case TRUNCATE:
1354
                    return "TRUNCATE";
1355
                case UPDATE:
1356
                    return "UPDATE";
1357
                case ALL:
1358
                default:
1359
                    return "ALL";
1360
            }
1361
        }
1362

    
1363
        @Override
1364
        public String toString() {
1365
            return this.toString(formatter());
1366
        }
1367

    
1368
        @Override
1369
        public String toString(Formatter<Value> formatter) {
1370
            if (formatter!=null && formatter.canApply(this)) {
1371
                return formatter.format(this);
1372
            }
1373
            StringBuilder builder = new StringBuilder();
1374
            boolean first = true;
1375
            for (Privilege privilege : privileges) {
1376
                if (first) {
1377
                    first = false;
1378
                } else {
1379
                    builder.append(", ");
1380
                }
1381
                builder.append(this.getPrivilegeName(privilege));
1382
            }
1383
            String sql = MessageFormat.format(
1384
                    STMT_GRANT_privileges_ON_table_TO_role,
1385
                    builder.toString(),
1386
                    table.toString(formatter),
1387
                    role
1388
            );
1389
            return sql;
1390
        }
1391
    }
1392

    
1393
    public class GrantBuilderBase
1394
            extends AbstractStatement
1395
            implements GrantBuilder {
1396

    
1397
        protected TableNameBuilder table;
1398
        protected Map<String, GrantRoleBuilder> roles;
1399

    
1400
        public GrantBuilderBase() {
1401
            this.roles = new HashMap<>();
1402
        }
1403

    
1404
        @Override
1405
        public TableNameBuilder table() {
1406
            if (table == null) {
1407
                table = createTableNameBuilder();
1408
            }
1409
            return table;
1410
        }
1411

    
1412
        @Override
1413
        public void accept(Visitor visitor, VisitorFilter filter) {
1414
            if (filter.accept(this)) {
1415
                visitor.visit(this);
1416
            }
1417
            if (this.table != null) {
1418
                this.table.accept(visitor, filter);
1419
            }
1420
        }
1421

    
1422
        @Override
1423
        public GrantRoleBuilder role(String role) {
1424
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1425
            if (roleBuilder == null) {
1426
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1427
                this.roles.put(role, roleBuilder);
1428
            }
1429
            return roleBuilder;
1430
        }
1431

    
1432
        @Override
1433
        public String toString() {
1434
            return this.toString(formatter());
1435
        }
1436

    
1437
        @Override
1438
        public String toString(Formatter<Value> formatter) {
1439
            if (formatter!=null && formatter.canApply(this)) {
1440
                return formatter.format(this);
1441
            }
1442
            StringBuilder builder = new StringBuilder();
1443
            boolean first = true;
1444
            for (String sql : toStrings(formatter)) {
1445
                if (StringUtils.isEmpty(sql)) {
1446
                    continue;
1447
                }
1448
                if (first) {
1449
                    first = false;
1450
                } else {
1451
                    builder.append("; ");
1452
                }
1453
                builder.append(sql);
1454
            }
1455
            return builder.toString();
1456
        }
1457

    
1458
        @Override
1459
        public List<String> toStrings() {
1460
            return this.toStrings(formatter());
1461
        }
1462

    
1463
        @Override
1464
        public List<String> toStrings(Formatter formatter) {
1465
            List<String> sqls = new ArrayList<>();
1466
            for (GrantRoleBuilder role : roles.values()) {
1467
                sqls.add(role.toString(formatter));
1468
            }
1469
            return sqls;
1470
        }
1471
    }
1472

    
1473
    public class UpdateColumnBuilderBase
1474
            extends InsertColumnBuilderBase
1475
            implements UpdateColumnBuilder {
1476

    
1477
        public UpdateColumnBuilderBase() {
1478
            super();
1479
        }
1480

    
1481
        @Override
1482
        public UpdateColumnBuilder name(String name) {
1483
            return (UpdateColumnBuilder) super.name(name);
1484
        }
1485

    
1486
        @Override
1487
        public UpdateColumnBuilder with_value(Value value) {
1488
            return (UpdateColumnBuilder) super.with_value(value);
1489
        }
1490

    
1491
    }
1492

    
1493
    public class UpdateBuilderBase
1494
            extends AbstractStatement
1495
            implements UpdateBuilder {
1496

    
1497
        protected GeometryExpressionBuilder where;
1498
        protected List<UpdateColumnBuilder> columns;
1499
        protected TableNameBuilder table;
1500

    
1501
        public UpdateBuilderBase() {
1502
            this.columns = new ArrayList<>();
1503
        }
1504

    
1505
        @Override
1506
        public void accept(Visitor visitor, VisitorFilter filter) {
1507
            if (filter.accept(this)) {
1508
                visitor.visit(this);
1509
            }
1510
            if (this.table != null) {
1511
                this.table.accept(visitor, filter);
1512
            }
1513
            for (UpdateColumnBuilder column : columns) {
1514
                column.accept(visitor, filter);
1515
            }
1516
            if (this.has_where()) {
1517
                this.where.accept(visitor, filter);
1518
            }
1519
        }
1520

    
1521
        @Override
1522
        public GeometryExpressionBuilder where() {
1523
            if (this.where == null) {
1524
                this.where = createExpressionBuilder();
1525
            }
1526
            return this.where;
1527
        }
1528

    
1529
        @Override
1530
        public TableNameBuilder table() {
1531
            if (table == null) {
1532
                table = createTableNameBuilder();
1533
            }
1534
            return table;
1535
        }
1536

    
1537
        @Override
1538
        public UpdateColumnBuilder column() {
1539
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1540
            this.columns.add(column);
1541
            return column;
1542
        }
1543

    
1544
        @Override
1545
        public boolean has_where() {
1546
            return this.where != null;
1547
        }
1548

    
1549
        @Override
1550
        public String toString() {
1551
            return this.toString(formatter());
1552
        }
1553

    
1554
        @Override
1555
        public String toString(Formatter<Value> formatter) {
1556
            if (formatter!=null && formatter.canApply(this)) {
1557
                return formatter.format(this);
1558
            }
1559
            /*
1560
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1561
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1562
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1563
             * output_expression [ AS output_name ] [, ...] ]
1564
             */
1565
            StringBuilder columnsAndValues = new StringBuilder();
1566

    
1567
            boolean first = true;
1568
            for (UpdateColumnBuilder column : columns) {
1569
                if (first) {
1570
                    first = false;
1571
                } else {
1572
                    columnsAndValues.append(", ");
1573
                }
1574
                columnsAndValues.append(as_identifier(column.getName()));
1575
                columnsAndValues.append(" = ");
1576
                columnsAndValues.append(column.getValue().toString(formatter));
1577
            }
1578

    
1579
            String sql;
1580
            if (this.has_where()) {
1581
                sql = MessageFormat.format(
1582
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1583
                        this.table.toString(formatter),
1584
                        columnsAndValues.toString(),
1585
                        this.where.toString(formatter)
1586
                );
1587
            } else {
1588
                sql = MessageFormat.format(
1589
                        STMT_UPDATE_table_SET_columnsAndValues,
1590
                        this.table.toString(formatter),
1591
                        columnsAndValues.toString()
1592
                );
1593
            }
1594
            return sql;
1595
        }
1596
    }
1597

    
1598
    public class DeleteBuilderBase
1599
            extends AbstractStatement
1600
            implements DeleteBuilder {
1601

    
1602
        protected GeometryExpressionBuilder where;
1603
        protected TableNameBuilder table;
1604

    
1605
        public DeleteBuilderBase() {
1606
        }
1607

    
1608
        @Override
1609
        public void accept(Visitor visitor, VisitorFilter filter) {
1610
            if (filter.accept(this)) {
1611
                visitor.visit(this);
1612
            }
1613
            if (this.table != null) {
1614
                this.table.accept(visitor, filter);
1615
            }
1616
            if (this.has_where()) {
1617
                this.where.accept(visitor, filter);
1618
            }
1619
        }
1620

    
1621
        @Override
1622
        public GeometryExpressionBuilder where() {
1623
            if (this.where == null) {
1624
                this.where = createExpressionBuilder();
1625
            }
1626
            return this.where;
1627
        }
1628

    
1629
        @Override
1630
        public TableNameBuilder table() {
1631
            if (table == null) {
1632
                table = createTableNameBuilder();
1633
            }
1634
            return table;
1635
        }
1636

    
1637
        @Override
1638
        public boolean has_where() {
1639
            return this.where != null;
1640
        }
1641

    
1642
        @Override
1643
        public String toString() {
1644
            return this.toString(formatter());
1645
        }
1646

    
1647
        @Override
1648
        public String toString(Formatter<Value> formatter) {
1649
            if (formatter!=null && formatter.canApply(this)) {
1650
                return formatter.format(this);
1651
            }
1652
            /*
1653
             * DELETE FROM table_name
1654
             * WHERE some_column=some_value; 
1655
             */
1656
            String sql;
1657
            if (this.has_where()) {
1658
                sql = MessageFormat.format(
1659
                        STMT_DELETE_FROM_table_WHERE_expresion,
1660
                        this.table.toString(formatter),
1661
                        this.where.toString(formatter)
1662
                );
1663
            } else {
1664
                sql = MessageFormat.format(
1665
                        STMT_DELETE_FROM_table,
1666
                        this.table.toString(formatter)
1667
                );
1668
            }
1669
            return sql;
1670
        }
1671
    }
1672

    
1673
    public class CreateIndexBuilderBase
1674
            extends AbstractStatement
1675
            implements CreateIndexBuilder {
1676

    
1677
        protected boolean ifNotExist = false;
1678
        protected boolean isUnique = false;
1679
        protected String indexName;
1680
        protected boolean isSpatial = false;
1681
        protected TableNameBuilder table;
1682
        protected final List<String> columns;
1683

    
1684
        public CreateIndexBuilderBase() {
1685
            this.columns = new ArrayList<>();
1686
        }
1687

    
1688
        @Override
1689
        public CreateIndexBuilder unique() {
1690
            this.isUnique = true;
1691
            return this;
1692
        }
1693

    
1694
        @Override
1695
        public CreateIndexBuilder if_not_exist() {
1696
            this.ifNotExist = true;
1697
            return this;
1698
        }
1699

    
1700
        @Override
1701
        public CreateIndexBuilder name(String name) {
1702
            this.indexName = name;
1703
            return this;
1704
        }
1705

    
1706
        @Override
1707
        public CreateIndexBuilder spatial() {
1708
            this.isSpatial = true;
1709
            return this;
1710
        }
1711

    
1712
        @Override
1713
        public CreateIndexBuilder column(String name) {
1714
            this.columns.add(name);
1715
            return this;
1716
        }
1717

    
1718
        @Override
1719
        public TableNameBuilder table() {
1720
            if (table == null) {
1721
                table = createTableNameBuilder();
1722
            }
1723
            return table;
1724
        }
1725

    
1726
        @Override
1727
        public void accept(Visitor visitor, VisitorFilter filter) {
1728
            if (filter.accept(this)) {
1729
                visitor.visit(this);
1730
            }
1731
            if (this.table != null) {
1732
                this.table.accept(visitor, filter);
1733
            }
1734
        }
1735

    
1736
        @Override
1737
        public String toString() {
1738
            return this.toString(formatter());
1739
        }
1740

    
1741
        @Override
1742
        public String toString(Formatter<Value> formatter) {
1743
            if (formatter!=null && formatter.canApply(this)) {
1744
                return formatter.format(this);
1745
            }
1746
            StringBuilder builder = new StringBuilder();
1747
            boolean first = true;
1748
            for (String sql : toStrings(formatter)) {
1749
                if (StringUtils.isEmpty(sql)) {
1750
                    continue;
1751
                }
1752
                if (first) {
1753
                    first = false;
1754
                } else {
1755
                    builder.append("; ");
1756
                }
1757
                builder.append(sql);
1758
            }
1759
            return builder.toString();
1760
        }
1761

    
1762
        @Override
1763
        public List<String> toStrings() {
1764
            return this.toStrings(formatter());
1765
        }
1766

    
1767
        @Override
1768
        public List<String> toStrings(Formatter formatter) {
1769
            StringBuilder builder = new StringBuilder();
1770
            builder.append("CREATE ");
1771
            if (this.isUnique) {
1772
                builder.append("UNIQUE ");
1773
            }
1774
            builder.append("INDEX ");
1775
            if (this.ifNotExist) {
1776
                builder.append("IF NOT EXISTS ");
1777
            }
1778
            builder.append(as_identifier(this.indexName));
1779
            builder.append(" ON ");
1780
            builder.append(this.table.toString(formatter));
1781
            if (this.isSpatial) {
1782
                builder.append(" USING GIST ");
1783
            }
1784
            builder.append(" ( ");
1785
            boolean is_first_column = true;
1786
            for (String column : this.columns) {
1787
                if (is_first_column) {
1788
                    is_first_column = false;
1789
                } else {
1790
                    builder.append(", ");
1791
                }
1792
                builder.append(column);
1793
            }
1794
            builder.append(" )");
1795

    
1796
            List<String> sqls = new ArrayList<>();
1797
            sqls.add(builder.toString());
1798
            return sqls;
1799
        }
1800

    
1801
    }
1802

    
1803
    public class AlterTableBuilderBase
1804
            extends AbstractStatement
1805
            implements AlterTableBuilder {
1806

    
1807
        protected TableNameBuilder table;
1808
        protected List<String> drops;
1809
        protected List<ColumnDescriptor> adds;
1810
        protected List<ColumnDescriptor> alters;
1811
        protected List<Pair<String, String>> renames;
1812

    
1813
        public AlterTableBuilderBase() {
1814
            this.drops = new ArrayList<>();
1815
            this.adds = new ArrayList<>();
1816
            this.alters = new ArrayList<>();
1817
            this.renames = new ArrayList<>();
1818
        }
1819

    
1820
        @Override
1821
        public boolean isEmpty() {
1822
            return this.drops.isEmpty()
1823
                    && this.adds.isEmpty()
1824
                    && this.alters.isEmpty()
1825
                    && this.renames.isEmpty();
1826
        }
1827

    
1828
        @Override
1829
        public void accept(Visitor visitor, VisitorFilter filter) {
1830
            if (filter.accept(this)) {
1831
                visitor.visit(this);
1832
            }
1833
            if (this.table != null) {
1834
                this.table.accept(visitor, filter);
1835
            }
1836
        }
1837

    
1838
        @Override
1839
        public TableNameBuilder table() {
1840
            if (table == null) {
1841
                table = createTableNameBuilder();
1842
            }
1843
            return table;
1844
        }
1845

    
1846
        @Override
1847
        public AlterTableBuilder drop_column(String columnName) {
1848
            this.drops.add(columnName);
1849
            return this;
1850
        }
1851

    
1852
        @Override
1853
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1854
            this.adds.add(new ColumnDescriptorBase(fad));
1855
            return this;
1856
        }
1857

    
1858
        @Override
1859
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1860
            if (isPk || isAutomatic) {
1861
                allowNulls = false;
1862
            }
1863
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1864
            return this;
1865
        }
1866

    
1867
        @Override
1868
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1869
            if (StringUtils.isEmpty(columnName)) {
1870
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1871
            }
1872
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1873
            return this;
1874
        }
1875

    
1876
        @Override
1877
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1878
            if (StringUtils.isEmpty(columnName)) {
1879
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1880
            }
1881
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1882
            return this;
1883
        }
1884

    
1885
        @Override
1886
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1887
            this.alters.add(new ColumnDescriptorBase(fad));
1888
            return this;
1889
        }
1890

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

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

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

    
1918
        @Override
1919
        public AlterTableBuilder rename_column(String source, String target) {
1920
            this.renames.add(new ImmutablePair(source, target));
1921
            return this;
1922
        }
1923

    
1924
        @Override
1925
        public String toString() {
1926
            return this.toString(formatter());
1927
        }
1928

    
1929
        @Override
1930
        public String toString(Formatter<Value> formatter) {
1931
            if (formatter!=null && formatter.canApply(this)) {
1932
                return formatter.format(this);
1933
            }
1934
            StringBuilder builder = new StringBuilder();
1935
            boolean first = true;
1936
            for (String sql : toStrings(formatter)) {
1937
                if (StringUtils.isEmpty(sql)) {
1938
                    continue;
1939
                }
1940
                if (first) {
1941
                    first = false;
1942
                } else {
1943
                    builder.append("; ");
1944
                }
1945
                builder.append(sql);
1946
            }
1947
            return builder.toString();
1948
        }
1949

    
1950
        @Override
1951
        public List<String> toStrings() {
1952
            return this.toStrings(formatter());
1953
        }
1954

    
1955
        @Override
1956
        public List<String> toStrings(Formatter formatter) {
1957
            List<String> sqls = new ArrayList<>();
1958
            if (this.isEmpty()) {
1959
                return sqls;
1960
            }
1961
            for (String column : drops) {
1962
                StringBuilder builder = new StringBuilder();
1963
                builder.append("ALTER TABLE ");
1964
                builder.append(this.table.toString(formatter));
1965
                builder.append(" DROP COLUMN IF EXISTS ");
1966
                builder.append(as_identifier(column));
1967
                sqls.add(builder.toString());
1968
            }
1969
            for (ColumnDescriptor column : adds) {
1970
                StringBuilder builder = new StringBuilder();
1971
                builder.append("ALTER TABLE ");
1972
                builder.append(this.table.toString(formatter));
1973
                builder.append(" ADD COLUMN ");
1974
                builder.append(as_identifier(column.getName()));
1975
                builder.append(" ");
1976
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1977
                    builder.append(" SERIAL");
1978
                } else {
1979
                    builder.append(
1980
                            sqltype(
1981
                                    column.getType(),
1982
                                    column.getSize(),
1983
                                    column.getPrecision(),
1984
                                    column.getScale(),
1985
                                    column.getGeometryType(),
1986
                                    column.getGeometrySubtype()
1987
                            )
1988
                    );
1989
                }
1990
                if (column.getDefaultValue() == null) {
1991
                    if (column.allowNulls()) {
1992
                        builder.append(" DEFAULT NULL");
1993
                    }
1994
                } else {
1995
                    builder.append(" DEFAULT '");
1996
                    builder.append(Objects.toString(column.getDefaultValue(),""));
1997
                    builder.append("'");
1998
                }
1999
                if (column.allowNulls()) {
2000
                    builder.append(" NULL");
2001
                } else {
2002
                    builder.append(" NOT NULL");
2003
                }
2004
                if (column.isPrimaryKey()) {
2005
                    builder.append(" PRIMARY KEY");
2006
                }
2007
                sqls.add(builder.toString());
2008
            }
2009
            for (ColumnDescriptor column : alters) {
2010
                StringBuilder builder = new StringBuilder();
2011
                builder.append("ALTER TABLE ");
2012
                builder.append(this.table.toString(formatter));
2013
                builder.append(" ALTER COLUMN ");
2014
                builder.append(as_identifier(column.getName()));
2015
                builder.append(" SET DATA TYPE ");
2016
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2017
                    builder.append(" SERIAL");
2018
                } else {
2019
                    builder.append(
2020
                            sqltype(
2021
                                    column.getType(),
2022
                                    column.getSize(),
2023
                                    column.getPrecision(),
2024
                                    column.getScale(),
2025
                                    column.getGeometryType(),
2026
                                    column.getGeometrySubtype()
2027
                            )
2028
                    );
2029
                }
2030
                if (column.getDefaultValue() == null) {
2031
                    if (column.allowNulls()) {
2032
                        builder.append(" DEFAULT NULL");
2033
                    } else {
2034
                        builder.append(" DROP DEFAULT");
2035
                    }
2036
                } else {
2037
                    builder.append(" DEFAULT '");
2038
                    builder.append(column.getDefaultValue().toString());
2039
                    builder.append("'");
2040
                }
2041
                sqls.add(builder.toString());
2042
            }
2043
            for (Pair<String, String> pair : renames) {
2044
                StringBuilder builder = new StringBuilder();
2045
                builder.append("ALTER TABLE ");
2046
                builder.append(this.table.toString(formatter));
2047
                builder.append(" RENAME COLUMN ");
2048
                builder.append(as_identifier(pair.getLeft()));
2049
                builder.append(" TO ");
2050
                builder.append(as_identifier(pair.getRight()));
2051
                sqls.add(builder.toString());
2052
            }
2053
            return sqls;
2054
        }
2055

    
2056
    }
2057

    
2058
    public class CreateTableBuilderBase
2059
            extends AbstractStatement
2060
            implements CreateTableBuilder {
2061

    
2062
        protected TableNameBuilder table;
2063
        protected List<ColumnDescriptor> columns;
2064

    
2065
        public CreateTableBuilderBase() {
2066
            this.columns = new ArrayList<>();
2067
        }
2068

    
2069
        @Override
2070
        public void accept(Visitor visitor, VisitorFilter filter) {
2071
            if (filter.accept(this)) {
2072
                visitor.visit(this);
2073
            }
2074
            if (this.table != null) {
2075
                this.table.accept(visitor, filter);
2076
            }
2077
        }
2078

    
2079
        @Override
2080
        public TableNameBuilder table() {
2081
            if (table == null) {
2082
                table = createTableNameBuilder();
2083
            }
2084
            return table;
2085
        }
2086

    
2087
        @Override
2088
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2089
            this.columns.add(new ColumnDescriptorBase(fad));
2090
            return this;
2091
        }
2092

    
2093
        @Override
2094
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2095
            if (StringUtils.isEmpty(columnName)) {
2096
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2097
            }
2098
            if (isPk || isAutomatic) {
2099
                allowNulls = false;
2100
            }
2101
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2102
            return this;
2103
        }
2104

    
2105
        @Override
2106
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2107
            if (StringUtils.isEmpty(columnName)) {
2108
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2109
            }
2110
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2111
            return this;
2112
        }
2113

    
2114
        @Override
2115
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2116
            if (StringUtils.isEmpty(columnName)) {
2117
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2118
            }
2119
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2120
            return this;
2121
        }
2122

    
2123
        @Override
2124
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2125
            if (StringUtils.isEmpty(columnName)) {
2126
                return null;
2127
            }
2128
            for (ColumnDescriptor column : columns) {
2129
                if (columnName.equals(column.getName())) {
2130
                    return column;
2131
                }
2132
            }
2133
            return null;
2134
        }
2135

    
2136
        @Override
2137
        public String toString() {
2138
            return this.toString(formatter());
2139
        }
2140

    
2141
        @Override
2142
        public String toString(Formatter<Value> formatter) {
2143
            if (formatter!=null && formatter.canApply(this)) {
2144
                return formatter.format(this);
2145
            }
2146
            StringBuilder builder = new StringBuilder();
2147
            boolean first = true;
2148
            for (String sql : toStrings(formatter)) {
2149
                if (StringUtils.isEmpty(sql)) {
2150
                    continue;
2151
                }
2152
                if (first) {
2153
                    first = false;
2154
                } else {
2155
                    builder.append("; ");
2156
                }
2157
                builder.append(sql);
2158
            }
2159
            return builder.toString();
2160
        }
2161

    
2162
        @Override
2163
        public List<String> toStrings() {
2164
            return this.toStrings(formatter());
2165
        }
2166

    
2167
        @Override
2168
        public List<String> toStrings(Formatter formatter) {
2169
            List<String> sqls = new ArrayList<>();
2170
            /**
2171
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2172
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2173
             * column_constraint [ ... ] ] | table_constraint | LIKE
2174
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2175
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2176
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2177
             *
2178
             * where column_constraint is:
2179
             *
2180
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2181
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2182
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2183
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2184
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2185
             *
2186
             * and table_constraint is:
2187
             *
2188
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2189
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2190
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2191
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2192
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2193
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2194
             */
2195
            StringBuilder builder = new StringBuilder();
2196

    
2197
            builder.append("CREATE TABLE ");
2198
            builder.append(this.table.toString(formatter));
2199
            builder.append(" (");
2200
            boolean first = true;
2201
            for (ColumnDescriptor column : columns) {
2202
                if (first) {
2203
                    first = false;
2204
                } else {
2205
                    builder.append(", ");
2206
                }
2207
                builder.append(as_identifier(column.getName()));
2208
                builder.append(" ");
2209
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2210
                    builder.append("SERIAL");
2211
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2212
                    builder.append("BIGSERIAL");
2213
                } else {
2214
                    builder.append(sqltype(
2215
                            column.getType(),
2216
                            column.getSize(),
2217
                            column.getPrecision(),
2218
                            column.getScale(),
2219
                            column.getGeometryType(),
2220
                            column.getGeometrySubtype()
2221
                    )
2222
                    );
2223
                }
2224
                if (column.getDefaultValue() == null) {
2225
                    if (column.allowNulls()) {
2226
                        builder.append(" DEFAULT NULL");
2227
                    }
2228
                } else {
2229
                    builder.append(" DEFAULT '");
2230
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2231
                    builder.append("'");
2232
                }
2233
                if (column.allowNulls()) {
2234
                    builder.append(" NULL");
2235
                } else {
2236
                    builder.append(" NOT NULL");
2237
                }
2238
                if (column.isPrimaryKey()) {
2239
                    builder.append(" PRIMARY KEY");
2240
                }
2241
            }
2242
            builder.append(" )");
2243
            sqls.add(builder.toString());
2244
            return sqls;
2245
        }
2246
    }
2247

    
2248
    public class InsertColumnBuilderBase
2249
            extends AbstractStatement
2250
            implements InsertColumnBuilder {
2251

    
2252
        protected Variable name;
2253
        protected Value value;
2254

    
2255
        public InsertColumnBuilderBase() {
2256
        }
2257

    
2258
        @Override
2259
        public void accept(Visitor visitor, VisitorFilter filter) {
2260
            if (filter.accept(this)) {
2261
                visitor.visit(this);
2262
            }
2263
            if (this.name != null) {
2264
                this.name.accept(visitor, filter);
2265
            }
2266
            if (this.value != null) {
2267
                this.value.accept(visitor, filter);
2268
            }
2269
        }
2270

    
2271
        @Override
2272
        public InsertColumnBuilder name(String name) {
2273
            this.name = expression().variable(name);
2274
            return this;
2275
        }
2276

    
2277
        @Override
2278
        public InsertColumnBuilder with_value(Value value) {
2279
            this.value = value;
2280
            return this;
2281
        }
2282

    
2283
        @Override
2284
        public String getName() {
2285
            return this.name.name();
2286
        }
2287

    
2288
        @Override
2289
        public Value getValue() {
2290
            return this.value;
2291
        }
2292

    
2293
        @Override
2294
        public String toString() {
2295
            return this.toString(formatter());
2296
        }
2297

    
2298
        @Override
2299
        public String toString(Formatter<Value> formatter) {
2300
            if (formatter!=null && formatter.canApply(this)) {
2301
                return formatter.format(this);
2302
            }
2303
            return this.value.toString(formatter);
2304
        }
2305
    }
2306

    
2307
    public class InsertBuilderBase
2308
            extends AbstractStatement
2309
            implements InsertBuilder {
2310

    
2311
        protected List<InsertColumnBuilder> columns;
2312
        protected TableNameBuilder table;
2313

    
2314
        public InsertBuilderBase() {
2315
            this.columns = new ArrayList<>();
2316
        }
2317

    
2318
        @Override
2319
        public void accept(Visitor visitor, VisitorFilter filter) {
2320
            if (filter.accept(this)) {
2321
                visitor.visit(this);
2322
            }
2323
            if (this.table != null) {
2324
                this.table.accept(visitor, filter);
2325
            }
2326
            for (InsertColumnBuilder column : columns) {
2327
                column.accept(visitor, filter);
2328
            }
2329
        }
2330

    
2331
        @Override
2332
        public TableNameBuilder table() {
2333
            if (table == null) {
2334
                table = createTableNameBuilder();
2335
            }
2336
            return table;
2337
        }
2338

    
2339
        @Override
2340
        public InsertColumnBuilder column() {
2341
            InsertColumnBuilder column = createInsertColumnBuilder();
2342
            this.columns.add(column);
2343
            return column;
2344
        }
2345

    
2346
        @Override
2347
        public String toString() {
2348
            return this.toString(formatter());
2349
        }
2350

    
2351
        @Override
2352
        public String toString(Formatter<Value> formatter) {
2353
            if (formatter!=null && formatter.canApply(this)) {
2354
                return formatter.format(this);
2355
            }
2356
            /*
2357
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2358
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2359
             * output_expression [ AS output_name ] [, ...] ]
2360
             */
2361
            StringBuilder builderColumns = new StringBuilder();
2362
            StringBuilder builderValues = new StringBuilder();
2363

    
2364
            boolean first = true;
2365
            for (InsertColumnBuilder column : columns) {
2366
                if (first) {
2367
                    first = false;
2368
                } else {
2369
                    builderColumns.append(", ");
2370
                }
2371
                builderColumns.append(as_identifier(column.getName()));
2372
            }
2373
            first = true;
2374
            for (InsertColumnBuilder column : columns) {
2375
                if (first) {
2376
                    first = false;
2377
                } else {
2378
                    builderValues.append(", ");
2379
                }
2380
                builderValues.append(column.toString(formatter));
2381
            }
2382

    
2383
            String sql = MessageFormat.format(
2384
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2385
                    this.table.toString(formatter),
2386
                    builderColumns.toString(),
2387
                    builderValues.toString()
2388
            );
2389
            return sql;
2390

    
2391
        }
2392
    }
2393

    
2394
    public class UpdateTableStatisticsBuilderBase
2395
            extends AbstractStatement
2396
            implements UpdateTableStatisticsBuilder {
2397

    
2398
        protected TableNameBuilder table;
2399

    
2400
        @Override
2401
        public void accept(Visitor visitor, VisitorFilter filter) {
2402
            if (filter.accept(this)) {
2403
                visitor.visit(this);
2404
            }
2405
            if (this.table != null) {
2406
                this.table.accept(visitor, filter);
2407
            }
2408
        }
2409

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

    
2418
        @Override
2419
        public String toString() {
2420
            return this.toString(formatter());
2421
        }
2422

    
2423
        @Override
2424
        public String toString(Formatter<Value> formatter) {
2425
            if (formatter!=null && formatter.canApply(this)) {
2426
                return formatter.format(this);
2427
            }
2428
            StringBuilder builder = new StringBuilder();
2429
            boolean first = true;
2430
            for (String sql : toStrings(formatter)) {
2431
                if (StringUtils.isEmpty(sql)) {
2432
                    continue;
2433
                }
2434
                if (first) {
2435
                    first = false;
2436
                } else {
2437
                    builder.append("; ");
2438
                }
2439
                builder.append(sql);
2440
            }
2441
            return builder.toString();
2442
        }
2443

    
2444
        @Override
2445
        public List<String> toStrings() {
2446
            return this.toStrings(formatter());
2447
        }
2448

    
2449
        @Override
2450
        public List<String> toStrings(Formatter formatter) {
2451
            List<String> sqls = new ArrayList<>();
2452

    
2453
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2454
                String sql = MessageFormat.format(
2455
                        STMT_UPDATE_TABLE_STATISTICS_table,
2456
                        table.toString(formatter)
2457
                );
2458
                if (!StringUtils.isEmpty(sql)) {
2459
                    sqls.add(sql);
2460
                }
2461
            }
2462
            return sqls;
2463
        }
2464
    }
2465

    
2466
    protected GeometryExpressionBuilder expressionBuilder;
2467

    
2468
    protected String defaultSchema;
2469
    protected boolean supportSchemas;
2470
    protected boolean hasSpatialFunctions;
2471
    protected GeometrySupportType geometrySupportType;
2472
    protected boolean allowAutomaticValues;
2473

    
2474
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2475

    
2476
    protected String constant_true = "(1=1)";
2477
    protected String constant_false = "(1<>1)";
2478

    
2479
    protected String type_boolean = "BOOLEAN";
2480
    protected String type_byte = "TINYINT";
2481
    protected String type_bytearray = "BYTEA";
2482
    protected String type_geometry = "TEXT";
2483
    protected String type_char = "CHARACTER(1)";
2484
    protected String type_date = "DATE";
2485
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2486
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2487
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2488
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2489
    protected String type_int = "INT";
2490
    protected String type_long = "BIGINT";
2491
    protected String type_string = "TEXT";
2492
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2493
    protected String type_time = "TIME";
2494
    protected String type_timestamp = "TIMESTAMP";
2495
    protected String type_version = "VARCHAR(30)";
2496
    protected String type_URI = "TEXT";
2497
    protected String type_URL = "TEXT";
2498
    protected String type_FILE = "TEXT";
2499
    protected String type_FOLDER = "TEXT";
2500

    
2501
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2502
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2503
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2504
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2505
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2506
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2507
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2508
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2509
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2510
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2511

    
2512
    public SQLBuilderBase() {
2513
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2514

    
2515
        this.hasSpatialFunctions = false;
2516
        this.supportSchemas = true;
2517
        this.geometrySupportType = GeometrySupportType.WKT;
2518

    
2519
        this.defaultSchema = "public";
2520
        this.allowAutomaticValues = true;
2521

    
2522
    }
2523
    
2524
    @Override
2525
    public void setProperties(Class filter, final Object... values) {
2526
        this.accept(new Visitor() {
2527
            @Override
2528
            public void visit(Visitable v) {
2529
                for (int i = 0; i < values.length; i+=2) {
2530
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2531
                }
2532
            }
2533
        }, new ClassVisitorFilter(filter) );
2534
    }
2535

    
2536
    public String quote_for_identifiers() {
2537
        return "\"";
2538
    }
2539

    
2540
    public String quote_for_strings() {
2541
        return "'";
2542
    }
2543

    
2544
    @Override
2545
    public String as_identifier(String id) {
2546
        String quote = this.quote_for_identifiers();
2547
//        No se porque no esta disponible wrapIfMissing
2548
//        return StringUtils.wrapIfMissing(id,quote);
2549
        if (id.startsWith(quote)) {
2550
            return id;
2551
        }
2552
        return quote + id + quote;
2553

    
2554
    }
2555

    
2556
    @Override
2557
    public String as_string(String s) {
2558
        String quote = this.quote_for_strings();
2559
//        No se porque no esta disponible wrapIfMissing
2560
//        return StringUtils.wrapIfMissing(id,quote);
2561
        if (s.startsWith(quote)) {
2562
            return s;
2563
        }
2564
        return quote + s + quote;
2565

    
2566
    }
2567

    
2568
    @Override
2569
    public String as_string(byte[] data) {
2570
        return this.expressionBuilder.bytearray_0x(data);
2571
//        return this.expressionBuilder.bytearray_hex(data);
2572
//        return this.expressionBuilder.bytearray_x(data);
2573
    }
2574
    
2575
    @Override
2576
    public String as_string(boolean value) {
2577
        return value? "TRUE" : "FALSE";
2578
    }
2579

    
2580
    @Override
2581
    public String as_string(Number value) {
2582
        return Objects.toString(value);
2583
    }
2584
    
2585
    @Override
2586
    public String as_string(Object value) {
2587
        if( value == null ) {
2588
            return "NULL";
2589
        }
2590
        if( value instanceof CharSequence ) {
2591
            return as_string(value.toString());
2592
        }
2593
        if( value instanceof Number ) {
2594
            return as_string((Number)value);
2595
        }
2596
        if( value instanceof Boolean ) {
2597
            return as_string((boolean)value);
2598
        }
2599
        if( value instanceof byte[] ) {
2600
            return as_string((byte[])value);
2601
        }
2602
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2603
    }
2604
    
2605
    @Override
2606
    public GeometryExpressionBuilder expression() {
2607
        return this.expressionBuilder;
2608
    }
2609

    
2610
    @Override
2611
    public boolean has_spatial_functions() {
2612
        return this.hasSpatialFunctions;
2613
    }
2614

    
2615
    @Override
2616
    public GeometrySupportType geometry_support_type() {
2617
        return this.geometrySupportType;
2618
    }
2619

    
2620
    protected GeometryExpressionBuilder createExpressionBuilder() {
2621
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2622
    }
2623

    
2624
    @Override
2625
    public Object srs_id(IProjection projection) {
2626
        String abrev = projection.getAbrev();
2627
        return abrev.split(":")[1].trim();
2628
    }
2629

    
2630
    @Override
2631
    public String default_schema() {
2632
        return this.defaultSchema;
2633
    }
2634

    
2635
    @Override
2636
    public boolean support_schemas() {
2637
        return this.supportSchemas;
2638
    }
2639

    
2640
    @Override
2641
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2642
        switch (type) {
2643
            case DataTypes.BOOLEAN:
2644
                return type_boolean;
2645
            case DataTypes.CHAR:
2646
                return type_char;
2647

    
2648

    
2649
            case DataTypes.BYTE:
2650
                return type_byte;
2651
            case DataTypes.INT:
2652
                return type_int;
2653
            case DataTypes.LONG:
2654
                return type_long;
2655

    
2656
            case DataTypes.FLOAT:
2657
                return type_float;
2658
            case DataTypes.DOUBLE:
2659
                return type_double;
2660
            case DataTypes.DECIMAL:
2661
                if (precision < 1) {
2662
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2663
                }
2664
                if (scale < 1) {
2665
                  return MessageFormat.format(type_decimal_p, precision);
2666
                }
2667
                return MessageFormat.format(type_decimal_ps, precision, scale);
2668

    
2669
                
2670
            case DataTypes.STRING:
2671
                if (size < 0) {
2672
                    return type_string;
2673
                } else if (size < 4096) {
2674
                    return MessageFormat.format(type_string_p, size);
2675
                }
2676
                return type_string;
2677

    
2678
                
2679
            case DataTypes.DATE:
2680
                return type_date;
2681
            case DataTypes.TIME:
2682
                return type_time;
2683
            case DataTypes.TIMESTAMP:
2684
                return type_timestamp;
2685

    
2686
            case DataTypes.BYTEARRAY:
2687
                return type_bytearray;
2688

    
2689
            case DataTypes.GEOMETRY:
2690
                return type_geometry;
2691

    
2692
            case DataTypes.VERSION:
2693
                return type_version;
2694
            case DataTypes.URI:
2695
                return type_URI;
2696
            case DataTypes.URL:
2697
                return type_URL;
2698
            case DataTypes.FILE:
2699
                return type_FILE;
2700
            case DataTypes.FOLDER:
2701
                return type_FOLDER;
2702
            default:
2703
                return null;
2704
        }
2705
    }
2706

    
2707
    @Override
2708
    public Object sqlgeometrytype(int type, int subtype) {
2709
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2710
        // identificadores numericos para el tipo y otros strings.
2711
        // Por defecto vamos a devolver strings.
2712
        if (sqlgeometrytypes == null) {
2713
            sqlgeometrytypes = new HashMap<>();
2714
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2715
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2716
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2717
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2718

    
2719
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2720
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2721
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2722
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2723

    
2724
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2725
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2726
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2727
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2728

    
2729
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2730
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2731
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2732
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2733

    
2734
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2735
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2736
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2737
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2738

    
2739
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2740
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2741
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2742
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2743

    
2744
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2745
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2746
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2747
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2748

    
2749
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2750
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2751
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2752
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2753

    
2754
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2755
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2756
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2757
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2758
        }
2759
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2760
    }
2761

    
2762
    @Override
2763
    public Object sqlgeometrydimension(int type, int subtype) {
2764
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2765
        // identificadores numericos para las dimensiones y otros strings.
2766
        // Por defecto vamos a devolver enteros.
2767
        switch (subtype) {
2768
            case Geometry.SUBTYPES.GEOM3D:
2769
                return 3;
2770
            case Geometry.SUBTYPES.GEOM2DM:
2771
                return 3;
2772
            case Geometry.SUBTYPES.GEOM3DM:
2773
                return 4;
2774
            case Geometry.SUBTYPES.GEOM2D:
2775
            default:
2776
                return 2;
2777
        }
2778
    }
2779

    
2780
    @Override
2781
    public TableNameBuilder createTableNameBuilder() {
2782
        return new TableNameBuilderBase();
2783
    }
2784

    
2785
    protected SelectColumnBuilder createSelectColumnBuilder() {
2786
        return new SelectColumnBuilderBase();
2787
    }
2788

    
2789
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2790
        return new UpdateColumnBuilderBase();
2791
    }
2792

    
2793
    protected InsertColumnBuilder createInsertColumnBuilder() {
2794
        return new InsertColumnBuilderBase();
2795
    }
2796

    
2797
    protected OrderByBuilder createOrderByBuilder() {
2798
        return new OrderByBuilderBase();
2799
    }
2800

    
2801
    protected FromBuilder createFromBuilder() {
2802
        return new FromBuilderBase();
2803
    }
2804

    
2805
    protected SelectBuilder createSelectBuilder() {
2806
        return new SelectBuilderBase();
2807
    }
2808

    
2809
    protected UpdateBuilder createUpdateBuilder() {
2810
        return new UpdateBuilderBase();
2811
    }
2812

    
2813
    protected DeleteBuilder createDeleteBuilder() {
2814
        return new DeleteBuilderBase();
2815
    }
2816

    
2817
    protected GrantBuilder createGrantBuilder() {
2818
        return new GrantBuilderBase();
2819
    }
2820

    
2821
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2822
        return new GrantRoleBuilderBase(table, role);
2823
    }
2824

    
2825
    protected DropTableBuilder createDropTableBuilder() {
2826
        return new DropTableBuilderBase();
2827
    }
2828

    
2829
    protected CreateTableBuilder createCreateTableBuilder() {
2830
        return new CreateTableBuilderBase();
2831
    }
2832

    
2833
    protected AlterTableBuilder createAlterTableBuilder() {
2834
        return new AlterTableBuilderBase();
2835
    }
2836

    
2837
    protected InsertBuilder createInsertBuilder() {
2838
        return new InsertBuilderBase();
2839
    }
2840

    
2841
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2842
        return new UpdateTableStatisticsBuilderBase();
2843
    }
2844

    
2845
    protected CreateIndexBuilder createCreateIndexBuilder() {
2846
        return new CreateIndexBuilderBase();
2847
    }
2848

    
2849
    @Override
2850
    public SelectBuilder select() {
2851
        if (this.select == null) {
2852
            this.select = this.createSelectBuilder();
2853
        }
2854
        return this.select;
2855
    }
2856

    
2857
    @Override
2858
    public UpdateBuilder update() {
2859
        if (this.update == null) {
2860
            this.update = this.createUpdateBuilder();
2861
        }
2862
        return this.update;
2863
    }
2864

    
2865
    @Override
2866
    public UpdateTableStatisticsBuilder update_table_statistics() {
2867
        if (this.update_table_statistics == null) {
2868
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2869
        }
2870
        return this.update_table_statistics;
2871
    }
2872

    
2873
    @Override
2874
    public DropTableBuilder drop_table() {
2875
        if (this.drop_table == null) {
2876
            this.drop_table = this.createDropTableBuilder();
2877
        }
2878
        return this.drop_table;
2879
    }
2880

    
2881
    @Override
2882
    public CreateIndexBuilder create_index() {
2883
        if (this.create_index == null) {
2884
            this.create_index = this.createCreateIndexBuilder();
2885
        }
2886
        return this.create_index;
2887
    }
2888

    
2889
    @Override
2890
    public DeleteBuilder delete() {
2891
        if (this.delete == null) {
2892
            this.delete = this.createDeleteBuilder();
2893
        }
2894
        return this.delete;
2895
    }
2896

    
2897
    @Override
2898
    public InsertBuilder insert() {
2899
        if (this.insert == null) {
2900
            this.insert = this.createInsertBuilder();
2901
        }
2902
        return this.insert;
2903
    }
2904

    
2905
    @Override
2906
    public TableNameBuilder table_name() {
2907
        if (this.table_name == null) {
2908
            this.table_name = this.createTableNameBuilder();
2909
        }
2910
        return this.table_name;
2911
    }
2912

    
2913
    
2914
    @Override
2915
    public AlterTableBuilder alter_table() {
2916
        if (this.alter_table == null) {
2917
            this.alter_table = this.createAlterTableBuilder();
2918
        }
2919
        return this.alter_table;
2920
    }
2921

    
2922
    @Override
2923
    public CreateTableBuilder create_table() {
2924
        if (this.create_table == null) {
2925
            this.create_table = this.createCreateTableBuilder();
2926
        }
2927
        return this.create_table;
2928
    }
2929

    
2930
    @Override
2931
    public GrantBuilder grant() {
2932
        if (this.grant == null) {
2933
            this.grant = this.createGrantBuilder();
2934
        }
2935
        return this.grant;
2936
    }
2937
    
2938
    @Override
2939
    public Column column(String name) {
2940
        ColumnBase col = new ColumnBase(null, name);
2941
        return col;
2942
    }
2943

    
2944
    @Override
2945
    public Column column(TableNameBuilder table, String name) {
2946
        ColumnBase col = new ColumnBase(table, name);
2947
        return col;
2948
    }
2949
    
2950
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
2951
        return new JoinBase(type, table, expression);
2952
    }
2953

    
2954
    public void accept(Visitor visitor, VisitorFilter filter) {
2955
        if (this.select != null) {
2956
            this.select.accept(visitor, filter);
2957
        }
2958
        if (this.update != null) {
2959
            this.update.accept(visitor, filter);
2960
        }
2961
        if (this.insert != null) {
2962
            this.insert.accept(visitor, filter);
2963
        }
2964
        if (this.delete != null) {
2965
            this.delete.accept(visitor, filter);
2966
        }
2967
        if (this.alter_table != null) {
2968
            this.alter_table.accept(visitor, filter);
2969
        }
2970
        if (this.create_table != null) {
2971
            this.create_table.accept(visitor, filter);
2972
        }
2973
        if (this.drop_table != null) {
2974
            this.drop_table.accept(visitor, filter);
2975
        }
2976
        if (this.table_name != null) {
2977
            this.table_name.accept(visitor, filter);
2978
        }
2979
    }
2980

    
2981
    protected Formatter formatter() {
2982
        return expression().formatter();
2983
    }
2984

    
2985
    @Override
2986
    public String toString() {
2987
        return this.toString(formatter());
2988
    }
2989

    
2990
    @Override
2991
    public String toString(Formatter formatter) {
2992
        if (this.select != null) {
2993
            return this.select.toString(formatter);
2994
        }
2995
        if (this.update != null) {
2996
            return this.update.toString(formatter);
2997
        }
2998
        if (this.insert != null) {
2999
            return this.insert.toString(formatter);
3000
        }
3001
        if (this.delete != null) {
3002
            return this.delete.toString(formatter);
3003
        }
3004
        if (this.alter_table != null) {
3005
            return this.alter_table.toString(formatter);
3006
        }
3007
        if (this.create_table != null) {
3008
            return this.create_table.toString(formatter);
3009
        }
3010
        if (this.drop_table != null) {
3011
            return this.drop_table.toString(formatter);
3012
        }
3013
        if (this.update_table_statistics != null) {
3014
            return this.update_table_statistics.toString(formatter);
3015
        }
3016
        if (this.table_name != null) {
3017
            return this.table_name.toString(formatter);
3018
        }
3019
        return "";
3020
    }
3021

    
3022
    @Override
3023
    public CountBuilder count() {
3024
        return new CountBuilderBase();
3025
    }
3026

    
3027
    @Override
3028
    public List<Parameter> parameters() {
3029
        final List<Parameter> params = new ArrayList<>();
3030
        this.accept(new Visitor() {
3031
            @Override
3032
            public void visit(Visitable value) {
3033
                params.add((Parameter) value);
3034
            }
3035
        }, new ClassVisitorFilter(Parameter.class));
3036
        return params;
3037
    }
3038

    
3039
    @Override
3040
    public List<Variable> variables() {
3041
        final List<Variable> vars = new ArrayList<>();
3042
        this.accept(new Visitor() {
3043
            @Override
3044
            public void visit(Visitable value) {
3045
                if (!vars.contains((Variable) value)) {
3046
                    vars.add((Variable) value);
3047
                }
3048
            }
3049
        }, new ClassVisitorFilter(Variable.class));
3050
        return vars;
3051
    }
3052

    
3053
    @Override
3054
    public List<String> parameters_names() {
3055
        List<String> params = new ArrayList<>();
3056
        for (Parameter param : parameters()) {
3057
            String s;
3058
            switch (param.type()) {
3059
                case PARAMETER_TYPE_CONSTANT:
3060
                    Object theValue = param.value();
3061
                    if (theValue == null) {
3062
                        s = "null";
3063
                    } else if (theValue instanceof String) {
3064
                        s = "'" + (String) theValue + "'";
3065
                    } else {
3066
                        s = theValue.toString();
3067
                    }
3068
                    break;
3069
                case PARAMETER_TYPE_VARIABLE:
3070
                default:
3071
                    s = "\"" + param.name() + "\"";
3072
            }
3073
            params.add(s);
3074
        }
3075
        return params;
3076
    }
3077

    
3078
    @Override
3079
    public List<String> variables_names() {
3080
        List<String> vars = new ArrayList<>();
3081
        for (Variable var : this.variables()) {
3082
            vars.add(var.name());
3083
        }
3084
        Collections.sort(vars);
3085
        return vars;
3086
    }
3087
}