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

History | View | Annotate | Download (103 KB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1110
        @Override
1111
        public String toString() {
1112
            return this.toString(formatter());
1113
        }
1114

    
1115
        @Override
1116
        public String toString(Formatter<Value> formatter) {
1117
            if (formatter!=null && formatter.canApply(this)) {
1118
                return formatter.format(this);
1119
            }
1120
            StringBuilder builder = new StringBuilder();
1121
            if (!this.isValid(builder)) {
1122
                throw new IllegalStateException(builder.toString());
1123
            }
1124
            builder.append("SELECT ");
1125
            if (this.distinct) {
1126
                builder.append("DISTINCT ");
1127
            }
1128
            boolean first = true;
1129
            for (SelectColumnBuilder column : columns) {
1130
                if (first) {
1131
                    first = false;
1132
                } else {
1133
                    builder.append(", ");
1134
                }
1135
                builder.append(column.toString(formatter));
1136
            }
1137

    
1138
            if (this.has_from()) {
1139
                builder.append(" FROM ");
1140
                builder.append(this.from.toString(formatter));
1141
            }
1142
            if( this.has_group_by() ) {
1143
                builder.append(" GROUP BY ");
1144
                builder.append(this.groupColumn.get(0).toString(formatter));
1145
                for (int i = 1; i < groupColumn.size(); i++) {
1146
                    builder.append(", ");
1147
                    builder.append(this.groupColumn.get(i).toString(formatter));
1148
                }
1149
            }
1150
            if (this.has_where()) {
1151
                builder.append(" WHERE ");
1152
                builder.append(this.where.toString(formatter));
1153
            }
1154

    
1155
            if (this.has_order_by()) {
1156
                builder.append(" ORDER BY ");
1157
                first = true;
1158
                for (OrderByBuilder item : this.order_by) {
1159
                    if (first) {
1160
                        first = false;
1161
                    } else {
1162
                        builder.append(", ");
1163
                    }
1164
                    builder.append(item.toString(formatter));
1165
                }
1166
            }
1167

    
1168
            if (this.has_limit()) {
1169
                builder.append(" LIMIT ");
1170
                builder.append(this.limit);
1171
            }
1172
            if (this.has_offset()) {
1173
                builder.append(" OFFSET ");
1174
                builder.append(this.offset);
1175
            }
1176
            return builder.toString();
1177

    
1178
        }
1179
    }
1180

    
1181
    public class DropTableBuilderBase
1182
            extends AbstractStatement
1183
            implements DropTableBuilder {
1184

    
1185
        protected TableNameBuilder table;
1186

    
1187
        @Override
1188
        public TableNameBuilder table() {
1189
            if (table == null) {
1190
                table = createTableNameBuilder();
1191
            }
1192
            return table;
1193
        }
1194

    
1195
        @Override
1196
        public void accept(Visitor visitor, VisitorFilter filter) {
1197
            if (filter.accept(this)) {
1198
                visitor.visit(this);
1199
            }
1200
            this.table.accept(visitor, filter);
1201
        }
1202

    
1203
        @Override
1204
        public String toString() {
1205
            return this.toString(formatter());
1206
        }
1207

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

    
1229
        @Override
1230
        public List<String> toStrings() {
1231
            return this.toStrings(formatter());
1232
        }
1233

    
1234
        @Override
1235
        public List<String> toStrings(Formatter formatter) {
1236
            List<String> sqls = new ArrayList<>();
1237

    
1238
            sqls.add(
1239
                    MessageFormat.format(
1240
                            STMT_DROP_TABLE_table,
1241
                            this.table.toString(formatter)
1242
                    )
1243
            );
1244
            String sql;
1245
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1246
                if (this.table.has_schema()) {
1247
                    sql = MessageFormat.format(
1248
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1249
                            as_string(this.table.getSchema()),
1250
                            as_string(this.table.getName())
1251
                    );
1252
                } else {
1253
                    sql = MessageFormat.format(
1254
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1255
                            as_identifier(this.table.getName())
1256
                    );
1257
                }
1258
                if (!StringUtils.isEmpty(sql)) {
1259
                    sqls.add(sql);
1260
                }
1261
            }
1262
            return sqls;
1263
        }
1264
    }
1265

    
1266
    public class GrantRoleBuilderBase
1267
            extends AbstractStatementPart
1268
            implements GrantRoleBuilder {
1269

    
1270
        protected TableNameBuilder table;
1271
        protected String role;
1272
        protected Set<Privilege> privileges;
1273

    
1274
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1275
            this.table = table;
1276
            this.role = role;
1277
            this.privileges = new HashSet<>();
1278
        }
