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

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

    
52
@SuppressWarnings("UseSpecificCatch")
53
public class SQLBuilderBase implements SQLBuilder {
54

    
55
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
56

    
57
    protected SelectBuilder select;
58
    protected UpdateBuilder update;
59
    protected InsertBuilder insert;
60
    protected DeleteBuilder delete;
61
    protected AlterTableBuilder alter_table;
62
    protected CreateTableBuilder create_table;
63
    protected GrantBuilder grant;
64
    protected DropTableBuilder drop_table;
65
    protected UpdateTableStatisticsBuilder update_table_statistics;
66
    protected CreateIndexBuilder create_index;
67

    
68
    protected abstract class AbstractStatementPart extends AbstractValue {
69

    
70
    }
71

    
72
    protected abstract class AbstractStatement extends AbstractStatementPart {
73

    
74
    }
75

    
76
    protected class ColumnDescriptorBase implements ColumnDescriptor {
77

    
78
        private String name;
79
        private int type;
80
        private int type_p;
81
        private int type_s;
82
        private boolean isPk;
83
        private boolean _allowNulls;
84
        private boolean _isAutomatic;
85
        private Object defaultValue;
86
        private int geom_type;
87
        private int geom_subtype;
88
        private Object geom_srsdbcode;
89
        private boolean _isIndexed;
90
        private DataStoreParameters parameters = null;
91

    
92
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
93
            this.name = name;
94
            this.type = type;
95
            this.type_p = -1;
96
            this.type_s = -1;
97
            this.isPk = false;
98
            this._allowNulls = true;
99
            this._isAutomatic = false;
100
            this.defaultValue = defaultValue;
101
            this.geom_type = Geometry.TYPES.GEOMETRY;
102
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
103
            this.geom_srsdbcode = null;
104
            this._isIndexed = false;
105
        }
106

    
107
        public ColumnDescriptorBase(String name, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
108
            this.name = name;
109
            this.type = type;
110
            this.type_p = type_p;
111
            this.type_s = type_s;
112
            this.isPk = isPk;
113
            this._allowNulls = allowNulls;
114
            this._isAutomatic = isAutomatic;
115
            this.defaultValue = defaultValue;
116
            this.geom_type = Geometry.TYPES.GEOMETRY;
117
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
118
            this.geom_srsdbcode = null;
119
            this._isIndexed = isIndexed;
120
        }
121

    
122
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
123
            this.name = name;
124
            this.type = DataTypes.GEOMETRY;
125
            this.type_p = 0;
126
            this.type_s = 0;
127
            this.isPk = false;
128
            this._allowNulls = allowNulls;
129
            this._isAutomatic = false;
130
            this.defaultValue = null;
131
            this.geom_type = geom_type;
132
            this.geom_subtype = geom_subtype;
133
            this.geom_srsdbcode = srs_id(proj);
134
            this._isIndexed = isIndexed;
135
        }
136

    
137
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
138
            this.name = name;
139
            this.type = DataTypes.GEOMETRY;
140
            this.type_p = 0;
141
            this.type_s = 0;
142
            this.isPk = false;
143
            this._allowNulls = allowNulls;
144
            this._isAutomatic = false;
145
            this.defaultValue = null;
146
            this.geom_type = geom_type;
147
            this.geom_subtype = geom_subtype;
148
            this.geom_srsdbcode = srsdbcode;
149
            this._isIndexed = isIndexed;
150
        }
151

    
152
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
153
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
154
            this.type_p = fad.getPrecision();
155
            this.type_s = fad.getSize();
156
            this.isPk = fad.isPrimaryKey();
157
            this._allowNulls = fad.allowNull();
158
            this._isAutomatic = fad.isAutomatic();
159
            this._isIndexed = fad.isIndexed();
160

    
161
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
162
                this.geom_type = fad.getGeomType().getType();
163
                this.geom_subtype = fad.getGeomType().getSubType();
164
                this.geom_srsdbcode = fad.getSRS();
165
            }
166
        }
167
    
168

    
169
        @Override
170
        public String getName() {
171
            return this.name;
172
        }
173

    
174
        @Override
175
        public void setName(String name) {
176
            this.name = name;
177
        }
178

    
179
        @Override
180
        public int getType() {
181
            return this.type;
182
        }
183

    
184
        @Override
185
        public void setType(int type) {
186
            this.type = type;
187
        }
188

    
189
        @Override
190
        public int getPrecision() {
191
            return type_p;
192
        }
193

    
194
        @Override
195
        public void setPrecision(int precision) {
196
            this.type_p = precision;
197
        }
198

    
199
        @Override
200
        public int getSize() {
201
            return type_s;
202
        }
203

    
204
        @Override
205
        public void setSize(int size) {
206
            this.type_s = size;
207
        }
208

    
209
        @Override
210
        public boolean isPrimaryKey() {
211
            return isPk;
212
        }
213

    
214
        @Override
215
        public void setIsPrimaryKey(boolean isPk) {
216
            this.isPk = isPk;
217
        }
218

    
219
        @Override
220
        public boolean allowNulls() {
221
            return _allowNulls;
222
        }
223

    
224
        @Override
225
        public void setAllowNulls(boolean allowNulls) {
226
            this._allowNulls = allowNulls;
227
        }
228

    
229
        @Override
230
        public boolean isAutomatic() {
231
            return _isAutomatic;
232
        }
233

    
234
        @Override
235
        public boolean isIndexed() {
236
            return _isIndexed;
237
        }
238

    
239
        @Override
240
        public void setIsAutomatic(boolean isAutomatic) {
241
            this._isAutomatic = isAutomatic;
242
        }
243

    
244
        @Override
245
        public Object getDefaultValue() {
246
            return defaultValue;
247
        }
248

    
249
        @Override
250
        public void setDefaultValue(Object defaultValue) {
251
            this.defaultValue = defaultValue;
252
        }
253

    
254
        @Override
255
        public int getGeometryType() {
256
            return geom_type;
257
        }
258

    
259
        @Override
260
        public void setGeometryType(int geom_type) {
261
            this.geom_type = geom_type;
262
        }
263

    
264
        @Override
265
        public int getGeometrySubtype() {
266
            return geom_subtype;
267
        }
268

    
269
        @Override
270
        public void setGeometrySubtype(int geom_subtype) {
271
            this.geom_subtype = geom_subtype;
272
        }
273

    
274
        @Override
275
        public Object getGeometrySRSId() {
276
            return geom_srsdbcode;
277
        }
278

    
279
        @Override
280
        public void setGeometrySRSId(Object geom_srsid) {
281
            this.geom_srsdbcode = geom_srsid;
282
        }
283

    
284
        @Override
285
        public boolean isGeometry() {
286
            return this.type == DataTypes.GEOMETRY;
287
        }
288

    
289
        private void setStoreParameters(DataStoreParameters parameters) {
290
            this.parameters = parameters;
291
        }
292

    
293
        @Override
294
        public DataStoreParameters getStoreParameters() {
295
            return this.parameters;
296
        }
297
    }
298
//
299
//    public class ColumnBase extends AbstractValue implements Column {
300
//
301
//        protected ColumnDescriptor descriptor;
302
//        protected String name;
303
//
304
//        public ColumnBase(ColumnDescriptor descriptor) {
305
//            this.name = descriptor.getName();
306
//            this.descriptor = descriptor;
307
//        }
308
//
309
//        public ColumnBase(String name) {
310
//            this.name = name;
311
//            this.descriptor = null;
312
//        }
313
//
314
//        @Override
315
//        public ColumnDescriptor getDescriptor() {
316
//            return descriptor;
317
//        }
318
//
319
//        @Override
320
//        public String name() {
321
//            return this.name;
322
//        }
323
//
324
//        @Override
325
//        public String toString() {
326
//            return this.toString(formatter());
327
//        }
328
//
329
//        @Override
330
//        public String toString(Formatter<Value> formatter) {
331
//            if (formatter.canApply(this)) {
332
//                return formatter.format(this);
333
//            }
334
//            return as_identifier(this.name);
335
//        }
336
//
337
//        @Override
338
//        public int compareTo(ExpressionBuilder.Variable o) {
339
//            return this.name.compareTo(o.name());
340
//        }
341
//
342
//        @Override
343
//        public boolean equals(Object obj) {
344
//            if (!(obj instanceof ExpressionBuilder.Variable)) {
345
//                return false;
346
//            }
347
//            return this.name.equals(((ExpressionBuilder.Variable) obj).name());
348
//        }
349
//
350
//        @Override
351
//        public int hashCode() {
352
//            int hash = 7;
353
//            hash = 37 * hash + Objects.hashCode(this.name);
354
//            return hash;
355
//        }
356
//
357
//    }
358

    
359
    public class TableNameBuilderBase
360
            extends AbstractStatementPart