1279

    
1280
        @Override
1281
        public GrantRoleBuilder privilege(Privilege privilege) {
1282
            privileges.add(privilege);
1283
            return this;
1284
        }
1285

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

    
1292
        @Override
1293
        public GrantRoleBuilder update() {
1294
            privileges.add(Privilege.UPDATE);
1295
            return this;
1296
        }
1297

    
1298
        @Override
1299
        public GrantRoleBuilder insert() {
1300
            privileges.add(Privilege.INSERT);
1301
            return this;
1302
        }
1303

    
1304
        @Override
1305
        public GrantRoleBuilder delete() {
1306
            privileges.add(Privilege.DELETE);
1307
            return this;
1308
        }
1309

    
1310
        @Override
1311
        public GrantRoleBuilder truncate() {
1312
            privileges.add(Privilege.TRUNCATE);
1313
            return this;
1314
        }
1315

    
1316
        @Override
1317
        public GrantRoleBuilder reference() {
1318
            privileges.add(Privilege.REFERENCE);
1319
            return this;
1320
        }
1321

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

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

    
1334
        protected String getPrivilegeName(Privilege privilege) {
1335
            switch (privilege) {
1336
                case DELETE:
1337
                    return "DELETE";
1338
                case INSERT:
1339
                    return "INSERT";
1340
                case REFERENCE:
1341
                    return "REFERENCE";
1342
                case SELECT:
1343
                    return "SELECT";
1344
                case TRIGGER:
1345
                    return "TRIGGER";
1346
                case TRUNCATE:
1347
                    return "TRUNCATE";
1348
                case UPDATE:
1349
                    return "UPDATE";
1350
                case ALL:
1351
                default:
1352
                    return "ALL";
1353
            }
1354
        }
1355

    
1356
        @Override
1357
        public String toString() {
1358
            return this.toString(formatter());
1359
        }
1360

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

    
1386
    public class GrantBuilderBase
1387
            extends AbstractStatement
1388
            implements GrantBuilder {
1389

    
1390
        protected TableNameBuilder table;
1391
        protected Map<String, GrantRoleBuilder> roles;
1392

    
1393
        public GrantBuilderBase() {
1394
            this.roles = new HashMap<>();
1395
        }
1396

    
1397
        @Override
1398
        public TableNameBuilder table() {
1399
            if (table == null) {
1400
                table = createTableNameBuilder();
1401
            }
1402
            return table;
1403
        }
1404

    
1405
        @Override
1406
        public void accept(Visitor visitor, VisitorFilter filter) {
1407
            if (filter.accept(this)) {
1408
                visitor.visit(this);
1409
            }
1410
            if (this.table != null) {
1411
                this.table.accept(visitor, filter);
1412
            }
1413
        }
1414

    
1415
        @Override
1416
        public GrantRoleBuilder role(String role) {
1417
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1418
            if (roleBuilder == null) {
1419
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1420
                this.roles.put(role, roleBuilder);
1421
            }
1422
            return roleBuilder;
1423
        }
1424

    
1425
        @Override
1426
        public String toString() {
1427
            return this.toString(formatter());
1428
        }
1429

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

    
1451
        @Override
1452
        public List<String> toStrings() {
1453
            return this.toStrings(formatter());
1454
        }
1455

    
1456
        @Override
1457
        public List<String> toStrings(Formatter formatter) {
1458
            List<String> sqls = new ArrayList<>();
1459
            for (GrantRoleBuilder role : roles.values()) {
1460
                sqls.add(role.toString(formatter));
1461
            }
1462
            return sqls;
1463
        }
1464
    }
1465

    
1466
    public class UpdateColumnBuilderBase
1467
            extends InsertColumnBuilderBase
1468
            implements UpdateColumnBuilder {
1469

    
1470
        public UpdateColumnBuilderBase() {
1471
            super();
1472
        }
1473

    
1474
        @Override
1475
        public UpdateColumnBuilder name(String name) {
1476
            return (UpdateColumnBuilder) super.name(name);
1477
        }
1478

    
1479
        @Override
1480
        public UpdateColumnBuilder with_value(Value value) {
1481
            return (UpdateColumnBuilder) super.with_value(value);
1482
        }
1483

    
1484
    }
1485

    
1486
    public class UpdateBuilderBase
1487
            extends AbstractStatement