361
            implements TableNameBuilder {
362

    
363
        public String tableName;
364
        public String schemaName;
365
        private String databaseName;
366

    
367
        public TableNameBuilderBase() {
368
        }
369

    
370
        @Override
371
        public void accept(Visitor visitor, VisitorFilter filter) {
372
            if (filter.accept(this)) {
373
                visitor.visit(this);
374
            }
375
        }
376

    
377
        @Override
378
        public TableNameBuilder database(String name) {
379
            this.databaseName = name;
380
            return this;
381
        }
382

    
383
        @Override
384
        public TableNameBuilder schema(String name) {
385
            if (support_schemas()) {
386
                this.schemaName = name;
387
            }
388
            return this;
389
        }
390

    
391
        @Override
392
        public TableNameBuilder name(String name) {
393
            this.tableName = name;
394
            return this;
395
        }
396

    
397
        @Override
398
        public String getDatabase() {
399
            return this.databaseName;
400
        }
401

    
402
        @Override
403
        public String getSchema() {
404
            return this.schemaName;
405
        }
406

    
407
        @Override
408
        public String getName() {
409
            return this.tableName;
410
        }
411

    
412
        @Override
413
        public boolean has_schema() {
414
            if (!support_schemas()) {
415
                return false;
416
            }
417
            return !StringUtils.isEmpty(this.schemaName);
418
        }
419

    
420
        @Override
421
        public boolean has_database() {
422
            return !StringUtils.isEmpty(this.databaseName);
423
        }
424

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

    
430
        @Override
431
        public String toString(Formatter<Value> formatter) {
432
            if (formatter.canApply(this)) {
433
                return formatter.format(this);
434
            }
435
            if (this.has_database()) {
436
                if (this.has_schema()) {
437
                    return as_identifier(this.databaseName) + "."
438
                            + as_identifier(this.schemaName) + "."
439
                            + as_identifier(this.tableName);
440
                }
441
            } else {
442
                if (this.has_schema()) {
443
                    return as_identifier(this.schemaName) + "."
444
                            + as_identifier(this.tableName);
445
                }
446
            }
447
            return as_identifier(this.tableName);
448
        }
449

    
450
    }
451

    
452
    public class CountBuilderBase
453
            extends AbstractStatementPart
454
            implements CountBuilder {
455

    
456
        protected Value value;
457
        protected boolean distinct;
458
        protected boolean all;
459

    
460
        public CountBuilderBase() {
461
            this.value = null;
462
            this.distinct = false;
463
            this.all = false;
464
        }
465

    
466
        @Override
467
        public CountBuilder all() {
468
            this.all = true;
469
            return this;
470
        }
471

    
472
        @Override
473
        public CountBuilder column(Value value) {
474
            this.value = value;
475
            return this;
476
        }
477

    
478
        @Override
479
        public CountBuilder distinct() {
480
            this.distinct = true;
481
            return this;
482
        }
483

    
484
        @Override
485
        public String toString() {
486
            return this.toString(formatter());
487
        }
488

    
489
        @Override
490
        public String toString(Formatter formatter) {
491
            if (formatter.canApply(this)) {
492
                return formatter.format(this);
493
            }
494
            if (this.all) {
495
                return "COUNT(*)";
496
            }
497
            if (this.distinct) {
498
                return MessageFormat.format(
499
                        "COUNT(DISTINCT {0})",
500
                        value.toString(formatter)
501
                );
502
            }
503
            return MessageFormat.format(
504
                    "COUNT({0})",
505
                    value.toString(formatter)
506
            );
507
        }
508

    
509
    }
510

    
511
    public class FromBuilderBase
512
            extends AbstractStatementPart
513
            implements FromBuilder {
514

    
515
        protected TableNameBuilder tableName = null;
516
        private String subquery = null;
517
        private String passthrough = null;
518

    
519
        @Override
520
        public TableNameBuilder table() {
521
            if (tableName == null) {
522
                this.tableName = createTableNameBuilder();
523
            }
524
            return this.tableName;
525
        }
526

    
527
        @Override
528
        public void accept(Visitor visitor, VisitorFilter filter) {
529
            if (filter.accept(this)) {
530
                visitor.visit(this);
531
            }
532
            if (this.tableName != null) {
533
                this.tableName.accept(visitor, filter);
534
            }
535
        }
536

    
537
        @Override
538
        public FromBuilder custom(String passthrough) {
539
            this.passthrough = passthrough;
540
            return this;
541
        }
542

    
543
        @Override
544
        public FromBuilder subquery(String subquery) {
545
            this.subquery = subquery;
546
            return this;
547
        }
548

    
549
        @Override
550
        public String toString() {
551
            return this.toString(formatter());
552
        }
553

    
554
        @Override
555
        public String toString(Formatter<Value> formatter) {
556
            if (formatter.canApply(this)) {
557
                return formatter.format(this);
558
            }
559
            if (!StringUtils.isEmpty(passthrough)) {
560
                return passthrough;
561
            }
562
            if (!StringUtils.isEmpty(subquery)) {
563
                return "( " + this.subquery + ") as _subquery_alias_ ";
564
            }
565
            return this.tableName.toString(formatter);
566
        }
567

    
568
    }
569

    
570
    public class SelectColumnBuilderBase
571
            extends AbstractStatementPart
572
            implements SelectColumnBuilder {
573

    
574
        private Variable name = null;
575
        private String alias = null;
576
        private Value value = null;
577
        private boolean asGeometry = false;
578

    
579
        @Override
580
        public void accept(Visitor visitor, VisitorFilter filter) {
581
            if (filter.accept(this)) {
582
                visitor.visit(this);
583
            }
584
            if (this.name != null) {
585
                this.name.accept(visitor, filter);
586
            }
587
            if (this.value != null) {
588
                this.value.accept(visitor, filter);
589
            }
590
        }
591

    
592
        @Override
593
        public SelectColumnBuilder name(String name) {
594
            String quote = quote_for_identifiers();
595
            if (name.startsWith(quote)) {
596
                // Remove quotes
597
                name = name.substring(1, name.length() - 1);
598
            }
599
            this.name = expression().variable(name);
600
            this.value = null;
601
            this.asGeometry = false;
602
            return this;
603
        }
604

    
605
        @Override
606
        public SelectColumnBuilder all() {
607
            this.name = null;
608
            this.value = expression().custom("*");
609
            this.asGeometry = false;
610
            return this;
611
        }
612

    
613
        @Override
614
        public SelectColumnBuilder as_geometry() {
615
            this.asGeometry = true;
616
            return this;
617
        }
618

    
619
        @Override
620
        public SelectColumnBuilder value(Value value) {
621
            this.value = value;
622
            this.name = null;
623
            return this;
624
        }
625

    
626
        @Override
627
        public SelectColumnBuilder as(String alias) {
628
            this.alias = alias;
629
            return this;
630
        }
631

    
632
        @Override
633
        public String getName() {
634
            return this.name.name();
635
        }
636

    
637
        @Override
638
        public String getAlias() {
639
            return this.alias;
640
        }
641

    
642
        @Override
643
        public String getValue() {
644
            return this.alias;
645
        }
646

    
647
        @Override
648
        public String toString() {
649
            return this.toString(formatter());
650
        }
651

    
652
        @Override
653
        public String toString(Formatter<Value> formatter) {
654
            if (formatter.canApply(this)) {
655
                return formatter.format(this);
656
            }
657
            StringBuilder builder = new StringBuilder();
658
            if (this.asGeometry) {
659
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
660
            } else {
661
                if (this.name != null) {
662
                    builder.append(this.name.toString(formatter));
663
                } else {
664
                    builder.append(this.value.toString(formatter));
665
                }
666
            }
667
            if (this.alias != null) {
668
                builder.append(" AS ");
669
                builder.append(as_identifier(this.alias));
670
            }
671
            return builder.toString();
672
        }
673
    }
674

    
675
    public class OrderByBuilderBase
676
            extends AbstractStatementPart
677
            implements OrderByBuilder {
678

    
679
        protected String value;
680
        protected String custom;
681
        protected boolean ascending;
682

    
683
        public OrderByBuilderBase() {
684
            this.ascending = true;
685
        }
686

    
687
        @Override
688
        public void accept(Visitor visitor, VisitorFilter filter) {
689
            if (filter.accept(this)) {
690
                visitor.visit(this);
691
            }
692
        }
693

    
694
        @Override
695
        public OrderByBuilder column(String name) {
696
            this.value = name;
697
            return this;
698
        }
699

    
700
        @Override
701
        public OrderByBuilder custom(String order) {
702
            this.custom = order;
703
            return this;
704
        }
705

    
706
        @Override
707
        public OrderByBuilder ascending() {
708
            this.ascending = true;
709
            return this;
710
        }
711

    
712
        @Override
713
        public OrderByBuilder ascending(boolean asc) {
714
            this.ascending = asc;
715
            return this;
716
        }
717

    
718
        @Override
719
        public OrderByBuilder descending() {
720
            this.ascending = false;
721
            return this;
722
        }
723

    
724
        @Override
725
        public String toString() {
726
            return this.toString(formatter());
727
        }
728

    
729
        @Override
730
        public String toString(Formatter<Value> formatter) {
731
            if (formatter.canApply(this)) {
732
                return formatter.format(this);
733
            }
734
            if (!StringUtils.isEmpty(this.custom)) {
735
                return this.custom;
736
            }
737
            if (this.ascending) {
738
                return as_identifier(this.value) + " ASC";
739
            }
740
            return as_identifier(this.value) + " DESC";
741
        }
742
    }
743

    
744
    public class SelectBuilderBase
745
            extends AbstractStatement