1488
            implements UpdateBuilder {
1489

    
1490
        protected GeometryExpressionBuilder where;
1491
        protected List<UpdateColumnBuilder> columns;
1492
        protected TableNameBuilder table;
1493

    
1494
        public UpdateBuilderBase() {
1495
            this.columns = new ArrayList<>();
1496
        }
1497

    
1498
        @Override
1499
        public void accept(Visitor visitor, VisitorFilter filter) {
1500
            if (filter.accept(this)) {
1501
                visitor.visit(this);
1502
            }
1503
            if (this.table != null) {
1504
                this.table.accept(visitor, filter);
1505
            }
1506
            for (UpdateColumnBuilder column : columns) {
1507
                column.accept(visitor, filter);
1508
            }
1509
            if (this.has_where()) {
1510
                this.where.accept(visitor, filter);
1511
            }
1512
        }
1513

    
1514
        @Override
1515
        public GeometryExpressionBuilder where() {
1516
            if (this.where == null) {
1517
                this.where = createExpressionBuilder();
1518
            }
1519
            return this.where;
1520
        }
1521

    
1522
        @Override
1523
        public TableNameBuilder table() {
1524
            if (table == null) {
1525
                table = createTableNameBuilder();
1526
            }
1527
            return table;
1528
        }
1529

    
1530
        @Override
1531
        public UpdateColumnBuilder column() {
1532
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1533
            this.columns.add(column);
1534
            return column;
1535
        }
1536

    
1537
        @Override
1538
        public boolean has_where() {
1539
            return this.where != null;
1540
        }
1541

    
1542
        @Override
1543
        public String toString() {
1544
            return this.toString(formatter());
1545
        }
1546

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

    
1560
            boolean first = true;
1561
            for (UpdateColumnBuilder column : columns) {
1562
                if (first) {
1563
                    first = false;
1564
                } else {
1565
                    columnsAndValues.append(", ");
1566
                }
1567
                columnsAndValues.append(as_identifier(column.getName()));
1568
                columnsAndValues.append(" = ");
1569
                columnsAndValues.append(column.getValue().toString(formatter));
1570
            }
1571

    
1572
            String sql;
1573
            if (this.has_where()) {
1574
                sql = MessageFormat.format(
1575
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1576
                        this.table.toString(formatter),
1577
                        columnsAndValues.toString(),
1578
                        this.where.toString(formatter)
1579
                );
1580
            } else {
1581
                sql = MessageFormat.format(
1582
                        STMT_UPDATE_table_SET_columnsAndValues,
1583
                        this.table.toString(formatter),
1584
                        columnsAndValues.toString()
1585
                );
1586
            }
1587
            return sql;
1588
        }
1589
    }
1590

    
1591
    public class DeleteBuilderBase
1592
            extends AbstractStatement
1593
            implements DeleteBuilder {
1594

    
1595
        protected GeometryExpressionBuilder where;
1596
        protected TableNameBuilder table;
1597

    
1598
        public DeleteBuilderBase() {
1599
        }
1600

    
1601
        @Override
1602
        public void accept(Visitor visitor, VisitorFilter filter) {
1603
            if (filter.accept(this)) {
1604
                visitor.visit(this);
1605
            }
1606
            if (this.table != null) {
1607
                this.table.accept(visitor, filter);
1608
            }
1609
            if (this.has_where()) {
1610
                this.where.accept(visitor, filter);
1611
            }
1612
        }
1613

    
1614
        @Override
1615
        public GeometryExpressionBuilder where() {
1616
            if (this.where == null) {
1617
                this.where = createExpressionBuilder();
1618
            }
1619
            return this.where;
1620
        }
1621

    
1622
        @Override
1623
        public TableNameBuilder table() {
1624
            if (table == null) {
1625
                table = createTableNameBuilder();
1626
            }
1627
            return table;
1628
        }
1629

    
1630
        @Override
1631
        public boolean has_where() {
1632
            return this.where != null;
1633
        }
1634

    
1635
        @Override
1636
        public String toString() {
1637
            return this.toString(formatter());
1638
        }
1639

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

    
1666
    public class CreateIndexBuilderBase
1667
            extends AbstractStatement
1668
            implements CreateIndexBuilder {
1669

    
1670
        protected boolean ifNotExist = false;
1671
        protected boolean isUnique = false;
1672
        protected String indexName;
1673
        protected boolean isSpatial = false;
1674
        protected TableNameBuilder table;
1675
        protected final List<String> columns;
1676

    
1677
        public CreateIndexBuilderBase() {
1678
            this.columns = new ArrayList<>();
1679
        }
1680

    
1681
        @Override
1682
        public CreateIndexBuilder unique() {
1683
            this.isUnique = true;
1684
            return this;
1685
        }
1686

    
1687
        @Override
1688
        public CreateIndexBuilder if_not_exist() {
1689
            this.ifNotExist = true;
1690
            return this;
1691
        }
1692

    
1693
        @Override
1694
        public CreateIndexBuilder name(String name) {
1695
            this.indexName = name;
1696
            return this;
1697
        }
1698

    
1699
        @Override
1700
        public CreateIndexBuilder spatial() {
1701
            this.isSpatial = true;
1702
            return this;
1703
        }
1704

    
1705
        @Override
1706
        public CreateIndexBuilder column(String name) {
1707
            this.columns.add(name);
1708
            return this;
1709
        }
1710

    
1711
        @Override
1712
        public TableNameBuilder table() {
1713
            if (table == null) {
1714
                table = createTableNameBuilder();
1715
            }
1716
            return table;
1717
        }
1718

    
1719
        @Override
1720
        public void accept(Visitor visitor, VisitorFilter filter) {
1721
            if (filter.accept(this)) {
1722
                visitor.visit(this);
1723
            }
1724
            if (this.table != null) {
1725
                this.table.accept(visitor, filter);
1726
            }
1727
        }
1728

    
1729
        @Override
1730
        public String toString() {
1731
            return this.toString(formatter());
1732
        }
1733

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

    
1755
        @Override
1756
        public List<String> toStrings() {
1757
            return this.toStrings(formatter());
1758
        }
1759

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

    
1789
            List<String> sqls = new ArrayList<>();
1790
            sqls.add(builder.toString());
1791
            return sqls;
1792
        }
1793

    
1794
    }