746
            implements SelectBuilder {
747

    
748
        protected FromBuilder from;
749
        protected ExpressionBuilder where;
750
        protected long limit = -1;
751
        protected long offset = -1;
752
        protected List<SelectColumnBuilder> columns;
753
        protected List<OrderByBuilder> order_by;
754
        protected boolean distinct;
755

    
756
        public SelectBuilderBase() {
757
            this.columns = new ArrayList<>();
758
            this.distinct = false;
759
        }
760

    
761
        @Override
762
        public void accept(Visitor visitor, VisitorFilter filter) {
763
            if (filter.accept(this)) {
764
                visitor.visit(this);
765
            }
766
            for (SelectColumnBuilder column : columns) {
767
                column.accept(visitor, filter);
768
            }
769
            if (this.has_from()) {
770
                this.from.accept(visitor, filter);
771
            }
772
            if (this.has_where()) {
773
                this.where.accept(visitor, filter);
774
            }
775
            if (this.has_order_by()) {
776
                for (OrderByBuilder order : order_by) {
777
                    order.accept(visitor, filter);
778
                }
779
            }
780
        }
781

    
782
        @Override
783
        public SelectBuilder distinct() {
784
            this.distinct = true;
785
            return this;
786
        }
787

    
788
        @Override
789
        public SelectColumnBuilder column() {
790
            SelectColumnBuilder builder = createSelectColumnBuilder();
791
            this.columns.add(builder);
792
            return builder;
793
        }
794

    
795
        @Override
796
        public boolean has_column(String name) {
797
            for (SelectColumnBuilder column : columns) {
798
                if (name.equals(column.getName())) {
799
                    return true;
800
                }
801
            }
802
            return false;
803
        }
804

    
805
        @Override
806
        public FromBuilder from() {
807
            if (this.from == null) {
808
                this.from = createFromBuilder();
809
            }
810
            return this.from;
811
        }
812

    
813
        @Override
814
        public boolean has_from() {
815
            return this.from != null;
816
        }
817

    
818
        @Override
819
        public ExpressionBuilder where() {
820
            if (this.where == null) {
821
                this.where = createExpressionBuilder();
822
            }
823
            return this.where;
824
        }
825

    
826
        @Override
827
        public boolean has_where() {
828
            if (this.where == null) {
829
                return false;
830
            }
831
            return this.where.value() != null;
832
        }
833

    
834
        @Override
835
        public SelectBuilder limit(long limit) {
836
            this.limit = limit;
837
            return this;
838
        }
839

    
840
        @Override
841
        public SelectBuilder limit(Long limit) {
842
            if (limit == null) {
843
                this.limit = 0;
844
            } else {
845
                this.limit = limit;
846
            }
847
            return this;
848
        }
849

    
850
        @Override
851
        public boolean has_limit() {
852
            return this.limit > 0;
853
        }
854

    
855
        @Override
856
        public SelectBuilder offset(long offset) {
857
            this.offset = offset;
858
            return this;
859
        }
860

    
861
        @Override
862
        public boolean has_offset() {
863
            return this.offset > 0;
864
        }
865

    
866
        @Override
867
        public OrderByBuilder order_by() {
868
            if (this.order_by == null) {
869
                this.order_by = new ArrayList<>();
870
            }
871
            OrderByBuilder order = createOrderByBuilder();
872
            this.order_by.add(order);
873
            return order;
874
        }
875

    
876
        @Override
877
        public boolean has_order_by() {
878
            if (this.order_by == null) {
879
                return false;
880
            }
881
            return !this.order_by.isEmpty();
882
        }
883

    
884
        protected boolean isValid(StringBuilder message) {
885
            if (message == null) {
886
                message = new StringBuilder();
887
            }
888
            if (this.has_offset() && !this.has_order_by()) {
889
                // Algunos gestores de BBDD requieren que se especifique un
890
                // orden para poder usar OFFSET. Como eso parece buena idea para
891
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
892
                // siempre.
893
                message.append("Can't use OFFSET without an ORDER BY.");
894
                return false;
895
            }
896
            return true;
897
        }
898

    
899
        @Override
900
        public String toString() {
901
            return this.toString(formatter());
902
        }
903

    
904
        @Override
905
        public String toString(Formatter<Value> formatter) {
906
            if (formatter.canApply(this)) {
907
                return formatter.format(this);
908
            }
909
            StringBuilder builder = new StringBuilder();
910
            if (!this.isValid(builder)) {
911
                throw new IllegalStateException(builder.toString());
912
            }
913
            builder.append("SELECT ");
914
            if (this.distinct) {
915
                builder.append("DISTINCT ");
916
            }
917
            boolean first = true;
918
            for (SelectColumnBuilder column : columns) {
919
                if (first) {
920
                    first = false;
921
                } else {
922
                    builder.append(", ");
923
                }
924
                builder.append(column.toString(formatter));
925
            }
926

    
927
            if (this.has_from()) {
928
                builder.append(" FROM ");
929
                builder.append(this.from.toString(formatter));
930
            }
931
            if (this.has_where()) {
932
                builder.append(" WHERE ");
933
                builder.append(this.where.toString(formatter));
934
            }
935

    
936
            if (this.has_order_by()) {
937
                builder.append(" ORDER BY ");
938
                first = true;
939
                for (OrderByBuilder item : this.order_by) {
940
                    if (first) {
941
                        first = false;
942
                    } else {
943
                        builder.append(", ");
944
                    }
945
                    builder.append(item.toString(formatter));
946
                }
947
            }
948

    
949
            if (this.has_limit()) {
950
                builder.append(" LIMIT ");
951
                builder.append(this.limit);
952
            }
953
            if (this.has_offset()) {
954
                builder.append(" OFFSET ");
955
                builder.append(this.offset);
956
            }
957
            return builder.toString();
958

    
959
        }
960
    }
961

    
962
    public class DropTableBuilderBase
963
            extends AbstractStatement
964
            implements DropTableBuilder {
965

    
966
        protected TableNameBuilder table;
967

    
968
        @Override
969
        public TableNameBuilder table() {
970
            if (table == null) {
971
                table = createTableNameBuilder();
972
            }
973
            return table;
974
        }
975

    
976
        @Override
977
        public void accept(Visitor visitor, VisitorFilter filter) {
978
            if (filter.accept(this)) {
979
                visitor.visit(this);
980
            }
981
            this.table.accept(visitor, filter);
982
        }
983

    
984
        @Override
985
        public String toString() {
986
            return this.toString(formatter());
987
        }
988

    
989
        @Override
990
        public String toString(Formatter<Value> formatter) {
991
            if (formatter.canApply(this)) {
992
                return formatter.format(this);
993
            }
994
            StringBuilder builder = new StringBuilder();
995
            boolean first = true;
996
            for (String sql : toStrings(formatter)) {
997
                if (StringUtils.isEmpty(sql)) {
998
                    continue;
999
                }
1000
                if (first) {
1001
                    first = false;
1002
                } else {
1003
                    builder.append("; ");
1004
                }
1005
                builder.append(sql);
1006
            }
1007
            return builder.toString();
1008
        }
1009

    
1010
        @Override
1011
        public List<String> toStrings() {
1012
            return this.toStrings(formatter());
1013
        }
1014

    
1015
        @Override
1016
        public List<String> toStrings(Formatter formatter) {
1017
            List<String> sqls = new ArrayList<>();
1018

    
1019
            sqls.add(
1020
                    MessageFormat.format(
1021
                            STMT_DROP_TABLE_table,
1022
                            this.table.toString(formatter)
1023
                    )
1024
            );
1025
            String sql;
1026
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1027
                if (this.table.has_schema()) {
1028
                    sql = MessageFormat.format(
1029
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1030
                            as_string(this.table.getSchema()),
1031
                            as_string(this.table.getName())
1032
                    );
1033
                } else {
1034
                    sql = MessageFormat.format(
1035
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1036
                            as_identifier(this.table.getName())
1037
                    );
1038
                }
1039
                if (!StringUtils.isEmpty(sql)) {
1040
                    sqls.add(sql);
1041
                }
1042
            }
1043
            return sqls;
1044
        }
1045
    }
1046

    
1047
    public class GrantRoleBuilderBase
1048
            extends AbstractStatementPart
1049
            implements GrantRoleBuilder {
1050

    
1051
        protected TableNameBuilder table;
1052
        protected String role;
1053
        protected Set<Privilege> privileges;
1054

    
1055
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1056
            this.table = table;
1057
            this.role = role;
1058
            this.privileges = new HashSet<>();
1059
        }
1060

    
1061
        @Override
1062
        public GrantRoleBuilder privilege(Privilege privilege) {
1063
            privileges.add(privilege);
1064
            return this;
1065
        }
1066

    
1067
        @Override
1068
        public GrantRoleBuilder select() {
1069
            privileges.add(Privilege.SELECT);
1070
            return this;
1071
        }
1072

    
1073
        @Override
1074
        public GrantRoleBuilder update() {
1075
            privileges.add(Privilege.UPDATE);
1076
            return this;
1077
        }
1078

    
1079
        @Override
1080
        public GrantRoleBuilder insert() {
1081
            privileges.add(Privilege.INSERT);
1082
            return this;
1083
        }
1084

    
1085
        @Override
1086
        public GrantRoleBuilder delete() {
1087
            privileges.add(Privilege.DELETE);
1088
            return this;
1089
        }
1090

    
1091
        @Override
1092
        public GrantRoleBuilder truncate() {
1093
            privileges.add(Privilege.TRUNCATE);
1094
            return this;
1095
        }
1096

    
1097
        @Override
1098
        public GrantRoleBuilder reference() {
1099
            privileges.add(Privilege.REFERENCE);
1100
            return this;
1101
        }
1102

    
1103
        @Override
1104
        public GrantRoleBuilder trigger() {
1105
            privileges.add(Privilege.TRIGGER);
1106
            return this;
1107
        }
1108

    
1109
        @Override
1110
        public GrantRoleBuilder all() {
1111
            privileges.add(Privilege.ALL);
1112
            return this;
1113
        }
1114

    
1115
        protected String getPrivilegeName(Privilege privilege) {
1116
            switch (privilege) {
1117
                case DELETE:
1118
                    return "DELETE";
1119
                case INSERT:
1120
                    return "INSERT";
1121
                case REFERENCE:
1122
                    return "REFERENCE";
1123
                case SELECT:
1124
                    return "SELECT";
1125
                case TRIGGER:
1126
                    return "TRIGGER";
1127
                case TRUNCATE:
1128
                    return "TRUNCATE";
1129
                case UPDATE:
1130
                    return "UPDATE";
1131
                case ALL:
1132
                default:
1133
                    return "ALL";
1134
            }
1135
        }
1136

    
1137
        @Override
1138
        public String toString() {
1139
            return this.toString(formatter());
1140
        }
1141

    
1142
        @Override
1143
        public String toString(Formatter<Value> formatter) {
1144
            if (formatter.canApply(this)) {
1145
                return formatter.format(this);
1146
            }
1147
            StringBuilder builder = new StringBuilder();
1148
            boolean first = true;
1149
            for (Privilege privilege : privileges) {
1150
                if (first) {
1151
                    first = false;
1152
                } else {
1153
                    builder.append(", ");
1154
                }
1155
                builder.append(this.getPrivilegeName(privilege));
1156
            }
1157
            String sql = MessageFormat.format(
1158
                    STMT_GRANT_privileges_ON_table_TO_role,
1159
                    builder.toString(),
1160
                    table.toString(formatter),
1161
                    role
1162
            );
1163
            return sql;
1164
        }
1165
    }
1166

    
1167
    public class GrantBuilderBase
1168
            extends AbstractStatement
1169
            implements GrantBuilder {
1170

    
1171
        protected TableNameBuilder table;
1172
        protected Map<String, GrantRoleBuilder> roles;
1173

    
1174
        public GrantBuilderBase() {
1175
            this.roles = new HashMap<>();
1176
        }
1177

    
1178
        @Override
1179
        public TableNameBuilder table() {
1180
            if (table == null) {
1181
                table = createTableNameBuilder();
1182
            }
1183
            return table;
1184
        }
1185

    
1186
        @Override
1187
        public void accept(Visitor visitor, VisitorFilter filter) {
1188
            if (filter.accept(this)) {
1189
                visitor.visit(this);
1190
            }
1191
            if (this.table != null) {
1192
                this.table.accept(visitor, filter);
1193
            }
1194
        }
1195

    
1196
        @Override
1197
        public GrantRoleBuilder role(String role) {
1198
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1199
            if (roleBuilder == null) {
1200
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1201
                this.roles.put(role, roleBuilder);
1202
            }
1203
            return roleBuilder;
1204
        }
1205

    
1206
        @Override
1207
        public String toString() {
1208
            return this.toString(formatter());
1209
        }
1210

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

    
1232
        @Override
1233
        public List<String> toStrings() {
1234
            return this.toStrings(formatter());
1235
        }
1236

    
1237
        @Override
1238
        public List<String> toStrings(Formatter formatter) {
1239
            List<String> sqls = new ArrayList<>();
1240
            for (GrantRoleBuilder role : roles.values()) {
1241
                sqls.add(role.toString(formatter));
1242
            }
1243
            return sqls;
1244
        }
1245
    }
1246

    
1247
    public class UpdateColumnBuilderBase
1248
            extends InsertColumnBuilderBase
1249
            implements UpdateColumnBuilder {
1250

    
1251
        public UpdateColumnBuilderBase() {
1252
            super();
1253
        }
1254

    
1255
        @Override
1256
        public UpdateColumnBuilder name(String name) {
1257
            return (UpdateColumnBuilder) super.name(name);
1258
        }
1259

    
1260
        @Override
1261
        public UpdateColumnBuilder with_value(Value value) {
1262
            return (UpdateColumnBuilder) super.with_value(value);
1263
        }
1264

    
1265
    }
1266

    
1267
    public class UpdateBuilderBase
1268
            extends AbstractStatement
1269
            implements UpdateBuilder {
1270

    
1271
        protected ExpressionBuilder where;
1272
        protected List<UpdateColumnBuilder> columns;
1273
        protected TableNameBuilder table;
1274

    
1275
        public UpdateBuilderBase() {
1276
            this.columns = new ArrayList<>();
1277
        }
1278

    
1279
        @Override
1280
        public void accept(Visitor visitor, VisitorFilter filter) {
1281
            if (filter.accept(this)) {
1282
                visitor.visit(this);
1283
            }
1284
            if (this.table != null) {
1285
                this.table.accept(visitor, filter);
1286
            }
1287
            for (UpdateColumnBuilder column : columns) {
1288
                column.accept(visitor, filter);
1289
            }
1290
            if (this.has_where()) {
1291
                this.where.accept(visitor, filter);
1292
            }
1293
        }
1294

    
1295
        @Override
1296
        public ExpressionBuilder where() {
1297
            if (this.where == null) {
1298
                this.where = createExpressionBuilder();
1299
            }
1300
            return this.where;
1301
        }
1302

    
1303
        @Override
1304
        public TableNameBuilder table() {
1305
            if (table == null) {
1306
                table = createTableNameBuilder();
1307
            }
1308
            return table;
1309
        }
1310

    
1311
        @Override
1312
        public UpdateColumnBuilder column() {
1313
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1314
            this.columns.add(column);
1315
            return column;
1316
        }
1317

    
1318
        @Override
1319
        public boolean has_where() {
1320
            return this.where != null;
1321
        }
1322

    
1323
        @Override
1324
        public String toString() {
1325
            return this.toString(formatter());
1326
        }
1327

    
1328
        @Override
1329
        public String toString(Formatter<Value> formatter) {
1330
            if (formatter.canApply(this)) {
1331
                return formatter.format(this);
1332
            }
1333
            /*
1334
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1335
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1336
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1337
             * output_expression [ AS output_name ] [, ...] ]
1338
             */
1339
            StringBuilder columnsAndValues = new StringBuilder();
1340

    
1341
            boolean first = true;
1342
            for (UpdateColumnBuilder column : columns) {
1343
                if (first) {
1344
                    first = false;
1345
                } else {
1346
                    columnsAndValues.append(", ");
1347
                }
1348
                columnsAndValues.append(as_identifier(column.getName()));
1349
                columnsAndValues.append(" = ");
1350
                columnsAndValues.append(column.getValue().toString(formatter));
1351
            }
1352

    
1353
            String sql;
1354
            if (this.has_where()) {
1355
                sql = MessageFormat.format(
1356
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1357
                        this.table.toString(formatter),
1358
                        columnsAndValues.toString(),
1359
                        this.where.toString(formatter)
1360
                );
1361
            } else {
1362
                sql = MessageFormat.format(
1363
                        STMT_UPDATE_table_SET_columnsAndValues,
1364
                        this.table.toString(formatter),
1365
                        columnsAndValues.toString()
1366
                );
1367
            }
1368
            return sql;
1369
        }
1370
    }
1371

    
1372
    public class DeleteBuilderBase
1373
            extends AbstractStatement
1374
            implements DeleteBuilder {
1375

    
1376
        protected ExpressionBuilder where;
1377
        protected TableNameBuilder table;
1378

    
1379
        public DeleteBuilderBase() {
1380
        }
1381

    
1382
        @Override
1383
        public void accept(Visitor visitor, VisitorFilter filter) {
1384
            if (filter.accept(this)) {
1385
                visitor.visit(this);
1386
            }
1387
            if (this.table != null) {
1388
                this.table.accept(visitor, filter);
1389
            }
1390
            if (this.has_where()) {
1391
                this.where.accept(visitor, filter);
1392
            }
1393
        }
1394

    
1395
        @Override
1396
        public ExpressionBuilder where() {
1397
            if (this.where == null) {
1398
                this.where = createExpressionBuilder();
1399
            }
1400
            return this.where;
1401
        }
1402

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

    
1411
        @Override
1412
        public boolean has_where() {
1413
            return this.where != null;
1414
        }
1415

    
1416
        @Override
1417
        public String toString() {
1418
            return this.toString(formatter());
1419
        }
1420

    
1421
        @Override
1422
        public String toString(Formatter<Value> formatter) {
1423
            if (formatter.canApply(this)) {
1424
                return formatter.format(this);
1425
            }
1426
            /*
1427
             * DELETE FROM table_name
1428
             * WHERE some_column=some_value; 
1429
             */
1430
            String sql;
1431
            if (this.has_where()) {
1432
                sql = MessageFormat.format(
1433
                        STMT_DELETE_FROM_table_WHERE_expresion,
1434
                        this.table.toString(formatter),
1435
                        this.where.toString(formatter)
1436
                );
1437
            } else {
1438
                sql = MessageFormat.format(
1439
                        STMT_DELETE_FROM_table,
1440
                        this.table.toString(formatter)
1441
                );
1442
            }
1443
            return sql;
1444
        }
1445
    }
1446

    
1447
    public class CreateIndexBuilderBase
1448
            extends AbstractStatement