1795

    
1796
    public class AlterTableBuilderBase
1797
            extends AbstractStatement
1798
            implements AlterTableBuilder {
1799

    
1800
        protected TableNameBuilder table;
1801
        protected List<String> drops;
1802
        protected List<ColumnDescriptor> adds;
1803
        protected List<ColumnDescriptor> alters;
1804
        protected List<Pair<String, String>> renames;
1805

    
1806
        public AlterTableBuilderBase() {
1807
            this.drops = new ArrayList<>();
1808
            this.adds = new ArrayList<>();
1809
            this.alters = new ArrayList<>();
1810
            this.renames = new ArrayList<>();
1811
        }
1812

    
1813
        @Override
1814
        public boolean isEmpty() {
1815
            return this.drops.isEmpty()
1816
                    && this.adds.isEmpty()
1817
                    && this.alters.isEmpty()
1818
                    && this.renames.isEmpty();
1819
        }
1820

    
1821
        @Override
1822
        public void accept(Visitor visitor, VisitorFilter filter) {
1823
            if (filter.accept(this)) {
1824
                visitor.visit(this);
1825
            }
1826
            if (this.table != null) {
1827
                this.table.accept(visitor, filter);
1828
            }
1829
        }
1830

    
1831
        @Override
1832
        public TableNameBuilder table() {
1833
            if (table == null) {
1834
                table = createTableNameBuilder();
1835
            }
1836
            return table;
1837
        }
1838

    
1839
        @Override
1840
        public AlterTableBuilder drop_column(String columnName) {
1841
            this.drops.add(columnName);
1842
            return this;
1843
        }
1844

    
1845
        @Override
1846
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1847
            this.adds.add(new ColumnDescriptorBase(fad));
1848
            return this;
1849
        }
1850

    
1851
        @Override
1852
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1853
            if (isPk || isAutomatic) {
1854
                allowNulls = false;
1855
            }
1856
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1857
            return this;
1858
        }
1859

    
1860
        @Override
1861
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1862
            if (StringUtils.isEmpty(columnName)) {
1863
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1864
            }
1865
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1866
            return this;
1867
        }
1868

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

    
1878
        @Override
1879
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1880
            this.alters.add(new ColumnDescriptorBase(fad));
1881
            return this;
1882
        }
1883

    
1884
        @Override
1885
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1886
            if (isPk || isAutomatic) {
1887
                allowNulls = false;
1888
            }
1889
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1890
            return this;
1891
        }
1892

    
1893
        @Override
1894
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1895
            if (StringUtils.isEmpty(columnName)) {
1896
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1897
            }
1898
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1899
            return this;
1900
        }
1901

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

    
1911
        @Override
1912
        public AlterTableBuilder rename_column(String source, String target) {
1913
            this.renames.add(new ImmutablePair(source, target));
1914
            return this;
1915
        }
1916

    
1917
        @Override
1918
        public String toString() {
1919
            return this.toString(formatter());
1920
        }
1921

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

    
1943
        @Override
1944
        public List<String> toStrings() {
1945
            return this.toStrings(formatter());
1946
        }
1947

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

    
2049
    }
2050

    
2051
    public class CreateTableBuilderBase
2052
            extends AbstractStatement