1449
            implements CreateIndexBuilder {
1450

    
1451
        protected boolean ifNotExist = false;
1452
        protected boolean isUnique = false;
1453
        protected String indexName;
1454
        protected boolean isSpatial = false;
1455
        protected TableNameBuilder table;
1456
        protected final List<String> columns;
1457

    
1458
        public CreateIndexBuilderBase() {
1459
            this.columns = new ArrayList<>();
1460
        }
1461

    
1462
        @Override
1463
        public CreateIndexBuilder unique() {
1464
            this.isUnique = true;
1465
            return this;
1466
        }
1467

    
1468
        @Override
1469
        public CreateIndexBuilder if_not_exist() {
1470
            this.ifNotExist = true;
1471
            return this;
1472
        }
1473

    
1474
        @Override
1475
        public CreateIndexBuilder name(String name) {
1476
            this.indexName = name;
1477
            return this;
1478
        }
1479

    
1480
        @Override
1481
        public CreateIndexBuilder spatial() {
1482
            this.isSpatial = true;
1483
            return this;
1484
        }
1485

    
1486
        @Override
1487
        public CreateIndexBuilder column(String name) {
1488
            this.columns.add(name);
1489
            return this;
1490
        }
1491

    
1492
        @Override
1493
        public TableNameBuilder table() {
1494
            if (table == null) {
1495
                table = createTableNameBuilder();
1496
            }
1497
            return table;
1498
        }
1499

    
1500
        @Override
1501
        public void accept(Visitor visitor, VisitorFilter filter) {
1502
            if (filter.accept(this)) {
1503
                visitor.visit(this);
1504
            }
1505
            if (this.table != null) {
1506
                this.table.accept(visitor, filter);
1507
            }
1508
        }
1509

    
1510
        @Override
1511
        public String toString() {
1512
            return this.toString(formatter());
1513
        }
1514

    
1515
        @Override
1516
        public String toString(Formatter<Value> formatter) {
1517
            if (formatter.canApply(this)) {
1518
                return formatter.format(this);
1519
            }
1520
            StringBuilder builder = new StringBuilder();
1521
            boolean first = true;
1522
            for (String sql : toStrings(formatter)) {
1523
                if (StringUtils.isEmpty(sql)) {
1524
                    continue;
1525
                }
1526
                if (first) {
1527
                    first = false;
1528
                } else {
1529
                    builder.append("; ");
1530
                }
1531
                builder.append(sql);
1532
            }
1533
            return builder.toString();
1534
        }
1535

    
1536
        @Override
1537
        public List<String> toStrings() {
1538
            return this.toStrings(formatter());
1539
        }
1540

    
1541
        @Override
1542
        public List<String> toStrings(Formatter formatter) {
1543
            StringBuilder builder = new StringBuilder();
1544
            builder.append("CREATE ");
1545
            if (this.isUnique) {
1546
                builder.append("UNIQUE ");
1547
            }
1548
            builder.append("INDEX ");
1549
            if (this.ifNotExist) {
1550
                builder.append("IF NOT EXISTS ");
1551
            }
1552
            builder.append(as_identifier(this.indexName));
1553
            builder.append(" ON ");
1554
            builder.append(this.table.toString(formatter));
1555
            if (this.isSpatial) {
1556
                builder.append(" USING GIST ");
1557
            }
1558
            builder.append(" ( ");
1559
            boolean is_first_column = true;
1560
            for (String column : this.columns) {
1561
                if (is_first_column) {
1562
                    is_first_column = false;
1563
                } else {
1564
                    builder.append(", ");
1565
                }
1566
                builder.append(column);
1567
            }
1568
            builder.append(" )");
1569

    
1570
            List<String> sqls = new ArrayList<>();
1571
            sqls.add(builder.toString());
1572
            return sqls;
1573
        }
1574

    
1575
    }
1576

    
1577
    public class AlterTableBuilderBase
1578
            extends AbstractStatement
1579
            implements AlterTableBuilder {
1580

    
1581
        protected TableNameBuilder table;
1582
        protected List<String> drops;
1583
        protected List<ColumnDescriptor> adds;
1584
        protected List<ColumnDescriptor> alters;
1585
        protected List<Pair<String, String>> renames;
1586

    
1587
        public AlterTableBuilderBase() {
1588
            this.drops = new ArrayList<>();
1589
            this.adds = new ArrayList<>();
1590
            this.alters = new ArrayList<>();
1591
            this.renames = new ArrayList<>();
1592
        }
1593

    
1594
        @Override
1595
        public boolean isEmpty() {
1596
            return this.drops.isEmpty()
1597
                    && this.adds.isEmpty()
1598
                    && this.alters.isEmpty()
1599
                    && this.renames.isEmpty();
1600
        }
1601

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

    
1612
        @Override
1613
        public TableNameBuilder table() {
1614
            if (table == null) {
1615
                table = createTableNameBuilder();
1616
            }
1617
            return table;
1618
        }
1619

    
1620
        @Override
1621
        public AlterTableBuilder drop_column(String columnName) {
1622
            this.drops.add(columnName);
1623
            return this;
1624
        }
1625

    
1626
        @Override
1627
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1628
            this.adds.add(new ColumnDescriptorBase(fad));
1629
            return this;
1630
        }
1631

    
1632
        @Override
1633
        public AlterTableBuilder add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1634
            if (isPk || isAutomatic) {
1635
                allowNulls = false;
1636
            }
1637
            this.adds.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1638
            return this;
1639
        }
1640

    
1641
        @Override
1642
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1643
            if (StringUtils.isEmpty(columnName)) {
1644
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1645
            }
1646
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1647
            return this;
1648
        }
1649

    
1650
        @Override
1651
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1652
            if (StringUtils.isEmpty(columnName)) {
1653
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1654
            }
1655
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1656
            return this;
1657
        }
1658

    
1659
        @Override
1660
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1661
            this.alters.add(new ColumnDescriptorBase(fad));
1662
            return this;
1663
        }
1664

    
1665
        @Override
1666
        public AlterTableBuilder alter_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1667
            if (isPk || isAutomatic) {
1668
                allowNulls = false;
1669
            }
1670
            this.alters.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1671
            return this;
1672
        }
1673

    
1674
        @Override
1675
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1676
            if (StringUtils.isEmpty(columnName)) {
1677
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1678
            }
1679
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1680
            return this;
1681
        }
1682

    
1683
        @Override
1684
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1685
            if (StringUtils.isEmpty(columnName)) {
1686
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1687
            }
1688
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1689
            return this;
1690
        }
1691

    
1692
        @Override
1693
        public AlterTableBuilder rename_column(String source, String target) {
1694
            this.renames.add(new ImmutablePair(source, target));
1695
            return this;
1696
        }
1697

    
1698
        @Override
1699
        public String toString() {
1700
            return this.toString(formatter());
1701
        }
1702

    
1703
        @Override
1704
        public String toString(Formatter<Value> formatter) {
1705
            if (formatter.canApply(this)) {
1706
                return formatter.format(this);
1707
            }
1708
            StringBuilder builder = new StringBuilder();
1709
            boolean first = true;
1710
            for (String sql : toStrings(formatter)) {
1711
                if (StringUtils.isEmpty(sql)) {
1712
                    continue;
1713
                }
1714
                if (first) {
1715
                    first = false;
1716
                } else {
1717
                    builder.append("; ");
1718
                }
1719
                builder.append(sql);
1720
            }
1721
            return builder.toString();
1722
        }
1723

    
1724
        @Override
1725
        public List<String> toStrings() {
1726
            return this.toStrings(formatter());
1727
        }
1728

    
1729
        @Override
1730
        public List<String> toStrings(Formatter formatter) {
1731
            List<String> sqls = new ArrayList<>();
1732
            if (this.isEmpty()) {
1733
                return sqls;
1734
            }
1735
            for (String column : drops) {
1736
                StringBuilder builder = new StringBuilder();
1737
                builder.append("ALTER TABLE ");
1738
                builder.append(this.table.toString(formatter));
1739
                builder.append(" DROP COLUMN IF EXISTS ");
1740
                builder.append(as_identifier(column));
1741
                sqls.add(builder.toString());
1742
            }
1743
            for (ColumnDescriptor column : adds) {
1744
                StringBuilder builder = new StringBuilder();
1745
                builder.append("ALTER TABLE ");
1746
                builder.append(this.table.toString(formatter));
1747
                builder.append(" ADD COLUMN ");
1748
                builder.append(as_identifier(column.getName()));
1749
                builder.append(" ");
1750
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1751
                    builder.append(" SERIAL");
1752
                } else {
1753
                    builder.append(
1754
                            sqltype(
1755
                                    column.getType(),
1756
                                    column.getPrecision(),
1757
                                    column.getSize(),
1758
                                    column.getGeometryType(),
1759
                                    column.getGeometrySubtype()
1760
                            )
1761
                    );
1762
                }
1763
                if (column.getDefaultValue() == null) {
1764
                    if (column.allowNulls()) {
1765
                        builder.append(" DEFAULT NULL");
1766
                    }
1767
                } else {
1768
                    builder.append(" DEFAULT '");
1769
                    builder.append(column.getDefaultValue().toString());
1770
                    builder.append("'");
1771
                }
1772
                if (column.allowNulls()) {
1773
                    builder.append(" NULL");
1774
                } else {
1775
                    builder.append(" NOT NULL");
1776
                }
1777
                if (column.isPrimaryKey()) {
1778
                    builder.append(" PRIMARY KEY");
1779
                }
1780
                sqls.add(builder.toString());
1781
            }
1782
            for (ColumnDescriptor column : alters) {
1783
                StringBuilder builder = new StringBuilder();
1784
                builder.append("ALTER TABLE ");
1785
                builder.append(this.table.toString(formatter));
1786
                builder.append(" ALTER COLUMN ");
1787
                builder.append(as_identifier(column.getName()));
1788
                builder.append(" SET DATA TYPE ");
1789
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1790
                    builder.append(" SERIAL");
1791
                } else {
1792
                    builder.append(
1793
                            sqltype(
1794
                                    column.getType(),
1795
                                    column.getPrecision(),
1796
                                    column.getSize(),
1797
                                    column.getGeometryType(),
1798
                                    column.getGeometrySubtype()
1799
                            )
1800
                    );
1801
                }
1802
                if (column.getDefaultValue() == null) {
1803
                    if (column.allowNulls()) {
1804
                        builder.append(" DEFAULT NULL");
1805
                    } else {
1806
                        builder.append(" DROP DEFAULT");
1807
                    }
1808
                } else {
1809
                    builder.append(" DEFAULT '");
1810
                    builder.append(column.getDefaultValue().toString());
1811
                    builder.append("'");
1812
                }
1813
                sqls.add(builder.toString());
1814
            }
1815
            for (Pair<String, String> pair : renames) {
1816
                StringBuilder builder = new StringBuilder();
1817
                builder.append("ALTER TABLE ");
1818
                builder.append(this.table.toString(formatter));
1819
                builder.append(" RENAME COLUMN ");
1820
                builder.append(as_identifier(pair.getLeft()));
1821
                builder.append(" TO ");
1822
                builder.append(as_identifier(pair.getRight()));
1823
                sqls.add(builder.toString());
1824
            }
1825
            return sqls;
1826
        }
1827

    
1828
    }
1829

    
1830
    public class CreateTableBuilderBase
1831
            extends AbstractStatement
1832
            implements CreateTableBuilder {
1833

    
1834
        protected TableNameBuilder table;
1835
        protected List<ColumnDescriptor> columns;
1836

    
1837
        public CreateTableBuilderBase() {
1838
            this.columns = new ArrayList<>();
1839
        }
1840

    
1841
        @Override
1842
        public void accept(Visitor visitor, VisitorFilter filter) {
1843
            if (filter.accept(this)) {
1844
                visitor.visit(this);
1845
            }
1846
            if (this.table != null) {
1847
                this.table.accept(visitor, filter);
1848
            }
1849
        }
1850

    
1851
        @Override
1852
        public TableNameBuilder table() {
1853
            if (table == null) {
1854
                table = createTableNameBuilder();
1855
            }
1856
            return table;
1857
        }
1858

    
1859
        @Override
1860
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
1861
            this.columns.add(new ColumnDescriptorBase(fad));
1862
            return this;
1863
        }
1864

    
1865
        @Override
1866
        public CreateTableBuilderBase add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1867
            if (StringUtils.isEmpty(columnName)) {
1868
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1869
            }
1870
            if (isPk || isAutomatic) {
1871
                allowNulls = false;
1872
            }
1873
            this.columns.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1874
            return this;
1875
        }
1876

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

    
1886
        @Override
1887
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1888
            if (StringUtils.isEmpty(columnName)) {
1889
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1890
            }
1891
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1892
            return this;
1893
        }
1894

    
1895
        @Override
1896
        public ColumnDescriptor getColumnDescriptor(String columnName) {
1897
            if (StringUtils.isEmpty(columnName)) {
1898
                return null;
1899
            }
1900
            for (ColumnDescriptor column : columns) {
1901
                if (columnName.equals(column.getName())) {
1902
                    return column;
1903
                }
1904
            }
1905
            return null;
1906
        }
1907

    
1908
        @Override
1909
        public String toString() {
1910
            return this.toString(formatter());
1911
        }
1912

    
1913
        @Override
1914
        public String toString(Formatter<Value> formatter) {
1915
            if (formatter.canApply(this)) {
1916
                return formatter.format(this);
1917
            }
1918
            StringBuilder builder = new StringBuilder();
1919
            boolean first = true;
1920
            for (String sql : toStrings(formatter)) {
1921
                if (StringUtils.isEmpty(sql)) {
1922
                    continue;
1923
                }
1924
                if (first) {
1925
                    first = false;
1926
                } else {
1927
                    builder.append("; ");
1928
                }
1929
                builder.append(sql);
1930
            }
1931
            return builder.toString();
1932
        }
1933

    
1934
        @Override
1935
        public List<String> toStrings() {
1936
            return this.toStrings(formatter());
1937
        }
1938

    
1939
        @Override
1940
        public List<String> toStrings(Formatter formatter) {
1941
            List<String> sqls = new ArrayList<>();
1942
            /**
1943
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
1944
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
1945
             * column_constraint [ ... ] ] | table_constraint | LIKE
1946
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
1947
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
1948
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
1949
             *
1950
             * where column_constraint is:
1951
             *
1952
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
1953
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
1954
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
1955
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
1956
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1957
             *
1958
             * and table_constraint is:
1959
             *
1960
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
1961
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
1962
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
1963
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
1964
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
1965
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1966
             */
1967
            StringBuilder builder = new StringBuilder();
1968

    
1969
            builder.append("CREATE TABLE ");
1970
            builder.append(this.table.toString(formatter));
1971
            builder.append(" (");
1972
            boolean first = true;
1973
            for (ColumnDescriptor column : columns) {
1974
                if (first) {
1975
                    first = false;
1976
                } else {
1977
                    builder.append(", ");
1978
                }
1979
                builder.append(as_identifier(column.getName()));
1980
                builder.append(" ");
1981
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
1982
                    builder.append("SERIAL");
1983
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
1984
                    builder.append("BIGSERIAL");
1985
                } else {
1986
                    builder.append(sqltype(
1987
                            column.getType(),
1988
                            column.getPrecision(),
1989
                            column.getSize(),
1990
                            column.getGeometryType(),
1991
                            column.getGeometrySubtype()
1992
                    )
1993
                    );
1994
                }
1995
                if (column.getDefaultValue() == null) {
1996
                    if (column.allowNulls()) {
1997
                        builder.append(" DEFAULT NULL");
1998
                    }
1999
                } else {
2000
                    builder.append(" DEFAULT '");
2001
                    builder.append(column.getDefaultValue().toString());
2002
                    builder.append("'");
2003
                }
2004
                if (column.allowNulls()) {
2005
                    builder.append(" NULL");
2006
                } else {
2007
                    builder.append(" NOT NULL");
2008
                }
2009
                if (column.isPrimaryKey()) {
2010
                    builder.append(" PRIMARY KEY");
2011
                }
2012
            }
2013
            builder.append(" )");
2014
            sqls.add(builder.toString());
2015
            return sqls;
2016
        }
2017
    }
2018

    
2019
    public class InsertColumnBuilderBase
2020
            extends AbstractStatement
2021
            implements InsertColumnBuilder {
2022

    
2023
        protected Variable name;
2024
        protected Value value;
2025

    
2026
        public InsertColumnBuilderBase() {
2027
        }
2028

    
2029
        @Override
2030
        public void accept(Visitor visitor, VisitorFilter filter) {
2031
            if (filter.accept(this)) {
2032
                visitor.visit(this);
2033
            }
2034
            if (this.name != null) {
2035
                this.name.accept(visitor, filter);
2036
            }
2037
            if (this.value != null) {
2038
                this.value.accept(visitor, filter);
2039
            }
2040
        }
2041

    
2042
        @Override
2043
        public InsertColumnBuilder name(String name) {
2044
            this.name = expression().variable(name);
2045
            return this;
2046
        }
2047

    
2048
        @Override
2049
        public InsertColumnBuilder with_value(Value value) {
2050
            this.value = value;
2051
            return this;
2052
        }
2053

    
2054
        @Override
2055
        public String getName() {
2056
            return this.name.name();
2057
        }
2058

    
2059
        @Override
2060
        public Value getValue() {
2061
            return this.value;
2062
        }
2063

    
2064
        @Override
2065
        public String toString() {
2066
            return this.toString(formatter());
2067
        }
2068

    
2069
        @Override
2070
        public String toString(Formatter<Value> formatter) {
2071
            if (formatter.canApply(this)) {
2072
                return formatter.format(this);
2073
            }
2074
            return this.value.toString(formatter);
2075
        }
2076
    }
2077

    
2078
    public class InsertBuilderBase
2079
            extends AbstractStatement
2080
            implements InsertBuilder {
2081

    
2082
        protected List<InsertColumnBuilder> columns;
2083
        protected TableNameBuilder table;
2084

    
2085
        public InsertBuilderBase() {
2086
            this.columns = new ArrayList<>();
2087
        }
2088

    
2089
        @Override
2090
        public void accept(Visitor visitor, VisitorFilter filter) {
2091
            if (filter.accept(this)) {
2092
                visitor.visit(this);
2093
            }
2094
            if (this.table != null) {
2095
                this.table.accept(visitor, filter);
2096
            }
2097
            for (InsertColumnBuilder column : columns) {
2098
                column.accept(visitor, filter);
2099
            }
2100
        }
2101

    
2102
        @Override
2103
        public TableNameBuilder table() {
2104
            if (table == null) {
2105
                table = createTableNameBuilder();
2106
            }
2107
            return table;
2108
        }
2109

    
2110
        @Override
2111
        public InsertColumnBuilder column() {
2112
            InsertColumnBuilder column = createInsertColumnBuilder();
2113
            this.columns.add(column);
2114
            return column;
2115
        }
2116

    
2117
        @Override
2118
        public String toString() {
2119
            return this.toString(formatter());
2120
        }
2121

    
2122
        @Override
2123
        public String toString(Formatter<Value> formatter) {
2124
            if (formatter.canApply(this)) {
2125
                return formatter.format(this);
2126
            }
2127
            /*
2128
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2129
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2130
             * output_expression [ AS output_name ] [, ...] ]
2131
             */
2132
            StringBuilder builderColumns = new StringBuilder();
2133
            StringBuilder builderValues = new StringBuilder();
2134

    
2135
            boolean first = true;
2136
            for (InsertColumnBuilder column : columns) {
2137
                if (first) {
2138
                    first = false;
2139
                } else {
2140
                    builderColumns.append(", ");
2141
                }
2142
                builderColumns.append(as_identifier(column.getName()));
2143
            }
2144
            first = true;
2145
            for (InsertColumnBuilder column : columns) {
2146
                if (first) {
2147
                    first = false;
2148
                } else {
2149
                    builderValues.append(", ");
2150
                }
2151
                builderValues.append(column.toString(formatter));
2152
            }
2153

    
2154
            String sql = MessageFormat.format(
2155
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2156
                    this.table.toString(formatter),
2157
                    builderColumns.toString(),
2158
                    builderValues.toString()
2159
            );
2160
            return sql;
2161

    
2162
        }
2163
    }
2164

    
2165
    public class UpdateTableStatisticsBuilderBase
2166
            extends AbstractStatement