2053
            implements CreateTableBuilder {
2054

    
2055
        protected TableNameBuilder table;
2056
        protected List<ColumnDescriptor> columns;
2057

    
2058
        public CreateTableBuilderBase() {
2059
            this.columns = new ArrayList<>();
2060
        }
2061

    
2062
        @Override
2063
        public void accept(Visitor visitor, VisitorFilter filter) {
2064
            if (filter.accept(this)) {
2065
                visitor.visit(this);
2066
            }
2067
            if (this.table != null) {
2068
                this.table.accept(visitor, filter);
2069
            }
2070
        }
2071

    
2072
        @Override
2073
        public TableNameBuilder table() {
2074
            if (table == null) {
2075
                table = createTableNameBuilder();
2076
            }
2077
            return table;
2078
        }
2079

    
2080
        @Override
2081
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2082
            this.columns.add(new ColumnDescriptorBase(fad));
2083
            return this;
2084
        }
2085

    
2086
        @Override
2087
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2088
            if (StringUtils.isEmpty(columnName)) {
2089
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2090
            }
2091
            if (isPk || isAutomatic) {
2092
                allowNulls = false;
2093
            }
2094
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2095
            return this;
2096
        }
2097

    
2098
        @Override
2099
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2100
            if (StringUtils.isEmpty(columnName)) {
2101
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2102
            }
2103
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2104
            return this;
2105
        }
2106

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

    
2116
        @Override
2117
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2118
            if (StringUtils.isEmpty(columnName)) {
2119
                return null;
2120
            }
2121
            for (ColumnDescriptor column : columns) {
2122
                if (columnName.equals(column.getName())) {
2123
                    return column;
2124
                }
2125
            }
2126
            return null;
2127
        }
2128

    
2129
        @Override
2130
        public String toString() {
2131
            return this.toString(formatter());
2132
        }
2133

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

    
2155
        @Override
2156
        public List<String> toStrings() {
2157
            return this.toStrings(formatter());
2158
        }
2159

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

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

    
2241
    public class InsertColumnBuilderBase
2242
            extends AbstractStatement
2243
            implements InsertColumnBuilder {
2244

    
2245
        protected Variable name;
2246
        protected Value value;
2247

    
2248
        public InsertColumnBuilderBase() {
2249
        }
2250

    
2251
        @Override
2252
        public void accept(Visitor visitor, VisitorFilter filter) {
2253
            if (filter.accept(this)) {
2254
                visitor.visit(this);
2255
            }
2256
            if (this.name != null) {
2257
                this.name.accept(visitor, filter);
2258
            }
2259
            if (this.value != null) {
2260
                this.value.accept(visitor, filter);
2261
            }
2262
        }
2263

    
2264
        @Override
2265
        public InsertColumnBuilder name(String name) {
2266
            this.name = expression().variable(name);
2267
            return this;
2268
        }
2269

    
2270
        @Override
2271
        public InsertColumnBuilder with_value(Value value) {
2272
            this.value = value;
2273
            return this;
2274
        }
2275

    
2276
        @Override
2277
        public String getName() {
2278
            return this.name.name();
2279
        }
2280

    
2281
        @Override
2282
        public Value getValue() {
2283
            return this.value;
2284
        }
2285

    
2286
        @Override
2287
        public String toString() {
2288
            return this.toString(formatter());
2289
        }
2290

    
2291
        @Override
2292
        public String toString(Formatter<Value> formatter) {
2293
            if (formatter!=null && formatter.canApply(this)) {
2294
                return formatter.format(this);
2295
            }
2296
            return this.value.toString(formatter);
2297
        }
2298
    }
2299

    
2300
    public class InsertBuilderBase
2301
            extends AbstractStatement