2167
            implements UpdateTableStatisticsBuilder {
2168

    
2169
        protected TableNameBuilder table;
2170

    
2171
        @Override
2172
        public void accept(Visitor visitor, VisitorFilter filter) {
2173
            if (filter.accept(this)) {
2174
                visitor.visit(this);
2175
            }
2176
            if (this.table != null) {
2177
                this.table.accept(visitor, filter);
2178
            }
2179
        }
2180

    
2181
        @Override
2182
        public TableNameBuilder table() {
2183
            if (table == null) {
2184
                table = createTableNameBuilder();
2185
            }
2186
            return table;
2187
        }
2188

    
2189
        @Override
2190
        public String toString() {
2191
            return this.toString(formatter());
2192
        }
2193

    
2194
        @Override
2195
        public String toString(Formatter<Value> formatter) {
2196
            if (formatter.canApply(this)) {
2197
                return formatter.format(this);
2198
            }
2199
            StringBuilder builder = new StringBuilder();
2200
            boolean first = true;
2201
            for (String sql : toStrings(formatter)) {
2202
                if (StringUtils.isEmpty(sql)) {
2203
                    continue;
2204
                }
2205
                if (first) {
2206
                    first = false;
2207
                } else {
2208
                    builder.append("; ");
2209
                }
2210
                builder.append(sql);
2211
            }
2212
            return builder.toString();
2213
        }
2214

    
2215
        @Override
2216
        public List<String> toStrings() {
2217
            return this.toStrings(formatter());
2218
        }
2219

    
2220
        @Override
2221
        public List<String> toStrings(Formatter formatter) {
2222
            List<String> sqls = new ArrayList<>();
2223

    
2224
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2225
                String sql = MessageFormat.format(
2226
                        STMT_UPDATE_TABLE_STATISTICS_table,
2227
                        table.toString(formatter)
2228
                );
2229
                if (!StringUtils.isEmpty(sql)) {
2230
                    sqls.add(sql);
2231
                }
2232
            }
2233
            return sqls;
2234
        }
2235
    }
2236

    
2237
    protected ExpressionBuilder expressionBuilder;
2238

    
2239
    protected String defaultSchema;
2240
    protected boolean supportSchemas;
2241
    protected boolean hasSpatialFunctions;
2242
    protected GeometrySupportType geometrySupportType;
2243
    protected boolean allowAutomaticValues;
2244

    
2245
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2246

    
2247
    protected String constant_true = "(1=1)";
2248
    protected String constant_false = "(1=1)";
2249

    
2250
    protected String type_boolean = "BOOLEAN";
2251
    protected String type_byte = "TINYINT";
2252
    protected String type_bytearray = "BYTEA";
2253
    protected String type_geometry = "TEXT";
2254
    protected String type_char = "CHARACTER(1)";
2255
    protected String type_date = "DATE";
2256
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2257
    protected String type_numeric_p = "NUMERIC({0})";
2258
    protected String type_numeric_ps = "NUMERIC({0},{1})";
2259
    protected String type_bigdecimal = "NUMERIC({0},{1})";
2260
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2261
    protected String type_int = "INT";
2262
    protected String type_long = "BIGINT";
2263
    protected String type_string = "TEXT";
2264
    protected String type_string_p = "VARCHAR({0})";
2265
    protected String type_time = "TIME";
2266
    protected String type_timestamp = "TIMESTAMP";
2267
    protected String type_version = "VARCHAR(30)";
2268
    protected String type_URI = "TEXT";
2269
    protected String type_URL = "TEXT";
2270
    protected String type_FILE = "TEXT";
2271
    protected String type_FOLDER = "TEXT";
2272

    
2273
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2274
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2275
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2276
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2277
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2278
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2279
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2280
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2281
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2282
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2283

    
2284
    public SQLBuilderBase() {
2285
        this.expressionBuilder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2286

    
2287
        this.hasSpatialFunctions = false;
2288
        this.supportSchemas = true;
2289
        this.geometrySupportType = GeometrySupportType.WKT;
2290

    
2291
        this.defaultSchema = "public";
2292
        this.allowAutomaticValues = true;
2293

    
2294
    }
2295
    
2296
    @Override
2297
    public void setProperties(Class filter, final Object... values) {
2298
        this.accept(new Visitor() {
2299
            @Override
2300
            public void visit(Visitable v) {
2301
                for (int i = 0; i < values.length; i+=2) {
2302
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2303
                }
2304
            }
2305
        }, new ClassVisitorFilter(filter) );
2306
    }
2307

    
2308
    public String quote_for_identifiers() {
2309
        return "\"";
2310
    }
2311

    
2312
    public String quote_for_strings() {
2313
        return "'";
2314
    }
2315

    
2316
    @Override
2317
    public String as_identifier(String id) {
2318
        String quote = this.quote_for_identifiers();
2319
//        No se porque no esta disponible wrapIfMissing
2320
//        return StringUtils.wrapIfMissing(id,quote);
2321
        if (id.startsWith(quote)) {
2322
            return id;
2323
        }
2324
        return quote + id + quote;
2325

    
2326
    }
2327

    
2328
    @Override
2329
    public String as_string(String s) {
2330
        String quote = this.quote_for_strings();
2331
//        No se porque no esta disponible wrapIfMissing
2332
//        return StringUtils.wrapIfMissing(id,quote);
2333
        if (s.startsWith(quote)) {
2334
            return s;
2335
        }
2336
        return quote + s + quote;
2337

    
2338
    }
2339

    
2340
    @Override
2341
    public String as_string(byte[] data) {
2342
        return this.expressionBuilder.bytearray_0x(data);
2343
//        return this.expressionBuilder.bytearray_hex(data);
2344
//        return this.expressionBuilder.bytearray_x(data);
2345
    }
2346
    
2347
    @Override
2348
    public String as_string(boolean value) {
2349
        return value? "TRUE" : "FALSE";
2350
    }
2351

    
2352
    @Override
2353
    public String as_string(Number value) {
2354
        return Objects.toString(value);
2355
    }
2356
    
2357
    @Override
2358
    public String as_string(Object value) {
2359
        if( value == null ) {
2360
            return "NULL";
2361
        }
2362
        if( value instanceof CharSequence ) {
2363
            return as_string(value.toString());
2364
        }
2365
        if( value instanceof Number ) {
2366
            return as_string((Number)value);
2367
        }
2368
        if( value instanceof Boolean ) {
2369
            return as_string((boolean)value);
2370
        }
2371
        if( value instanceof byte[] ) {
2372
            return as_string((byte[])value);
2373
        }
2374
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2375
    }
2376
    
2377
    @Override
2378
    public ExpressionBuilder expression() {
2379
        return this.expressionBuilder;
2380
    }
2381

    
2382
    @Override
2383
    public boolean has_spatial_functions() {
2384
        return this.hasSpatialFunctions;
2385
    }
2386

    
2387
    @Override
2388
    public GeometrySupportType geometry_support_type() {
2389
        return this.geometrySupportType;
2390
    }
2391

    
2392
    protected ExpressionBuilder createExpressionBuilder() {
2393
        return ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2394
    }
2395

    
2396
    @Override
2397
    public Object srs_id(IProjection projection) {
2398
        String abrev = projection.getAbrev();
2399
        return abrev.split(":")[1].trim();
2400
    }
2401

    
2402
    @Override
2403
    public String default_schema() {
2404
        return this.defaultSchema;
2405
    }
2406

    
2407
    @Override
2408
    public boolean support_schemas() {
2409
        return this.supportSchemas;
2410
    }
2411

    
2412
    @Override
2413
    public String sqltype(int type, int p, int s, int geomType, int geomSubtype) {
2414
        switch (type) {
2415
            case DataTypes.BOOLEAN:
2416
                return type_boolean;
2417
            case DataTypes.BYTE:
2418
                return type_byte;
2419
            case DataTypes.BYTEARRAY:
2420
                return type_bytearray;
2421
            case DataTypes.GEOMETRY:
2422
                return type_geometry;
2423
            case DataTypes.CHAR:
2424
                return type_char;
2425
            case DataTypes.DATE:
2426
                return type_date;
2427
            case DataTypes.DOUBLE:
2428
                // FIXME: Si cargamos la capa "country" al exportarla a
2429
                // SQLServer falla por:
2430
                //  Error de desbordamiento aritm?tico al convertir float al tipo de datos numeric.
2431
                // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
2432
                // Algeria intenta asignarle un valor de 2320972.0 y falla.
2433
                // Habria que repasar el proveedor de shape.
2434

    
2435
//                if (p > 1) {
2436
//                    if (s < 0) {
2437
//                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
2438
//                    }
2439
//                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
2440
//                }
2441
                return MessageFormat.format(type_double, p, s);
2442
            case DataTypes.BIGDECIMAL:
2443
                if (p < 1) {
2444
                    p = 20;
2445
                }
2446
                if (s < 0) {
2447
                    s = 10;
2448
                }
2449
                return MessageFormat.format(type_bigdecimal, p, s);
2450
            case DataTypes.FLOAT:
2451
                return MessageFormat.format(type_float, p, s);
2452
            case DataTypes.INT:
2453
                return MessageFormat.format(type_int, p, s);
2454
            case DataTypes.LONG:
2455
                return MessageFormat.format(type_long, p, s);
2456
            case DataTypes.STRING:
2457
                if (p < 0) {
2458
                    return type_string;
2459
                } else if (p < 4096) {
2460
                    return MessageFormat.format(type_string_p, p);
2461
                }
2462
                return type_string;
2463
            case DataTypes.TIME:
2464
                return type_time;
2465
            case DataTypes.TIMESTAMP:
2466
                return type_timestamp;
2467
            case DataTypes.VERSION:
2468
                return type_version;
2469
            case DataTypes.URI:
2470
                return type_URI;
2471
            case DataTypes.URL:
2472
                return type_URL;
2473
            case DataTypes.FILE:
2474
                return type_FILE;
2475
            case DataTypes.FOLDER:
2476
                return type_FOLDER;
2477
            default:
2478
                return null;
2479
        }
2480
    }
2481

    
2482
    @Override