2302
            implements InsertBuilder {
2303

    
2304
        protected List<InsertColumnBuilder> columns;
2305
        protected TableNameBuilder table;
2306

    
2307
        public InsertBuilderBase() {
2308
            this.columns = new ArrayList<>();
2309
        }
2310

    
2311
        @Override
2312
        public void accept(Visitor visitor, VisitorFilter filter) {
2313
            if (filter.accept(this)) {
2314
                visitor.visit(this);
2315
            }
2316
            if (this.table != null) {
2317
                this.table.accept(visitor, filter);
2318
            }
2319
            for (InsertColumnBuilder column : columns) {
2320
                column.accept(visitor, filter);
2321
            }
2322
        }
2323

    
2324
        @Override
2325
        public TableNameBuilder table() {
2326
            if (table == null) {
2327
                table = createTableNameBuilder();
2328
            }
2329
            return table;
2330
        }
2331

    
2332
        @Override
2333
        public InsertColumnBuilder column() {
2334
            InsertColumnBuilder column = createInsertColumnBuilder();
2335
            this.columns.add(column);
2336
            return column;
2337
        }
2338

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

    
2344
        @Override
2345
        public String toString(Formatter<Value> formatter) {
2346
            if (formatter!=null && formatter.canApply(this)) {
2347
                return formatter.format(this);
2348
            }
2349
            /*
2350
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2351
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2352
             * output_expression [ AS output_name ] [, ...] ]
2353
             */
2354
            StringBuilder builderColumns = new StringBuilder();
2355
            StringBuilder builderValues = new StringBuilder();
2356

    
2357
            boolean first = true;
2358
            for (InsertColumnBuilder column : columns) {
2359
                if (first) {
2360
                    first = false;
2361
                } else {
2362
                    builderColumns.append(", ");
2363
                }
2364
                builderColumns.append(as_identifier(column.getName()));
2365
            }
2366
            first = true;
2367
            for (InsertColumnBuilder column : columns) {
2368
                if (first) {
2369
                    first = false;
2370
                } else {
2371
                    builderValues.append(", ");
2372
                }
2373
                builderValues.append(column.toString(formatter));
2374
            }
2375

    
2376
            String sql = MessageFormat.format(
2377
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2378
                    this.table.toString(formatter),
2379
                    builderColumns.toString(),
2380
                    builderValues.toString()
2381
            );
2382
            return sql;
2383

    
2384
        }
2385
    }
2386

    
2387
    public class UpdateTableStatisticsBuilderBase
2388
            extends AbstractStatement
2389
            implements UpdateTableStatisticsBuilder {
2390

    
2391
        protected TableNameBuilder table;
2392

    
2393
        @Override
2394
        public void accept(Visitor visitor, VisitorFilter filter) {
2395
            if (filter.accept(this)) {
2396
                visitor.visit(this);
2397
            }
2398
            if (this.table != null) {
2399
                this.table.accept(visitor, filter);
2400
            }
2401
        }
2402

    
2403
        @Override
2404
        public TableNameBuilder table() {
2405
            if (table == null) {
2406
                table = createTableNameBuilder();
2407
            }
2408
            return table;
2409
        }
2410

    
2411
        @Override
2412
        public String toString() {
2413
            return this.toString(formatter());
2414
        }
2415

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

    
2437
        @Override
2438
        public List<String> toStrings() {
2439
            return this.toStrings(formatter());
2440
        }
2441

    
2442
        @Override
2443
        public List<String> toStrings(Formatter formatter) {
2444
            List<String> sqls = new ArrayList<>();
2445

    
2446
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2447
                String sql = MessageFormat.format(
2448
                        STMT_UPDATE_TABLE_STATISTICS_table,
2449
                        table.toString(formatter)
2450
                );
2451
                if (!StringUtils.isEmpty(sql)) {
2452
                    sqls.add(sql);
2453
                }
2454
            }
2455
            return sqls;
2456
        }
2457
    }
2458

    
2459
    protected GeometryExpressionBuilder expressionBuilder;
2460

    
2461
    protected String defaultSchema;
2462
    protected boolean supportSchemas;
2463
    protected boolean hasSpatialFunctions;
2464
    protected GeometrySupportType geometrySupportType;
2465
    protected boolean allowAutomaticValues;
2466

    
2467
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2468

    
2469
    protected String constant_true = "(1=1)";
2470
    protected String constant_false = "(1<>1)";
2471

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

    
2495
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2496
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2497
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2498
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2499
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2500
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2501
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2502
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2503
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2504
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2505

    
2506
    public SQLBuilderBase() {
2507
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2508

    
2509
        this.hasSpatialFunctions = false;
2510
        this.supportSchemas = true;
2511
        this.geometrySupportType = GeometrySupportType.WKT;
2512

    
2513
        this.defaultSchema = "public";
2514
        this.allowAutomaticValues = true;
2515

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

    
2530
    public String quote_for_identifiers() {
2531
        return "\"";
2532
    }
2533

    
2534
    public String quote_for_strings() {
2535
        return "'";
2536
    }
2537

    
2538
    @Override
2539
    public String as_identifier(String id) {
2540
        String quote = this.quote_for_identifiers();
2541
//        No se porque no esta disponible wrapIfMissing
2542
//        return StringUtils.wrapIfMissing(id,quote);
2543
        if (id.startsWith(quote)) {
2544
            return id;
2545
        }
2546
        return quote + id + quote;
2547

    
2548
    }
2549

    
2550
    @Override
2551
    public String as_string(String s) {
2552
        String quote = this.quote_for_strings();
2553
//        No se porque no esta disponible wrapIfMissing
2554
//        return StringUtils.wrapIfMissing(id,quote);
2555
        if (s.startsWith(quote)) {
2556
            return s;
2557
        }
2558
        return quote + s + quote;
2559

    
2560
    }
2561

    
2562
    @Override
2563
    public String as_string(byte[] data) {
2564
        return this.expressionBuilder.bytearray_0x(data);
2565
//        return this.expressionBuilder.bytearray_hex(data);
2566
//        return this.expressionBuilder.bytearray_x(data);
2567
    }
2568
    
2569
    @Override
2570
    public String as_string(boolean value) {
2571
        return value? "TRUE" : "FALSE";
2572
    }
2573

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

    
2604
    @Override
2605
    public boolean has_spatial_functions() {
2606
        return this.hasSpatialFunctions;
2607
    }
2608

    
2609
    @Override
2610
    public GeometrySupportType geometry_support_type() {
2611
        return this.geometrySupportType;
2612
    }
2613

    
2614
    protected GeometryExpressionBuilder createExpressionBuilder() {
2615
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2616
    }
2617

    
2618
    @Override
2619
    public Object srs_id(IProjection projection) {
2620
        String abrev = projection.getAbrev();
2621
        return abrev.split(":")[1].trim();
2622
    }
2623

    
2624
    @Override
2625
    public String default_schema() {
2626
        return this.defaultSchema;
2627
    }
2628

    
2629
    @Override
2630
    public boolean support_schemas() {
2631
        return this.supportSchemas;
2632
    }
2633

    
2634
    @Override
2635
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2636
        switch (type) {
2637
            case DataTypes.BOOLEAN:
2638
                return type_boolean;
2639
            case DataTypes.BYTE:
2640
                return type_byte;
2641
            case DataTypes.BYTEARRAY:
2642
                return type_bytearray;
2643
            case DataTypes.GEOMETRY:
2644
                return type_geometry;
2645
            case DataTypes.CHAR:
2646
                return type_char;
2647
            case DataTypes.DATE:
2648
                return type_date;
2649
            case DataTypes.DOUBLE:
2650
                // FIXME: Si cargamos la capa "country" al exportarla a
2651
                // SQLServer falla por:
2652
                //  Error de desbordamiento aritm?tico al convertir float al tipo de datos numeric.
2653
                // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
2654
                // Algeria intenta asignarle un valor de 2320972.0 y falla.
2655
                // Habria que repasar el proveedor de shape.
2656

    
2657
//                if (p > 1) {
2658
//                    if (s < 0) {
2659
//                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
2660
//                    }
2661
//                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
2662
//                }
2663
                return MessageFormat.format(type_double, precision, scale);
2664
            case DataTypes.DECIMAL:
2665
                if (precision < 1) {
2666
                    precision = 20;
2667
                }
2668
                if (scale < 0) {
2669
                    scale = 10;
2670
                }
2671
                return MessageFormat.format(type_bigdecimal, precision, scale);
2672
            case DataTypes.FLOAT:
2673
                return MessageFormat.format(type_float, precision, scale);
2674
            case DataTypes.INT:
2675
                return MessageFormat.format(type_int, precision, scale);
2676
            case DataTypes.LONG:
2677
                return MessageFormat.format(type_long, precision, scale);
2678
            case DataTypes.STRING:
2679
                if (size < 0) {
2680
                    return type_string;
2681
                } else if (size < 4096) {
2682
                    return MessageFormat.format(type_string_p, size);
2683
                }
2684
                return type_string;
2685
            case DataTypes.TIME:
2686
                return type_time;
2687
            case DataTypes.TIMESTAMP:
2688
                return type_timestamp;
2689
            case DataTypes.VERSION:
2690
                return type_version;
2691
            case DataTypes.URI:
2692
                return type_URI;
2693
            case DataTypes.URL:
2694
                return type_URL;
2695
            case DataTypes.FILE:
2696
                return type_FILE;
2697
            case DataTypes.FOLDER:
2698
                return type_FOLDER;
2699
            default:
2700
                return null;
2701
        }
2702
    }
2703

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

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

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

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

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

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

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

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

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

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

    
2777
    @Override
2778
    public TableNameBuilder createTableNameBuilder() {
2779
        return new TableNameBuilderBase();
2780
    }
2781

    
2782
    protected SelectColumnBuilder createSelectColumnBuilder() {
2783
        return new SelectColumnBuilderBase();
2784
    }
2785

    
2786
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2787
        return new UpdateColumnBuilderBase();
2788
    }