2483
    public Object sqlgeometrytype(int type, int subtype) {
2484
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2485
        // identificadores numericos para el tipo y otros strings.
2486
        // Por defecto vamos a devolver strings.
2487
        if (sqlgeometrytypes == null) {
2488
            sqlgeometrytypes = new HashMap<>();
2489
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2490
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2491
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2492
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2493

    
2494
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2495
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2496
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2497
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2498

    
2499
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2500
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2501
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2502
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2503

    
2504
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2505
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2506
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2507
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2508

    
2509
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2510
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2511
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2512
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2513

    
2514
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2515
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2516
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2517
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2518

    
2519
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2520
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2521
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2522
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2523

    
2524
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2525
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2526
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2527
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2528

    
2529
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2530
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2531
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2532
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2533
        }
2534
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2535
    }
2536

    
2537
    @Override
2538
    public Object sqlgeometrydimension(int type, int subtype) {
2539
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2540
        // identificadores numericos para las dimensiones y otros strings.
2541
        // Por defecto vamos a devolver enteros.
2542
        switch (subtype) {
2543
            case Geometry.SUBTYPES.GEOM3D:
2544
                return 3;
2545
            case Geometry.SUBTYPES.GEOM2DM:
2546
                return 3;
2547
            case Geometry.SUBTYPES.GEOM3DM:
2548
                return 4;
2549
            case Geometry.SUBTYPES.GEOM2D:
2550
            default:
2551
                return 2;
2552
        }
2553
    }
2554

    
2555
    protected TableNameBuilder createTableNameBuilder() {
2556
        return new TableNameBuilderBase();
2557
    }
2558

    
2559
    protected SelectColumnBuilder createSelectColumnBuilder() {
2560
        return new SelectColumnBuilderBase();
2561
    }
2562

    
2563
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2564
        return new UpdateColumnBuilderBase();
2565
    }
2566

    
2567
    protected InsertColumnBuilder createInsertColumnBuilder() {
2568
        return new InsertColumnBuilderBase();
2569
    }
2570

    
2571
    protected OrderByBuilder createOrderByBuilder() {
2572
        return new OrderByBuilderBase();
2573
    }
2574

    
2575
    protected FromBuilder createFromBuilder() {
2576
        return new FromBuilderBase();
2577
    }
2578

    
2579
    protected SelectBuilder createSelectBuilder() {
2580
        return new SelectBuilderBase();
2581
    }
2582

    
2583
    protected UpdateBuilder createUpdateBuilder() {
2584
        return new UpdateBuilderBase();
2585
    }
2586

    
2587
    protected DeleteBuilder createDeleteBuilder() {
2588
        return new DeleteBuilderBase();
2589
    }
2590

    
2591
    protected GrantBuilder createGrantBuilder() {
2592
        return new GrantBuilderBase();
2593
    }
2594

    
2595
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2596
        return new GrantRoleBuilderBase(table, role);
2597
    }
2598

    
2599
    protected DropTableBuilder createDropTableBuilder() {
2600
        return new DropTableBuilderBase();
2601
    }
2602

    
2603
    protected CreateTableBuilder createCreateTableBuilder() {
2604
        return new CreateTableBuilderBase();
2605
    }
2606

    
2607
    protected AlterTableBuilder createAlterTableBuilder() {
2608
        return new AlterTableBuilderBase();
2609
    }
2610

    
2611
    protected InsertBuilder createInsertBuilder() {
2612
        return new InsertBuilderBase();
2613
    }
2614

    
2615
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2616
        return new UpdateTableStatisticsBuilderBase();
2617
    }
2618

    
2619
    protected CreateIndexBuilder createCreateIndexBuilder() {
2620
        return new CreateIndexBuilderBase();
2621
    }
2622

    
2623
    @Override
2624
    public SelectBuilder select() {
2625
        if (this.select == null) {
2626
            this.select = this.createSelectBuilder();
2627
        }
2628
        return this.select;
2629
    }
2630

    
2631
    @Override
2632
    public UpdateBuilder update() {
2633
        if (this.update == null) {
2634
            this.update = this.createUpdateBuilder();
2635
        }
2636
        return this.update;
2637
    }
2638

    
2639
    @Override
2640
    public UpdateTableStatisticsBuilder update_table_statistics() {
2641
        if (this.update_table_statistics == null) {
2642
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2643
        }
2644
        return this.update_table_statistics;
2645
    }
2646

    
2647
    @Override
2648
    public DropTableBuilder drop_table() {
2649
        if (this.drop_table == null) {
2650
            this.drop_table = this.createDropTableBuilder();
2651
        }
2652
        return this.drop_table;
2653
    }
2654

    
2655
    @Override
2656
    public CreateIndexBuilder create_index() {
2657
        if (this.create_index == null) {
2658
            this.create_index = this.createCreateIndexBuilder();
2659
        }
2660
        return this.create_index;
2661
    }
2662

    
2663
    @Override
2664
    public DeleteBuilder delete() {
2665
        if (this.delete == null) {
2666
            this.delete = this.createDeleteBuilder();
2667
        }
2668
        return this.delete;
2669
    }
2670

    
2671
    @Override
2672
    public InsertBuilder insert() {
2673
        if (this.insert == null) {
2674
            this.insert = this.createInsertBuilder();
2675
        }
2676
        return this.insert;
2677
    }
2678

    
2679
    @Override
2680
    public AlterTableBuilder alter_table() {
2681
        if (this.alter_table == null) {
2682
            this.alter_table = this.createAlterTableBuilder();
2683
        }
2684
        return this.alter_table;
2685
    }
2686

    
2687
    @Override
2688
    public CreateTableBuilder create_table() {
2689
        if (this.create_table == null) {
2690
            this.create_table = this.createCreateTableBuilder();
2691
        }
2692
        return this.create_table;
2693
    }
2694

    
2695
    @Override
2696
    public GrantBuilder grant() {
2697
        if (this.grant == null) {
2698
            this.grant = this.createGrantBuilder();
2699
        }
2700
        return this.grant;
2701
    }
2702

    
2703
    public void accept(Visitor visitor, VisitorFilter filter) {
2704
        if (this.select != null) {
2705
            this.select.accept(visitor, filter);
2706
        }
2707
        if (this.update != null) {
2708
            this.update.accept(visitor, filter);
2709
        }
2710
        if (this.insert != null) {
2711
            this.insert.accept(visitor, filter);
2712
        }
2713
        if (this.delete != null) {
2714
            this.delete.accept(visitor, filter);
2715
        }
2716
        if (this.alter_table != null) {
2717
            this.alter_table.accept(visitor, filter);
2718
        }
2719
        if (this.create_table != null) {
2720
            this.create_table.accept(visitor, filter);
2721
        }
2722
        if (this.drop_table != null) {
2723
            this.drop_table.accept(visitor, filter);
2724
        }
2725
    }
2726

    
2727
    protected Formatter formatter() {
2728
        return ExpressionBuilder.EMPTY_FORMATTER;
2729
    }
2730

    
2731
    @Override
2732
    public String toString() {
2733
        return this.toString(formatter());
2734
    }
2735

    
2736
    @Override
2737
    public String toString(Formatter formatter) {
2738
        if (this.select != null) {
2739
            return this.select.toString(formatter);
2740
        }
2741
        if (this.update != null) {
2742
            return this.update.toString(formatter);
2743
        }
2744
        if (this.insert != null) {
2745
            return this.insert.toString(formatter);
2746
        }
2747
        if (this.delete != null) {
2748
            return this.delete.toString(formatter);
2749
        }
2750
        if (this.alter_table != null) {
2751
            return this.alter_table.toString(formatter);
2752
        }
2753
        if (this.create_table != null) {
2754
            return this.create_table.toString(formatter);
2755
        }
2756
        if (this.drop_table != null) {
2757
            return this.drop_table.toString(formatter);
2758
        }
2759
        if (this.update_table_statistics != null) {
2760
            return this.update_table_statistics.toString(formatter);
2761
        }
2762
        return "";
2763
    }
2764

    
2765
    @Override
2766
    public CountBuilder count() {
2767
        return new CountBuilderBase();
2768
    }
2769

    
2770
    @Override
2771
    public List<Parameter> parameters() {
2772
        final List<Parameter> params = new ArrayList<>();
2773
        this.accept(new Visitor() {
2774
            @Override
2775
            public void visit(Visitable value) {
2776
                params.add((Parameter) value);
2777
            }
2778
        }, new ClassVisitorFilter(Parameter.class));
2779
        return params;
2780
    }
2781

    
2782
    @Override
2783
    public List<Variable> variables() {
2784
        final List<Variable> vars = new ArrayList<>();
2785
        this.accept(new Visitor() {
2786
            @Override
2787
            public void visit(Visitable value) {
2788
                if (!vars.contains((Variable) value)) {
2789
                    vars.add((Variable) value);
2790
                }
2791
            }
2792
        }, new ClassVisitorFilter(Variable.class));
2793
        return vars;
2794
    }
2795

    
2796
    @Override
2797
    public List<String> parameters_names() {
2798
        List<String> params = new ArrayList<>();
2799
        for (Parameter param : parameters()) {
2800
            String s;
2801
            switch (param.type()) {
2802
                case Constant:
2803
                    Object theValue = param.value();
2804
                    if (theValue == null) {
2805
                        s = "null";
2806
                    } else if (theValue instanceof String) {
2807
                        s = "'" + (String) theValue + "'";
2808
                    } else {
2809
                        s = theValue.toString();
2810
                    }
2811
                    break;
2812
                case Geometry:
2813
                case Variable:
2814
                default:
2815
                    s = "\"" + param.name() + "\"";
2816
            }
2817
            params.add(s);
2818
        }
2819
        return params;
2820
    }
2821

    
2822
    @Override
2823
    public List<String> variables_names() {
2824
        List<String> vars = new ArrayList<>();
2825
        for (Variable var : this.variables()) {
2826
            vars.add(var.name());
2827
        }
2828
        Collections.sort(vars);
2829
        return vars;
2830
    }
2831
}