2789

    
2790
    protected InsertColumnBuilder createInsertColumnBuilder() {
2791
        return new InsertColumnBuilderBase();
2792
    }
2793

    
2794
    protected OrderByBuilder createOrderByBuilder() {
2795
        return new OrderByBuilderBase();
2796
    }
2797

    
2798
    protected FromBuilder createFromBuilder() {
2799
        return new FromBuilderBase();
2800
    }
2801

    
2802
    protected SelectBuilder createSelectBuilder() {
2803
        return new SelectBuilderBase();
2804
    }
2805

    
2806
    protected UpdateBuilder createUpdateBuilder() {
2807
        return new UpdateBuilderBase();
2808
    }
2809

    
2810
    protected DeleteBuilder createDeleteBuilder() {
2811
        return new DeleteBuilderBase();
2812
    }
2813

    
2814
    protected GrantBuilder createGrantBuilder() {
2815
        return new GrantBuilderBase();
2816
    }
2817

    
2818
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2819
        return new GrantRoleBuilderBase(table, role);
2820
    }
2821

    
2822
    protected DropTableBuilder createDropTableBuilder() {
2823
        return new DropTableBuilderBase();
2824
    }
2825

    
2826
    protected CreateTableBuilder createCreateTableBuilder() {
2827
        return new CreateTableBuilderBase();
2828
    }
2829

    
2830
    protected AlterTableBuilder createAlterTableBuilder() {
2831
        return new AlterTableBuilderBase();
2832
    }
2833

    
2834
    protected InsertBuilder createInsertBuilder() {
2835
        return new InsertBuilderBase();
2836
    }
2837

    
2838
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2839
        return new UpdateTableStatisticsBuilderBase();
2840
    }
2841

    
2842
    protected CreateIndexBuilder createCreateIndexBuilder() {
2843
        return new CreateIndexBuilderBase();
2844
    }
2845

    
2846
    @Override
2847
    public SelectBuilder select() {
2848
        if (this.select == null) {
2849
            this.select = this.createSelectBuilder();
2850
        }
2851
        return this.select;
2852
    }
2853

    
2854
    @Override
2855
    public UpdateBuilder update() {
2856
        if (this.update == null) {
2857
            this.update = this.createUpdateBuilder();
2858
        }
2859
        return this.update;
2860
    }
2861

    
2862
    @Override
2863
    public UpdateTableStatisticsBuilder update_table_statistics() {
2864
        if (this.update_table_statistics == null) {
2865
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2866
        }
2867
        return this.update_table_statistics;
2868
    }
2869

    
2870
    @Override
2871
    public DropTableBuilder drop_table() {
2872
        if (this.drop_table == null) {
2873
            this.drop_table = this.createDropTableBuilder();
2874
        }
2875
        return this.drop_table;
2876
    }
2877

    
2878
    @Override
2879
    public CreateIndexBuilder create_index() {
2880
        if (this.create_index == null) {
2881
            this.create_index = this.createCreateIndexBuilder();
2882
        }
2883
        return this.create_index;
2884
    }
2885

    
2886
    @Override
2887
    public DeleteBuilder delete() {
2888
        if (this.delete == null) {
2889
            this.delete = this.createDeleteBuilder();
2890
        }
2891
        return this.delete;
2892
    }
2893

    
2894
    @Override
2895
    public InsertBuilder insert() {
2896
        if (this.insert == null) {
2897
            this.insert = this.createInsertBuilder();
2898
        }
2899
        return this.insert;
2900
    }
2901

    
2902
    @Override
2903
    public TableNameBuilder table_name() {
2904
        if (this.table_name == null) {
2905
            this.table_name = this.createTableNameBuilder();
2906
        }
2907
        return this.table_name;
2908
    }
2909

    
2910
    
2911
    @Override
2912
    public AlterTableBuilder alter_table() {
2913
        if (this.alter_table == null) {
2914
            this.alter_table = this.createAlterTableBuilder();
2915
        }
2916
        return this.alter_table;
2917
    }
2918

    
2919
    @Override
2920
    public CreateTableBuilder create_table() {
2921
        if (this.create_table == null) {
2922
            this.create_table = this.createCreateTableBuilder();
2923
        }
2924
        return this.create_table;
2925
    }
2926

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

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

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

    
2978
    protected Formatter formatter() {
2979
        return ExpressionBuilder.EMPTY_FORMATTER;
2980
    }
2981

    
2982
    @Override
2983
    public String toString() {
2984
        return this.toString(formatter());
2985
    }
2986

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

    
3019
    @Override
3020
    public CountBuilder count() {
3021
        return new CountBuilderBase();
3022
    }
3023

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

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

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

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