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

History | View | Annotate | Download (109 KB)

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

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

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

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

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

    
75
    protected abstract class AbstractStatementPart extends AbstractValue {
76

    
77
    }
78

    
79
    protected abstract class AbstractStatement extends AbstractStatementPart {
80

    
81
    }
82

    
83
    protected class ColumnDescriptorBase implements ColumnDescriptor {
84

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

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

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

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

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

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

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

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

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

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

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

    
202
        @Override
203
        public int getPrecision() {
204
            return precision;
205
        }
206

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

    
212
        @Override
213
        public int getScale() {
214
            return scale;
215
        }
216

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

    
222
        @Override
223
        public int getSize() {
224
            return size;
225
        }
226

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

    
232
        @Override
233
        public boolean isPrimaryKey() {
234
            return isPk;
235
        }
236

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

    
242
        @Override
243
        public boolean allowNulls() {
244
            return _allowNulls;
245
        }
246

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

    
252
        @Override
253
        public boolean isAutomatic() {
254
            return _isAutomatic;
255
        }
256

    
257
        @Override
258
        public boolean isIndexed() {
259
            return _isIndexed;
260
        }
261

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

    
267
        @Override
268
        public Object getDefaultValue() {
269
            return defaultValue;
270
        }
271

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

    
277
        @Override
278
        public int getGeometryType() {
279
            return geom_type;
280
        }
281

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

    
287
        @Override
288
        public int getGeometrySubtype() {
289
            return geom_subtype;
290
        }
291

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

    
297
        @Override
298
        public Object getGeometrySRSId() {
299
            return geom_srsdbcode;
300
        }
301

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

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

    
312
        private void setStoreParameters(DataStoreParameters parameters) {
313
            this.parameters = parameters;
314
        }
315

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

    
322
    public class ColumnBase extends AbstractValue implements Column {
323

    
324
        private final String name;
325
        private TableNameBuilder table;
326

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

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

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

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

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

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

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

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

    
385
    public class TableNameBuilderBase
386
            extends AbstractStatementPart
387
            implements TableNameBuilder {
388

    
389
        public String tableName;
390
        public String schemaName;
391
        private String databaseName;
392

    
393
        public TableNameBuilderBase() {
394
        }
395

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

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

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

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

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

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

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

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

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

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

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

    
476
        @Override
477
        public boolean equals(Object obj) {
478
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
479
                return false;
480
            }
481
            TableNameBuilder other = (TableNameBuilder) obj;
482
            
483
            if (this.has_database() != other.has_database()) {
484
                return false;
485
            }
486
            String thisSchema = null;
487
            String otherSchema = null;
488
            if(support_schemas()) {
489
                thisSchema = this.schemaName;
490
                if (StringUtils.isBlank(thisSchema)) {
491
                    thisSchema = default_schema();
492
                }
493
                otherSchema = other.getSchema();
494
                if (StringUtils.isBlank(otherSchema)) {
495
                    otherSchema = default_schema();
496
                }
497
            }
498
            if (this.has_database()) {
499
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
500
                           StringUtils.equals(thisSchema, otherSchema) &&
501
                           StringUtils.equals(this.tableName,other.getName());
502
            } else {
503
                    return StringUtils.equals(thisSchema, otherSchema) &&
504
                           StringUtils.equals(this.tableName,other.getName());
505
            }
506
        }
507

    
508
        @Override
509
        public int hashCode() {
510
            int hash = 7;
511
            hash = 37 * hash + Objects.hashCode(this.toString());
512
            return hash;
513
        }
514

    
515
    }
516

    
517
    public class CountBuilderBase
518
            extends AbstractStatementPart
519
            implements CountBuilder {
520

    
521
        protected Value value;
522
        protected boolean distinct;
523
        protected boolean all;
524

    
525
        public CountBuilderBase() {
526
            this.value = null;
527
            this.distinct = false;
528
            this.all = false;
529
        }
530

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

    
537
        @Override
538
        public CountBuilder column(Value value) {
539
            this.value = value;
540
            return this;
541
        }
542

    
543
        @Override
544
        public CountBuilder distinct() {
545
            this.distinct = true;
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 formatter) {
556
            if (formatter!=null && formatter.canApply(this)) {
557
                return formatter.format(this);
558
            }
559
            if (this.all) {
560
                return "COUNT(*)";
561
            }
562
            if (this.distinct) {
563
                return MessageFormat.format(
564
                        "COUNT(DISTINCT {0})",
565
                        value.toString(formatter)
566
                );
567
            }
568
            return MessageFormat.format(
569
                    "COUNT({0})",
570
                    value.toString(formatter)
571
            );
572
        }
573

    
574
    }
575

    
576
    protected class JoinBase 
577
            extends AbstractStatementPart
578
            implements StatementPart 
579
        {
580
        protected String type;
581
        protected TableNameBuilder table;
582
        protected Value expression;
583
        
584
        public JoinBase(String type, TableNameBuilder table, Value expression) {
585
            this.type = type;
586
            this.table = table;
587
            this.expression = expression;
588
        }
589

    
590
        @Override
591
        public String toString() {
592
            return this.toString(formatter());
593
        }
594

    
595
        @Override
596
        public String toString(Formatter<Value> formatter) {
597
            if (formatter!=null && formatter.canApply(this)) {
598
                return formatter.format(this);
599
            }
600
            StringBuilder builder = new StringBuilder();
601
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
602
            builder.append(this.type.toUpperCase());
603
            builder.append(" JOIN ");
604
            builder.append(this.table.toString(formatter));
605
            builder.append(" ON ");
606
            builder.append(this.expression.toString(formatter));
607
            return builder.toString();
608
        }
609
        
610
        
611
    }
612
    
613
    public class FromBuilderBase
614
            extends AbstractStatementPart
615
            implements FromBuilder {
616

    
617
        protected TableNameBuilder tableName;
618
        protected String subquery;
619
        protected String passthrough;
620
        protected List<JoinBase> joins;
621

    
622
        public FromBuilderBase() {
623
            this.tableName = null;
624
            this.subquery = null;
625
            this.passthrough = null;
626
            this.joins = null;
627
        }
628

    
629
        @Override
630
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
631
            JoinBase join = createJoin("LEFT", table, expression);
632
            if( this.joins==null ) {
633
                this.joins = new ArrayList<>();
634
            }
635
            this.joins.add(join);
636
            return this;
637
        }
638
        
639
        @Override
640
        public TableNameBuilder table() {
641
            if (tableName == null) {
642
                this.tableName = createTableNameBuilder();
643
            }
644
            return this.tableName;
645
        }
646

    
647
        @Override
648
        public void accept(Visitor visitor, VisitorFilter filter) {
649
            if (filter==null || filter.accept(this)) {
650
                visitor.visit(this);
651
            }
652
            if (this.tableName != null) {
653
                this.tableName.accept(visitor, filter);
654
            }
655
        }
656

    
657
        @Override
658
        public FromBuilder custom(String passthrough) {
659
            this.passthrough = passthrough;
660
            return this;
661
        }
662

    
663
        @Override
664
        public FromBuilder subquery(String subquery) {
665
            this.subquery = subquery;
666
            return this;
667
        }
668

    
669
        @Override
670
        public String toString() {
671
            return this.toString(formatter());
672
        }
673

    
674
        @Override
675
        public String toString(Formatter<Value> formatter) {
676
            if (formatter!=null && formatter.canApply(this)) {
677
                return formatter.format(this);
678
            }
679
            if (!StringUtils.isEmpty(passthrough)) {
680
                return passthrough;
681
            }
682
            if (!StringUtils.isEmpty(subquery)) {
683
                return "( " + this.subquery + ") as _subquery_alias_ ";
684
            }
685
            if( this.joins==null || this.joins.isEmpty() ) {
686
                return this.tableName.toString(formatter);
687
            }
688
            StringBuilder builder = new StringBuilder();
689
            builder.append(this.tableName.toString(formatter));
690
            for (JoinBase join : this.joins) {
691
                builder.append(" ");
692
                builder.append(join.toString(formatter));
693
            }
694
            return builder.toString();
695
        }
696

    
697
    }
698

    
699
    public class SelectColumnBuilderBase
700
            extends AbstractStatementPart
701
            implements SelectColumnBuilder {
702

    
703
        protected Variable name = null;
704
        protected String alias = null;
705
        protected Value value = null;
706
        protected boolean asGeometry = false;
707
        protected TableNameBuilder table;
708

    
709
        @Override
710
        public void accept(Visitor visitor, VisitorFilter filter) {
711
            if (filter==null || filter.accept(this)) {
712
                visitor.visit(this);
713
            }
714
            if (this.name != null) {
715
                this.name.accept(visitor, filter);
716
            }
717
            if (this.value != null) {
718
                this.value.accept(visitor, filter);
719
            }
720
        }
721

    
722
        @Override
723
        public void replace(Value target, Value replacement) {
724
            if (this.name!=null ) {
725
                if( this.name == target) {
726
                    this.name = (Variable) replacement;
727
                }
728
            }
729
            if( this.value!=null ) {
730
                if (this.value == target) {
731
                    this.value = replacement;
732
                } else {
733
                    this.value.replace(target, replacement);
734
                }
735
            }
736
        }
737

    
738
        @Override
739
        public SelectColumnBuilder name(String name) {
740
            return this.name(null, name);
741
        }
742

    
743
        @Override
744
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
745
            String quote = quote_for_identifiers();
746
            if (name.startsWith(quote)) {
747
                // Remove quotes
748
                name = name.substring(1, name.length() - 1);
749
            }
750
            this.name = expression().variable(name);
751
            this.table = table;
752
            this.value = null;
753
            this.asGeometry = false;
754
            return this;
755
        }
756

    
757
        @Override
758
        public SelectColumnBuilder all() {
759
            this.name = null;
760
            this.value = expression().custom("*");
761
            this.asGeometry = false;
762
            return this;
763
        }
764

    
765
        @Override
766
        public SelectColumnBuilder as_geometry() {
767
            this.asGeometry = true;
768
            return this;
769
        }
770

    
771
        @Override
772
        public SelectColumnBuilder value(Value value) {
773
            this.value = value;
774
            this.name = null;
775
            return this;
776
        }
777

    
778
        @Override
779
        public SelectColumnBuilder as(String alias) {
780
            this.alias = alias;
781
            return this;
782
        }
783

    
784
        @Override
785
        public String getName() {
786
            if (this.name==null) {
787
                return null;
788
            }
789
            return this.name.name();
790
        }
791

    
792
        @Override
793
        public String getAlias() {
794
            return this.alias;
795
        }
796

    
797
        @Override
798
        public String getValue() {
799
            return this.alias;
800
        }
801

    
802
        @Override
803
        public String toString() {
804
            return this.toString(formatter());
805
        }
806

    
807
        @Override
808
        public String toString(Formatter<Value> formatter) {
809
            if (formatter!=null && formatter.canApply(this)) {
810
                return formatter.format(this);
811
            }
812
            StringBuilder builder = new StringBuilder();
813
            if (this.asGeometry) {
814
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
815
            } else {
816
                if (this.name != null) {
817
                    if( this.table==null ) {
818
                        builder.append(this.name.toString(formatter));
819
                    } else {
820
                        builder.append(this.table.toString(formatter));
821
                        builder.append(".");
822
                        builder.append(this.name.toString(formatter));
823
                    }
824
                } else {
825
                    builder.append(this.value.toString(formatter));
826
                }
827
            }
828
            if (this.alias != null) {
829
                builder.append(" AS ");
830
                builder.append(as_identifier(this.alias));
831
            }
832
            return builder.toString();
833
        }
834
        public boolean isGeometry() {
835
            return this.asGeometry;
836
        }
837
        
838
        public TableNameBuilder getTable() {
839
            return this.table;
840
        }
841
    }
842

    
843
    public class OrderByBuilderBase
844
            extends AbstractStatementPart
845
            implements OrderByBuilder {
846

    
847
        protected Value value;
848
        protected String custom;
849
        protected boolean ascending;
850

    
851
        public OrderByBuilderBase() {
852
            this.ascending = true;
853
        }
854

    
855
        @Override
856
        public void accept(Visitor visitor, VisitorFilter filter) {
857
            if (filter==null || filter.accept(this)) {
858
                visitor.visit(this);
859
            }
860
            if (this.value!=null) {
861
                this.value.accept(visitor, filter);
862
            }
863
        }
864

    
865
        @Override
866
        public OrderByBuilder column(String name) {
867
            this.value = expression().variable(name);
868
            return this;
869
        }
870
        
871
        @Override
872
        public boolean isColumn(String name) {
873
            if(this.value instanceof ExpressionBuilder.Variable){
874
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
875
            }
876
            return false;
877
        }
878
        
879
        @Override
880
        public OrderByBuilder value(Value expression) {
881
            this.value = expression;
882
            return this;
883
        }
884
        
885
        @Override
886
        public OrderByBuilder custom(String order) {
887
            this.custom = order;
888
            return this;
889
        }
890

    
891
        @Override
892
        public OrderByBuilder ascending() {
893
            this.ascending = true;
894
            return this;
895
        }
896

    
897
        @Override
898
        public OrderByBuilder ascending(boolean asc) {
899
            this.ascending = asc;
900
            return this;
901
        }
902

    
903
        @Override
904
        public OrderByBuilder descending() {
905
            this.ascending = false;
906
            return this;
907
        }
908

    
909
        @Override
910
        public String toString() {
911
            return this.toString(formatter());
912
        }
913

    
914
        @Override
915
        public String toString(Formatter<Value> formatter) {
916
            if (formatter!=null && formatter.canApply(this)) {
917
                return formatter.format(this);
918
            }
919
            if (!StringUtils.isEmpty(this.custom)) {
920
                return this.custom;
921
            }
922
            if (this.ascending) {
923
                return this.value.toString(formatter) + " ASC";
924
            }
925
            return this.value.toString(formatter) + " DESC";
926
        }
927
    }
928

    
929
    public class SelectBuilderBase
930
            extends AbstractStatement
931
            implements SelectBuilder {
932

    
933
        protected FromBuilder from;
934
        protected GeometryExpressionBuilder where;
935
        protected long limit = -1;
936
        protected long offset = -1;
937
        protected List<SelectColumnBuilder> columns;
938
        protected List<OrderByBuilder> order_by;
939
        protected boolean distinct;
940
        protected List<Value> groupColumn;
941
        protected boolean check_order_and_offset = true;
942

    
943
        public SelectBuilderBase() {
944
            this.columns = new ArrayList<>();
945
            this.distinct = false;
946
        }
947
        @Override
948
        public List<Value> getGroups() {
949
            return this.groupColumn;
950
        }
951
        
952
        public List<SelectColumnBuilder> getColumns() {
953
            return Collections.unmodifiableList(this.columns);
954
    }
955
        
956
        public void remove_column(String columnName) {
957
            SelectColumnBuilder found = null;
958
            for (SelectColumnBuilder column : columns) {
959
                if(column.getAlias().equalsIgnoreCase(columnName)) {
960
                    found = column;
961
                    break;
962
                }
963
                    
964
            }
965
            if(found!=null) {
966
                columns.remove(found);
967
            }
968
        }
969

    
970
        @Override
971
        public SelectBuilder group_by(Value... columns) {
972
            if( this.groupColumn==null ) {
973
                this.groupColumn = new ArrayList<>();
974
            }
975
            for (Value column : columns) {
976
                this.groupColumn.add(column);
977
            }
978
            return this;
979
        }
980

    
981
        @Override
982
        public void accept(Visitor visitor, VisitorFilter filter) {
983
            if (filter==null || filter.accept(this)) {
984
                visitor.visit(this);
985
            }
986
            for (SelectColumnBuilder column : columns) {
987
                column.accept(visitor, filter);
988
            }
989
            if (this.has_from()) {
990
                this.from.accept(visitor, filter);
991
            }
992
            if (this.has_where()) {
993
                this.where.accept(visitor, filter);
994
            }
995
            if (this.has_order_by()) {
996
                for (OrderByBuilder order : order_by) {
997
                    order.accept(visitor, filter);
998
                }
999
            }
1000
            if (this.has_group_by()) {
1001
                for (Value group : groupColumn) {
1002
                    group.accept(visitor, filter);
1003
                }
1004
            }
1005
        }
1006

    
1007
        @Override
1008
        public void replace(Value target, Value replacement) {
1009
            if( this.columns!=null ) {
1010
                for (int i = 0; i < columns.size(); i++) {
1011
                    SelectColumnBuilder column = columns.get(i);
1012
                    if( column == target ) {
1013
                        columns.set(i, (SelectColumnBuilder) replacement);
1014
                    } else {
1015
                        column.replace(target, replacement);
1016
                    }
1017
                }
1018
            }
1019
            if (this.has_from()) {
1020
                if( this.from == target ) {
1021
                    this.from = (FromBuilder) replacement;
1022
                } else {
1023
                    this.from.replace(target, replacement);
1024
                }
1025
            }
1026
            if (this.has_where()) {
1027
                if( this.where == target ) {
1028
                    this.where = (GeometryExpressionBuilder) replacement;
1029
                } else if( this.where.value() == target ) {
1030
                    this.where.value(replacement);
1031
                } else {
1032
                    this.where.value().replace(target, replacement);
1033
                }
1034
            }
1035
            if (this.has_order_by()) {
1036
                for (int i = 0; i < order_by.size(); i++) {
1037
                    OrderByBuilder order = order_by.get(i);
1038
                    if( order == target ) {
1039
                        order_by.set(i, (OrderByBuilder) replacement);
1040
                    } else {
1041
                        order.replace(target, replacement);
1042
                    }
1043
                }
1044
            }
1045
            if (this.has_group_by()) {
1046
                for (int i = 0; i < groupColumn.size(); i++) {
1047
                    Value group = groupColumn.get(i);
1048
                    if( group == target ) {
1049
                        groupColumn.set(i, replacement);
1050
                    } else {
1051
                        group.replace(target, replacement);
1052
                    }
1053
                }
1054
            }
1055
        }
1056

    
1057
        @Override
1058
        public SelectBuilder distinct() {
1059
            this.distinct = true;
1060
            return this;
1061
        }
1062

    
1063
        @Override
1064
        public SelectColumnBuilder column() {
1065
            SelectColumnBuilder builder = createSelectColumnBuilder();
1066
            this.columns.add(builder);
1067
            return builder;
1068
        }
1069

    
1070
        @Override
1071
        public SelectBuilder remove_all_columns() {
1072
            this.columns = new ArrayList<>();
1073
            return this;
1074
        }
1075
        
1076
        @Override
1077
        public boolean has_column(String name) {
1078
            for (SelectColumnBuilder column : columns) {
1079
                if (StringUtils.equals(name, column.getName())) {
1080
                    return true;
1081
                }
1082
                if (StringUtils.equals(name, column.getAlias())) {
1083
                    return true;
1084
                }
1085
            }
1086
            return false;
1087
        }
1088

    
1089
        @Override
1090
        public FromBuilder from() {
1091
            if (this.from == null) {
1092
                this.from = createFromBuilder();
1093
            }
1094
            return this.from;
1095
        }
1096

    
1097
        @Override
1098
        public boolean has_from() {
1099
            return this.from != null;
1100
        }
1101

    
1102
        @Override
1103
        public GeometryExpressionBuilder where() {
1104
            if (this.where == null) {
1105
                this.where = createExpressionBuilder();
1106
            }
1107
            return this.where;
1108
        }
1109

    
1110
        @Override
1111
        public boolean has_where() {
1112
            if (this.where == null) {
1113
                return false;
1114
            }
1115
            return this.where.value() != null;
1116
        }
1117

    
1118
        @Override
1119
        public SelectBuilder limit(long limit) {
1120
            this.limit = limit;
1121
            return this;
1122
        }
1123

    
1124
        @Override
1125
        public SelectBuilder limit(Long limit) {
1126
            if (limit == null) {
1127
                this.limit = 0;
1128
            } else {
1129
                this.limit = limit;
1130
            }
1131
            return this;
1132
        }
1133

    
1134
        @Override
1135
        public boolean has_limit() {
1136
            return this.limit > 0;
1137
        }
1138

    
1139
        @Override
1140
        public SelectBuilder offset(long offset) {
1141
            this.offset = offset;
1142
            return this;
1143
        }
1144

    
1145
        @Override
1146
        public boolean has_offset() {
1147
            return this.offset > 0;
1148
        }
1149

    
1150
        @Override
1151
        public OrderByBuilder order_by() {
1152
            if (this.order_by == null) {
1153
                this.order_by = new ArrayList<>();
1154
            }
1155
            OrderByBuilder order = createOrderByBuilder();
1156
            this.order_by.add(order);
1157
            return order;
1158
        }
1159
        
1160
        public OrderByBuilder getOrderBy(String column) {
1161
            if(this.order_by == null){
1162
                return null;
1163
            }
1164
            for (OrderByBuilder orderByBuilder : this.order_by) {
1165
                if(orderByBuilder.isColumn(column)){
1166
                    return orderByBuilder;
1167
                }
1168
            }
1169
            return null;
1170
        }
1171

    
1172
        @Override
1173
        public boolean has_order_by() {
1174
            if (this.order_by == null) {
1175
                return false;
1176
            }
1177
            return !this.order_by.isEmpty();
1178
        }
1179
        
1180
        @Override
1181
        public boolean has_group_by() {
1182
            if (this.groupColumn == null) {
1183
                return false;
1184
            }
1185
            return !this.groupColumn.isEmpty();
1186
        }
1187
        
1188
        @Override
1189
        public void disable_check_order_and_offset() {
1190
          this.check_order_and_offset = false;
1191
        }
1192
        
1193
        protected boolean isValid(StringBuilder message) {
1194
            if (message == null) {
1195
                message = new StringBuilder();
1196
            }
1197
            if( this.check_order_and_offset ) {
1198
              if (this.has_offset() && !this.has_order_by()) {
1199
                  // Algunos gestores de BBDD requieren que se especifique un
1200
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1201
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1202
                  // siempre.
1203
                  message.append("Can't use OFFSET without an ORDER BY.");
1204
                  return false;
1205
              }
1206
            }
1207
            return true;
1208
        }
1209

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

    
1215
        @Override
1216
        public String toString(Formatter<Value> formatter) {
1217
            if (formatter!=null && formatter.canApply(this)) {
1218
                return formatter.format(this);
1219
            }
1220
            StringBuilder builder = new StringBuilder();
1221
            if (!this.isValid(builder)) {
1222
                throw new IllegalStateException(builder.toString());
1223
            }
1224
            builder.append("SELECT ");
1225
            if (this.distinct) {
1226
                builder.append("DISTINCT ");
1227
            }
1228
            boolean first = true;
1229
            for (SelectColumnBuilder column : columns) {
1230
                if (first) {
1231
                    first = false;
1232
                } else {
1233
                    builder.append(", ");
1234
                }
1235
                builder.append(column.toString(formatter));
1236
            }
1237

    
1238
            if (this.has_from()) {
1239
                builder.append(" FROM ");
1240
                builder.append(this.from.toString(formatter));
1241
            }
1242
            if (this.has_where()) {
1243
                builder.append(" WHERE ");
1244
                builder.append(this.where.toString(formatter));
1245
            }
1246
            if( this.has_group_by() ) {
1247
                builder.append(" GROUP BY ");
1248
                builder.append(this.groupColumn.get(0).toString(formatter));
1249
                for (int i = 1; i < groupColumn.size(); i++) {
1250
                    builder.append(", ");
1251
                    builder.append(this.groupColumn.get(i).toString(formatter));
1252
                }
1253
            }
1254
            if (this.has_order_by()) {
1255
                builder.append(" ORDER BY ");
1256
                first = true;
1257
                for (OrderByBuilder item : this.order_by) {
1258
                    if (first) {
1259
                        first = false;
1260
                    } else {
1261
                        builder.append(", ");
1262
                    }
1263
                    builder.append(item.toString(formatter));
1264
                }
1265
            }
1266

    
1267
            if (this.has_limit()) {
1268
                builder.append(" LIMIT ");
1269
                builder.append(this.limit);
1270
            }
1271
            if (this.has_offset()) {
1272
                builder.append(" OFFSET ");
1273
                builder.append(this.offset);
1274
            }
1275
            return builder.toString();
1276

    
1277
        }
1278
    }
1279

    
1280
    public class DropTableBuilderBase
1281
            extends AbstractStatement
1282
            implements DropTableBuilder {
1283

    
1284
        protected TableNameBuilder table;
1285

    
1286
        @Override
1287
        public TableNameBuilder table() {
1288
            if (table == null) {
1289
                table = createTableNameBuilder();
1290
            }
1291
            return table;
1292
        }
1293

    
1294
        @Override
1295
        public void accept(Visitor visitor, VisitorFilter filter) {
1296
            if (filter==null || filter.accept(this)) {
1297
                visitor.visit(this);
1298
            }
1299
            this.table.accept(visitor, filter);
1300
        }
1301

    
1302
        @Override
1303
        public String toString() {
1304
            return this.toString(formatter());
1305
        }
1306

    
1307
        @Override
1308
        public String toString(Formatter<Value> formatter) {
1309
            if (formatter!=null && formatter.canApply(this)) {
1310
                return formatter.format(this);
1311
            }
1312
            StringBuilder builder = new StringBuilder();
1313
            boolean first = true;
1314
            for (String sql : toStrings(formatter)) {
1315
                if (StringUtils.isEmpty(sql)) {
1316
                    continue;
1317
                }
1318
                if (first) {
1319
                    first = false;
1320
                } else {
1321
                    builder.append("; ");
1322
                }
1323
                builder.append(sql);
1324
            }
1325
            return builder.toString();
1326
        }
1327

    
1328
        @Override
1329
        public List<String> toStrings() {
1330
            return this.toStrings(formatter());
1331
        }
1332

    
1333
        @Override
1334
        public List<String> toStrings(Formatter formatter) {
1335
            List<String> sqls = new ArrayList<>();
1336

    
1337
            sqls.add(
1338
                    MessageFormat.format(
1339
                            STMT_DROP_TABLE_table,
1340
                            this.table.toString(formatter)
1341
                    )
1342
            );
1343
            String sql;
1344
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1345
                if (this.table.has_schema()) {
1346
                    sql = MessageFormat.format(
1347
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1348
                            as_string(this.table.getSchema()),
1349
                            as_string(this.table.getName())
1350
                    );
1351
                } else {
1352
                    sql = MessageFormat.format(
1353
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1354
                            as_identifier(this.table.getName())
1355
                    );
1356
                }
1357
                if (!StringUtils.isEmpty(sql)) {
1358
                    sqls.add(sql);
1359
                }
1360
            }
1361
            return sqls;
1362
        }
1363
    }
1364

    
1365
    public class GrantRoleBuilderBase
1366
            extends AbstractStatementPart
1367
            implements GrantRoleBuilder {
1368

    
1369
        protected TableNameBuilder table;
1370
        protected String role;
1371
        protected Set<Privilege> privileges;
1372

    
1373
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1374
            this.table = table;
1375
            this.role = role;
1376
            this.privileges = new HashSet<>();
1377
        }
1378

    
1379
        @Override
1380
        public GrantRoleBuilder privilege(Privilege privilege) {
1381
            privileges.add(privilege);
1382
            return this;
1383
        }
1384

    
1385
        @Override
1386
        public GrantRoleBuilder select() {
1387
            privileges.add(Privilege.SELECT);
1388
            return this;
1389
        }
1390

    
1391
        @Override
1392
        public GrantRoleBuilder update() {
1393
            privileges.add(Privilege.UPDATE);
1394
            return this;
1395
        }
1396

    
1397
        @Override
1398
        public GrantRoleBuilder insert() {
1399
            privileges.add(Privilege.INSERT);
1400
            return this;
1401
        }
1402

    
1403
        @Override
1404
        public GrantRoleBuilder delete() {
1405
            privileges.add(Privilege.DELETE);
1406
            return this;
1407
        }
1408

    
1409
        @Override
1410
        public GrantRoleBuilder truncate() {
1411
            privileges.add(Privilege.TRUNCATE);
1412
            return this;
1413
        }
1414

    
1415
        @Override
1416
        public GrantRoleBuilder reference() {
1417
            privileges.add(Privilege.REFERENCE);
1418
            return this;
1419
        }
1420

    
1421
        @Override
1422
        public GrantRoleBuilder trigger() {
1423
            privileges.add(Privilege.TRIGGER);
1424
            return this;
1425
        }
1426

    
1427
        @Override
1428
        public GrantRoleBuilder all() {
1429
            privileges.add(Privilege.ALL);
1430
            return this;
1431
        }
1432

    
1433
        protected String getPrivilegeName(Privilege privilege) {
1434
            switch (privilege) {
1435
                case DELETE:
1436
                    return "DELETE";
1437
                case INSERT:
1438
                    return "INSERT";
1439
                case REFERENCE:
1440
                    return "REFERENCE";
1441
                case SELECT:
1442
                    return "SELECT";
1443
                case TRIGGER:
1444
                    return "TRIGGER";
1445
                case TRUNCATE:
1446
                    return "TRUNCATE";
1447
                case UPDATE:
1448
                    return "UPDATE";
1449
                case ALL:
1450
                default:
1451
                    return "ALL";
1452
            }
1453
        }
1454

    
1455
        @Override
1456
        public String toString() {
1457
            return this.toString(formatter());
1458
        }
1459

    
1460
        @Override
1461
        public String toString(Formatter<Value> formatter) {
1462
            if (formatter!=null && formatter.canApply(this)) {
1463
                return formatter.format(this);
1464
            }
1465
            StringBuilder builder = new StringBuilder();
1466
            boolean first = true;
1467
            for (Privilege privilege : privileges) {
1468
                if (first) {
1469
                    first = false;
1470
                } else {
1471
                    builder.append(", ");
1472
                }
1473
                builder.append(this.getPrivilegeName(privilege));
1474
            }
1475
            String sql = MessageFormat.format(
1476
                    STMT_GRANT_privileges_ON_table_TO_role,
1477
                    builder.toString(),
1478
                    table.toString(formatter),
1479
                    role
1480
            );
1481
            return sql;
1482
        }
1483
    }
1484

    
1485
    public class GrantBuilderBase
1486
            extends AbstractStatement
1487
            implements GrantBuilder {
1488

    
1489
        protected TableNameBuilder table;
1490
        protected Map<String, GrantRoleBuilder> roles;
1491

    
1492
        public GrantBuilderBase() {
1493
            this.roles = new HashMap<>();
1494
        }
1495

    
1496
        @Override
1497
        public TableNameBuilder table() {
1498
            if (table == null) {
1499
                table = createTableNameBuilder();
1500
            }
1501
            return table;
1502
        }
1503

    
1504
        @Override
1505
        public void accept(Visitor visitor, VisitorFilter filter) {
1506
            if (filter==null || filter.accept(this)) {
1507
                visitor.visit(this);
1508
            }
1509
            if (this.table != null) {
1510
                this.table.accept(visitor, filter);
1511
            }
1512
        }
1513

    
1514
        @Override
1515
        public GrantRoleBuilder role(String role) {
1516
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1517
            if (roleBuilder == null) {
1518
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1519
                this.roles.put(role, roleBuilder);
1520
            }
1521
            return roleBuilder;
1522
        }
1523

    
1524
        @Override
1525
        public String toString() {
1526
            return this.toString(formatter());
1527
        }
1528

    
1529
        @Override
1530
        public String toString(Formatter<Value> formatter) {
1531
            if (formatter!=null && formatter.canApply(this)) {
1532
                return formatter.format(this);
1533
            }
1534
            StringBuilder builder = new StringBuilder();
1535
            boolean first = true;
1536
            for (String sql : toStrings(formatter)) {
1537
                if (StringUtils.isEmpty(sql)) {
1538
                    continue;
1539
                }
1540
                if (first) {
1541
                    first = false;
1542
                } else {
1543
                    builder.append("; ");
1544
                }
1545
                builder.append(sql);
1546
            }
1547
            return builder.toString();
1548
        }
1549

    
1550
        @Override
1551
        public List<String> toStrings() {
1552
            return this.toStrings(formatter());
1553
        }
1554

    
1555
        @Override
1556
        public List<String> toStrings(Formatter formatter) {
1557
            List<String> sqls = new ArrayList<>();
1558
            for (GrantRoleBuilder role : roles.values()) {
1559
                sqls.add(role.toString(formatter));
1560
            }
1561
            return sqls;
1562
        }
1563
    }
1564

    
1565
    public class UpdateColumnBuilderBase
1566
            extends InsertColumnBuilderBase
1567
            implements UpdateColumnBuilder {
1568

    
1569
        public UpdateColumnBuilderBase() {
1570
            super();
1571
        }
1572

    
1573
        @Override
1574
        public UpdateColumnBuilder name(String name) {
1575
            return (UpdateColumnBuilder) super.name(name);
1576
        }
1577

    
1578
        @Override
1579
        public UpdateColumnBuilder with_value(Value value) {
1580
            return (UpdateColumnBuilder) super.with_value(value);
1581
        }
1582

    
1583
    }
1584

    
1585
    public class UpdateBuilderBase
1586
            extends AbstractStatement
1587
            implements UpdateBuilder {
1588

    
1589
        protected GeometryExpressionBuilder where;
1590
        protected List<UpdateColumnBuilder> columns;
1591
        protected TableNameBuilder table;
1592

    
1593
        public UpdateBuilderBase() {
1594
            this.columns = new ArrayList<>();
1595
        }
1596

    
1597
        @Override
1598
        public void accept(Visitor visitor, VisitorFilter filter) {
1599
            if (filter==null || filter.accept(this)) {
1600
                visitor.visit(this);
1601
            }
1602
            if (this.table != null) {
1603
                this.table.accept(visitor, filter);
1604
            }
1605
            for (UpdateColumnBuilder column : columns) {
1606
                column.accept(visitor, filter);
1607
            }
1608
            if (this.has_where()) {
1609
                this.where.accept(visitor, filter);
1610
            }
1611
        }
1612

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

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

    
1629
        @Override
1630
        public UpdateColumnBuilder column() {
1631
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1632
            this.columns.add(column);
1633
            return column;
1634
        }
1635

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

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

    
1646
        @Override
1647
        public String toString(Formatter<Value> formatter) {
1648
            if (formatter!=null && formatter.canApply(this)) {
1649
                return formatter.format(this);
1650
            }
1651
            /*
1652
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1653
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1654
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1655
             * output_expression [ AS output_name ] [, ...] ]
1656
             */
1657
            StringBuilder columnsAndValues = new StringBuilder();
1658

    
1659
            boolean first = true;
1660
            for (UpdateColumnBuilder column : columns) {
1661
                if (first) {
1662
                    first = false;
1663
                } else {
1664
                    columnsAndValues.append(", ");
1665
                }
1666
                columnsAndValues.append(as_identifier(column.getName()));
1667
                columnsAndValues.append(" = ");
1668
                columnsAndValues.append(column.getValue().toString(formatter));
1669
            }
1670

    
1671
            String sql;
1672
            if (this.has_where()) {
1673
                sql = MessageFormat.format(
1674
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1675
                        this.table.toString(formatter),
1676
                        columnsAndValues.toString(),
1677
                        this.where.toString(formatter)
1678
                );
1679
            } else {
1680
                sql = MessageFormat.format(
1681
                        STMT_UPDATE_table_SET_columnsAndValues,
1682
                        this.table.toString(formatter),
1683
                        columnsAndValues.toString()
1684
                );
1685
            }
1686
            return sql;
1687
        }
1688
    }
1689

    
1690
    public class DeleteBuilderBase
1691
            extends AbstractStatement
1692
            implements DeleteBuilder {
1693

    
1694
        protected GeometryExpressionBuilder where;
1695
        protected TableNameBuilder table;
1696

    
1697
        public DeleteBuilderBase() {
1698
        }
1699

    
1700
        @Override
1701
        public void accept(Visitor visitor, VisitorFilter filter) {
1702
            if (filter==null || filter.accept(this)) {
1703
                visitor.visit(this);
1704
            }
1705
            if (this.table != null) {
1706
                this.table.accept(visitor, filter);
1707
            }
1708
            if (this.has_where()) {
1709
                this.where.accept(visitor, filter);
1710
            }
1711
        }
1712

    
1713
        @Override
1714
        public GeometryExpressionBuilder where() {
1715
            if (this.where == null) {
1716
                this.where = createExpressionBuilder();
1717
            }
1718
            return this.where;
1719
        }
1720

    
1721
        @Override
1722
        public TableNameBuilder table() {
1723
            if (table == null) {
1724
                table = createTableNameBuilder();
1725
            }
1726
            return table;
1727
        }
1728

    
1729
        @Override
1730
        public boolean has_where() {
1731
            return this.where != null;
1732
        }
1733

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

    
1739
        @Override
1740
        public String toString(Formatter<Value> formatter) {
1741
            if (formatter!=null && formatter.canApply(this)) {
1742
                return formatter.format(this);
1743
            }
1744
            /*
1745
             * DELETE FROM table_name
1746
             * WHERE some_column=some_value; 
1747
             */
1748
            String sql;
1749
            if (this.has_where()) {
1750
                sql = MessageFormat.format(
1751
                        STMT_DELETE_FROM_table_WHERE_expresion,
1752
                        this.table.toString(formatter),
1753
                        this.where.toString(formatter)
1754
                );
1755
            } else {
1756
                sql = MessageFormat.format(
1757
                        STMT_DELETE_FROM_table,
1758
                        this.table.toString(formatter)
1759
                );
1760
            }
1761
            return sql;
1762
        }
1763
    }
1764

    
1765
    public class CreateIndexBuilderBase
1766
            extends AbstractStatement
1767
            implements CreateIndexBuilder {
1768

    
1769
        protected boolean ifNotExist = false;
1770
        protected boolean isUnique = false;
1771
        protected String indexName;
1772
        protected boolean isSpatial = false;
1773
        protected TableNameBuilder table;
1774
        protected final List<String> columns;
1775

    
1776
        public CreateIndexBuilderBase() {
1777
            this.columns = new ArrayList<>();
1778
        }
1779

    
1780
        @Override
1781
        public CreateIndexBuilder unique() {
1782
            this.isUnique = true;
1783
            return this;
1784
        }
1785

    
1786
        @Override
1787
        public CreateIndexBuilder if_not_exist() {
1788
            this.ifNotExist = true;
1789
            return this;
1790
        }
1791

    
1792
        @Override
1793
        public CreateIndexBuilder name(String name) {
1794
            this.indexName = name;
1795
            return this;
1796
        }
1797

    
1798
        @Override
1799
        public CreateIndexBuilder name(String tableName, String columnName) {
1800
            this.indexName = tableName + "_IDX_" + columnName;
1801
            return this;
1802
        }
1803

    
1804
        @Override
1805
        public CreateIndexBuilder spatial() {
1806
            this.isSpatial = true;
1807
            return this;
1808
        }
1809

    
1810
        @Override
1811
        public CreateIndexBuilder column(String name) {
1812
            this.columns.add(name);
1813
            return this;
1814
        }
1815

    
1816
        @Override
1817
        public TableNameBuilder table() {
1818
            if (table == null) {
1819
                table = createTableNameBuilder();
1820
            }
1821
            return table;
1822
        }
1823

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

    
1834
        @Override
1835
        public String toString() {
1836
            return this.toString(formatter());
1837
        }
1838

    
1839
        @Override
1840
        public String toString(Formatter<Value> formatter) {
1841
            if (formatter!=null && formatter.canApply(this)) {
1842
                return formatter.format(this);
1843
            }
1844
            StringBuilder builder = new StringBuilder();
1845
            boolean first = true;
1846
            for (String sql : toStrings(formatter)) {
1847
                if (StringUtils.isEmpty(sql)) {
1848
                    continue;
1849
                }
1850
                if (first) {
1851
                    first = false;
1852
                } else {
1853
                    builder.append("; ");
1854
                }
1855
                builder.append(sql);
1856
            }
1857
            return builder.toString();
1858
        }
1859

    
1860
        @Override
1861
        public List<String> toStrings() {
1862
            return this.toStrings(formatter());
1863
        }
1864

    
1865
        @Override
1866
        public List<String> toStrings(Formatter formatter) {
1867
            StringBuilder builder = new StringBuilder();
1868
            builder.append("CREATE ");
1869
            if (this.isUnique) {
1870
                builder.append("UNIQUE ");
1871
            }
1872
            builder.append("INDEX ");
1873
            if (this.ifNotExist) {
1874
                builder.append("IF NOT EXISTS ");
1875
            }
1876
            builder.append(as_identifier(this.indexName));
1877
            builder.append(" ON ");
1878
            builder.append(this.table.toString(formatter));
1879
            if (this.isSpatial) {
1880
                builder.append(" USING GIST ");
1881
            }
1882
            builder.append(" ( ");
1883
            boolean is_first_column = true;
1884
            for (String column : this.columns) {
1885
                if (is_first_column) {
1886
                    is_first_column = false;
1887
                } else {
1888
                    builder.append(", ");
1889
                }
1890
                builder.append(column);
1891
            }
1892
            builder.append(" )");
1893

    
1894
            List<String> sqls = new ArrayList<>();
1895
            sqls.add(builder.toString());
1896
            return sqls;
1897
        }
1898

    
1899
    }
1900

    
1901
    public class DropIndexBuilderBase
1902
            extends AbstractStatement
1903
            implements DropIndexBuilder {
1904

    
1905
        protected boolean ifNotExist = false;
1906
        protected String indexName;
1907

    
1908
        public DropIndexBuilderBase() {
1909
        }
1910

    
1911
        @Override
1912
        public DropIndexBuilder if_not_exist() {
1913
            this.ifNotExist = true;
1914
            return this;
1915
        }
1916

    
1917
        @Override
1918
        public DropIndexBuilder name(String name) {
1919
            this.indexName = name;
1920
            return this;
1921
        }
1922

    
1923
        @Override
1924
        public DropIndexBuilder name(String tableName, String columnName) {
1925
            this.indexName = tableName + "_IDX_" + columnName;
1926
            return this;
1927
        }
1928

    
1929
        @Override
1930
        public String toString() {
1931
            return this.toString(formatter());
1932
        }
1933

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

    
1955
        @Override
1956
        public List<String> toStrings() {
1957
            return this.toStrings(formatter());
1958
        }
1959

    
1960
        @Override
1961
        public List<String> toStrings(Formatter formatter) {
1962
            StringBuilder builder = new StringBuilder();
1963
            builder.append("DROP INDEX ");
1964
            if (this.ifNotExist) {
1965
                builder.append("IF NOT EXISTS ");
1966
            }
1967
            builder.append(as_identifier(this.indexName));
1968
            List<String> sqls = new ArrayList<>();
1969
            sqls.add(builder.toString());
1970
            return sqls;
1971
        }
1972

    
1973
    }
1974

    
1975
    public class AlterTableBuilderBase
1976
            extends AbstractStatement
1977
            implements AlterTableBuilder {
1978

    
1979
        protected TableNameBuilder table;
1980
        protected List<String> drops;
1981
        protected List<ColumnDescriptor> adds;
1982
        protected List<ColumnDescriptor> alters;
1983
        protected List<Pair<String, String>> renames;
1984
        protected String drop_primary_key_column;
1985

    
1986
        public AlterTableBuilderBase() {
1987
            this.drops = new ArrayList<>();
1988
            this.adds = new ArrayList<>();
1989
            this.alters = new ArrayList<>();
1990
            this.renames = new ArrayList<>();
1991
        }
1992

    
1993
        @Override
1994
        public boolean isEmpty() {
1995
            return this.drops.isEmpty()
1996
                    && this.adds.isEmpty()
1997
                    && this.alters.isEmpty()
1998
                    && this.renames.isEmpty();
1999
        }
2000

    
2001
        @Override
2002
        public void accept(Visitor visitor, VisitorFilter filter) {
2003
            if (filter==null || filter.accept(this)) {
2004
                visitor.visit(this);
2005
            }
2006
            if (this.table != null) {
2007
                this.table.accept(visitor, filter);
2008
            }
2009
        }
2010

    
2011
        @Override
2012
        public TableNameBuilder table() {
2013
            if (table == null) {
2014
                table = createTableNameBuilder();
2015
            }
2016
            return table;
2017
        }
2018

    
2019
        @Override
2020
        public AlterTableBuilder drop_column(String columnName) {
2021
            this.drops.add(columnName);
2022
            return this;
2023
        }
2024

    
2025
        @Override
2026
        public AlterTableBuilder drop_primary_key(String columnName) {
2027
            this.drop_primary_key_column = columnName;
2028
            return this;
2029
        }
2030

    
2031
        @Override
2032
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2033
            this.adds.add(new ColumnDescriptorBase(fad));
2034
            return this;
2035
        }
2036

    
2037
        @Override
2038
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2039
            if (isPk || isAutomatic) {
2040
                allowNulls = false;
2041
            }
2042
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2043
            return this;
2044
        }
2045

    
2046
        @Override
2047
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2048
            if (StringUtils.isEmpty(columnName)) {
2049
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2050
            }
2051
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2052
            return this;
2053
        }
2054

    
2055
        @Override
2056
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2057
            if (StringUtils.isEmpty(columnName)) {
2058
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2059
            }
2060
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2061
            return this;
2062
        }
2063

    
2064
        @Override
2065
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2066
            this.alters.add(new ColumnDescriptorBase(fad));
2067
            return this;
2068
        }
2069

    
2070
        @Override
2071
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2072
            if (isPk || isAutomatic) {
2073
                allowNulls = false;
2074
            }
2075
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2076
            return this;
2077
        }
2078

    
2079
        @Override
2080
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2081
            if (StringUtils.isEmpty(columnName)) {
2082
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2083
            }
2084
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2085
            return this;
2086
        }
2087

    
2088
        @Override
2089
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2090
            if (StringUtils.isEmpty(columnName)) {
2091
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2092
            }
2093
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2094
            return this;
2095
        }
2096

    
2097
        @Override
2098
        public AlterTableBuilder rename_column(String source, String target) {
2099
            this.renames.add(new ImmutablePair(source, target));
2100
            return this;
2101
        }
2102

    
2103
        protected String getConstrainName(String constrainType, String columnName) {
2104
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2105
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2106
            return constraint_name;
2107
        }
2108

    
2109
        @Override
2110
        public String toString() {
2111
            return this.toString(formatter());
2112
        }
2113

    
2114
        @Override
2115
        public String toString(Formatter<Value> formatter) {
2116
            if (formatter!=null && formatter.canApply(this)) {
2117
                return formatter.format(this);
2118
            }
2119
            StringBuilder builder = new StringBuilder();
2120
            boolean first = true;
2121
            for (String sql : toStrings(formatter)) {
2122
                if (StringUtils.isEmpty(sql)) {
2123
                    continue;
2124
                }
2125
                if (first) {
2126
                    first = false;
2127
                } else {
2128
                    builder.append("; ");
2129
                }
2130
                builder.append(sql);
2131
            }
2132
            return builder.toString();
2133
        }
2134

    
2135
        @Override
2136
        public List<String> toStrings() {
2137
            return this.toStrings(formatter());
2138
        }
2139

    
2140
        @Override
2141
        public List<String> toStrings(Formatter formatter) {
2142
            List<String> sqls = new ArrayList<>();
2143
            if (this.isEmpty()) {
2144
                return sqls;
2145
            }
2146
            for (String column : drops) {
2147
                StringBuilder builder = new StringBuilder();
2148
                builder.append("ALTER TABLE ");
2149
                builder.append(this.table.toString(formatter));
2150
                builder.append(" DROP COLUMN IF EXISTS ");
2151
                builder.append(as_identifier(column));
2152
                sqls.add(builder.toString());
2153
            }
2154
            for (ColumnDescriptor column : adds) {
2155
                StringBuilder builder = new StringBuilder();
2156
                builder.append("ALTER TABLE ");
2157
                builder.append(this.table.toString(formatter));
2158
                builder.append(" ADD COLUMN ");
2159
                builder.append(as_identifier(column.getName()));
2160
                builder.append(" ");
2161
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2162
                    builder.append(" SERIAL");
2163
                } else {
2164
                    builder.append(
2165
                            sqltype(
2166
                                    column.getType(),
2167
                                    column.getSize(),
2168
                                    column.getPrecision(),
2169
                                    column.getScale(),
2170
                                    column.getGeometryType(),
2171
                                    column.getGeometrySubtype()
2172
                            )
2173
                    );
2174
                }
2175
                if (column.getDefaultValue() == null) {
2176
                    if (column.allowNulls()) {
2177
                        builder.append(" DEFAULT NULL");
2178
                    }
2179
                } else {
2180
                    builder.append(" DEFAULT '");
2181
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2182
                    builder.append("'");
2183
                }
2184
                if (column.allowNulls()) {
2185
                    builder.append(" NULL");
2186
                } else {
2187
                    builder.append(" NOT NULL");
2188
                }
2189
                if (column.isPrimaryKey()) {
2190
                    builder.append(" PRIMARY KEY");
2191
                }
2192
                sqls.add(builder.toString());
2193
            }
2194
            for (ColumnDescriptor column : alters) {
2195
                StringBuilder builder = new StringBuilder();
2196
                builder.append("ALTER TABLE ");
2197
                builder.append(this.table.toString(formatter));
2198
                builder.append(" ALTER COLUMN ");
2199
                builder.append(as_identifier(column.getName()));
2200
                builder.append(" SET DATA TYPE ");
2201
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2202
                    builder.append(" SERIAL");
2203
                } else {
2204
                    builder.append(
2205
                            sqltype(
2206
                                    column.getType(),
2207
                                    column.getSize(),
2208
                                    column.getPrecision(),
2209
                                    column.getScale(),
2210
                                    column.getGeometryType(),
2211
                                    column.getGeometrySubtype()
2212
                            )
2213
                    );
2214
                }
2215
                if (column.getDefaultValue() == null) {
2216
                    if (column.allowNulls()) {
2217
                        builder.append(" DEFAULT NULL");
2218
                    } else {
2219
                        builder.append(" DROP DEFAULT");
2220
                    }
2221
                } else {
2222
                    builder.append(" DEFAULT '");
2223
                    builder.append(column.getDefaultValue().toString());
2224
                    builder.append("'");
2225
                }
2226
                sqls.add(builder.toString());
2227
            }
2228
            for (Pair<String, String> pair : renames) {
2229
                StringBuilder builder = new StringBuilder();
2230
                builder.append("ALTER TABLE ");
2231
                builder.append(this.table.toString(formatter));
2232
                builder.append(" RENAME COLUMN ");
2233
                builder.append(as_identifier(pair.getLeft()));
2234
                builder.append(" TO ");
2235
                builder.append(as_identifier(pair.getRight()));
2236
                sqls.add(builder.toString());
2237
            }
2238
            return sqls;
2239
        }
2240

    
2241
    }
2242

    
2243
    public class CreateTableBuilderBase
2244
            extends AbstractStatement
2245
            implements CreateTableBuilder {
2246

    
2247
        protected TableNameBuilder table;
2248
        protected List<ColumnDescriptor> columns;
2249

    
2250
        public CreateTableBuilderBase() {
2251
            this.columns = new ArrayList<>();
2252
        }
2253

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

    
2264
        @Override
2265
        public TableNameBuilder table() {
2266
            if (table == null) {
2267
                table = createTableNameBuilder();
2268
            }
2269
            return table;
2270
        }
2271

    
2272
        @Override
2273
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2274
            this.columns.add(new ColumnDescriptorBase(fad));
2275
            return this;
2276
        }
2277

    
2278
        @Override
2279
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2280
            if (StringUtils.isEmpty(columnName)) {
2281
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2282
            }
2283
            if (isPk || isAutomatic) {
2284
                allowNulls = false;
2285
            }
2286
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2287
            return this;
2288
        }
2289

    
2290
        @Override
2291
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2292
            if (StringUtils.isEmpty(columnName)) {
2293
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2294
            }
2295
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2296
            return this;
2297
        }
2298

    
2299
        @Override
2300
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2301
            if (StringUtils.isEmpty(columnName)) {
2302
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2303
            }
2304
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2305
            return this;
2306
        }
2307

    
2308
        @Override
2309
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2310
            if (StringUtils.isEmpty(columnName)) {
2311
                return null;
2312
            }
2313
            for (ColumnDescriptor column : columns) {
2314
                if (columnName.equals(column.getName())) {
2315
                    return column;
2316
                }
2317
            }
2318
            return null;
2319
        }
2320

    
2321
        @Override
2322
        public String toString() {
2323
            return this.toString(formatter());
2324
        }
2325

    
2326
        @Override
2327
        public String toString(Formatter<Value> formatter) {
2328
            if (formatter!=null && formatter.canApply(this)) {
2329
                return formatter.format(this);
2330
            }
2331
            StringBuilder builder = new StringBuilder();
2332
            boolean first = true;
2333
            for (String sql : toStrings(formatter)) {
2334
                if (StringUtils.isEmpty(sql)) {
2335
                    continue;
2336
                }
2337
                if (first) {
2338
                    first = false;
2339
                } else {
2340
                    builder.append("; ");
2341
                }
2342
                builder.append(sql);
2343
            }
2344
            return builder.toString();
2345
        }
2346

    
2347
        @Override
2348
        public List<String> toStrings() {
2349
            return this.toStrings(formatter());
2350
        }
2351

    
2352
        @Override
2353
        public List<String> toStrings(Formatter formatter) {
2354
            List<String> sqls = new ArrayList<>();
2355
            /**
2356
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2357
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2358
             * column_constraint [ ... ] ] | table_constraint | LIKE
2359
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2360
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2361
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2362
             *
2363
             * where column_constraint is:
2364
             *
2365
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2366
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2367
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2368
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2369
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2370
             *
2371
             * and table_constraint is:
2372
             *
2373
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2374
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2375
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2376
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2377
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2378
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2379
             */
2380
            StringBuilder builder = new StringBuilder();
2381

    
2382
            builder.append("CREATE TABLE ");
2383
            builder.append(this.table.toString(formatter));
2384
            builder.append(" (");
2385
            boolean first = true;
2386
            for (ColumnDescriptor column : columns) {
2387
                if (first) {
2388
                    first = false;
2389
                } else {
2390
                    builder.append(", ");
2391
                }
2392
                builder.append(as_identifier(column.getName()));
2393
                builder.append(" ");
2394
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2395
                    builder.append("SERIAL");
2396
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2397
                    builder.append("BIGSERIAL");
2398
                } else {
2399
                    builder.append(sqltype(
2400
                            column.getType(),
2401
                            column.getSize(),
2402
                            column.getPrecision(),
2403
                            column.getScale(),
2404
                            column.getGeometryType(),
2405
                            column.getGeometrySubtype()
2406
                    )
2407
                    );
2408
                }
2409
                if (column.getDefaultValue() == null) {
2410
                    if (column.allowNulls()) {
2411
                        builder.append(" DEFAULT NULL");
2412
                    }
2413
                } else {
2414
                    builder.append(" DEFAULT '");
2415
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2416
                    builder.append("'");
2417
                }
2418
                if (column.allowNulls()) {
2419
                    builder.append(" NULL");
2420
                } else {
2421
                    builder.append(" NOT NULL");
2422
                }
2423
                if (column.isPrimaryKey()) {
2424
                    builder.append(" PRIMARY KEY");
2425
                }
2426
            }
2427
            builder.append(" )");
2428
            sqls.add(builder.toString());
2429
            return sqls;
2430
        }
2431
    }
2432

    
2433
    public class InsertColumnBuilderBase
2434
            extends AbstractStatement
2435
            implements InsertColumnBuilder {
2436

    
2437
        protected Variable name;
2438
        protected Value value;
2439

    
2440
        public InsertColumnBuilderBase() {
2441
        }
2442

    
2443
        @Override
2444
        public void accept(Visitor visitor, VisitorFilter filter) {
2445
            if (filter==null || filter.accept(this)) {
2446
                visitor.visit(this);
2447
            }
2448
            if (this.name != null) {
2449
                this.name.accept(visitor, filter);
2450
            }
2451
            if (this.value != null) {
2452
                this.value.accept(visitor, filter);
2453
            }
2454
        }
2455

    
2456
        @Override
2457
        public InsertColumnBuilder name(String name) {
2458
            this.name = expression().variable(name);
2459
            return this;
2460
        }
2461

    
2462
        @Override
2463
        public InsertColumnBuilder with_value(Value value) {
2464
            this.value = value;
2465
            return this;
2466
        }
2467

    
2468
        @Override
2469
        public String getName() {
2470
            return this.name.name();
2471
        }
2472

    
2473
        @Override
2474
        public Value getValue() {
2475
            return this.value;
2476
        }
2477

    
2478
        @Override
2479
        public String toString() {
2480
            return this.toString(formatter());
2481
        }
2482

    
2483
        @Override
2484
        public String toString(Formatter<Value> formatter) {
2485
            if (formatter!=null && formatter.canApply(this)) {
2486
                return formatter.format(this);
2487
            }
2488
            return this.value.toString(formatter);
2489
        }
2490
    }
2491

    
2492
    public class InsertBuilderBase
2493
            extends AbstractStatement
2494
            implements InsertBuilder {
2495

    
2496
        protected List<InsertColumnBuilder> columns;
2497
        protected TableNameBuilder table;
2498

    
2499
        public InsertBuilderBase() {
2500
            this.columns = new ArrayList<>();
2501
        }
2502

    
2503
        @Override
2504
        public void accept(Visitor visitor, VisitorFilter filter) {
2505
            if (filter==null || filter.accept(this)) {
2506
                visitor.visit(this);
2507
            }
2508
            if (this.table != null) {
2509
                this.table.accept(visitor, filter);
2510
            }
2511
            for (InsertColumnBuilder column : columns) {
2512
                column.accept(visitor, filter);
2513
            }
2514
        }
2515

    
2516
        @Override
2517
        public TableNameBuilder table() {
2518
            if (table == null) {
2519
                table = createTableNameBuilder();
2520
            }
2521
            return table;
2522
        }
2523

    
2524
        @Override
2525
        public InsertColumnBuilder column() {
2526
            InsertColumnBuilder column = createInsertColumnBuilder();
2527
            this.columns.add(column);
2528
            return column;
2529
        }
2530

    
2531
        @Override
2532
        public String toString() {
2533
            return this.toString(formatter());
2534
        }
2535

    
2536
        @Override
2537
        public String toString(Formatter<Value> formatter) {
2538
            if (formatter!=null && formatter.canApply(this)) {
2539
                return formatter.format(this);
2540
            }
2541
            /*
2542
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2543
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2544
             * output_expression [ AS output_name ] [, ...] ]
2545
             */
2546
            StringBuilder builderColumns = new StringBuilder();
2547
            StringBuilder builderValues = new StringBuilder();
2548

    
2549
            boolean first = true;
2550
            for (InsertColumnBuilder column : columns) {
2551
                if (first) {
2552
                    first = false;
2553
                } else {
2554
                    builderColumns.append(", ");
2555
                }
2556
                builderColumns.append(as_identifier(column.getName()));
2557
            }
2558
            first = true;
2559
            for (InsertColumnBuilder column : columns) {
2560
                if (first) {
2561
                    first = false;
2562
                } else {
2563
                    builderValues.append(", ");
2564
                }
2565
                builderValues.append(column.toString(formatter));
2566
            }
2567

    
2568
            String sql = MessageFormat.format(
2569
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2570
                    this.table.toString(formatter),
2571
                    builderColumns.toString(),
2572
                    builderValues.toString()
2573
            );
2574
            return sql;
2575

    
2576
        }
2577
    }
2578

    
2579
    public class UpdateTableStatisticsBuilderBase
2580
            extends AbstractStatement
2581
            implements UpdateTableStatisticsBuilder {
2582

    
2583
        protected TableNameBuilder table;
2584

    
2585
        @Override
2586
        public void accept(Visitor visitor, VisitorFilter filter) {
2587
            if (filter==null || filter.accept(this)) {
2588
                visitor.visit(this);
2589
            }
2590
            if (this.table != null) {
2591
                this.table.accept(visitor, filter);
2592
            }
2593
        }
2594

    
2595
        @Override
2596
        public TableNameBuilder table() {
2597
            if (table == null) {
2598
                table = createTableNameBuilder();
2599
            }
2600
            return table;
2601
        }
2602

    
2603
        @Override
2604
        public String toString() {
2605
            return this.toString(formatter());
2606
        }
2607

    
2608
        @Override
2609
        public String toString(Formatter<Value> formatter) {
2610
            if (formatter!=null && formatter.canApply(this)) {
2611
                return formatter.format(this);
2612
            }
2613
            StringBuilder builder = new StringBuilder();
2614
            boolean first = true;
2615
            for (String sql : toStrings(formatter)) {
2616
                if (StringUtils.isEmpty(sql)) {
2617
                    continue;
2618
                }
2619
                if (first) {
2620
                    first = false;
2621
                } else {
2622
                    builder.append("; ");
2623
                }
2624
                builder.append(sql);
2625
            }
2626
            return builder.toString();
2627
        }
2628

    
2629
        @Override
2630
        public List<String> toStrings() {
2631
            return this.toStrings(formatter());
2632
        }
2633

    
2634
        @Override
2635
        public List<String> toStrings(Formatter formatter) {
2636
            List<String> sqls = new ArrayList<>();
2637

    
2638
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2639
                String sql = MessageFormat.format(
2640
                        STMT_UPDATE_TABLE_STATISTICS_table,
2641
                        table.toString(formatter)
2642
                );
2643
                if (!StringUtils.isEmpty(sql)) {
2644
                    sqls.add(sql);
2645
                }
2646
            }
2647
            return sqls;
2648
        }
2649
    }
2650

    
2651
    protected GeometryExpressionBuilder expressionBuilder;
2652

    
2653
    protected String defaultSchema;
2654
    protected boolean supportSchemas;
2655
    protected boolean hasSpatialFunctions;
2656
    protected GeometrySupportType geometrySupportType;
2657
    protected boolean allowAutomaticValues;
2658

    
2659
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2660

    
2661
    protected String constant_true = "(1=1)";
2662
    protected String constant_false = "(1<>1)";
2663

    
2664
    protected String type_boolean = "BOOLEAN";
2665
    protected String type_byte = "TINYINT";
2666
    protected String type_bytearray = "BYTEA";
2667
    protected String type_geometry = "TEXT";
2668
    protected String type_char = "CHARACTER(1)";
2669
    protected String type_date = "DATE";
2670
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2671
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2672
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2673
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2674
    protected String type_int = "INT";
2675
    protected String type_long = "BIGINT";
2676
    protected String type_string = "TEXT";
2677
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2678
    protected String type_time = "TIME";
2679
    protected String type_timestamp = "TIMESTAMP";
2680
    protected String type_version = "VARCHAR(30)";
2681
    protected String type_URI = "TEXT";
2682
    protected String type_URL = "TEXT";
2683
    protected String type_FILE = "TEXT";
2684
    protected String type_FOLDER = "TEXT";
2685

    
2686
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2687
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2688
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2689
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2690
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2691
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2692
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2693
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2694
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2695
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2696

    
2697
    public SQLBuilderBase() {
2698
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2699

    
2700
        this.hasSpatialFunctions = false;
2701
        this.supportSchemas = true;
2702
        this.geometrySupportType = GeometrySupportType.WKT;
2703

    
2704
        this.defaultSchema = "public";
2705
        this.allowAutomaticValues = true;
2706

    
2707
    }
2708
    
2709
    @Override
2710
    public void setProperties(Class filter, final Object... values) {
2711
        this.expressionBuilder.setProperties(filter, values);
2712
        this.accept(new Visitor() {
2713
            @Override
2714
            public void visit(Visitable v) {
2715
                for (int i = 0; i < values.length; i+=2) {
2716
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2717
                }
2718
            }
2719
        }, new ClassVisitorFilter(filter) );
2720
    }
2721

    
2722
    public String quote_for_identifiers() {
2723
        return "\"";
2724
    }
2725

    
2726
    public String quote_for_strings() {
2727
        return "'";
2728
    }
2729

    
2730
    @Override
2731
    public String as_identifier(String id) {
2732
        String quote = this.quote_for_identifiers();
2733
//        No se porque no esta disponible wrapIfMissing
2734
//        return StringUtils.wrapIfMissing(id,quote);
2735
        if (id.startsWith(quote)) {
2736
            return id;
2737
        }
2738
        return quote + id + quote;
2739

    
2740
    }
2741

    
2742
    @Override
2743
    public String as_string(String s) {
2744
        String quote = this.quote_for_strings();
2745
//        No se porque no esta disponible wrapIfMissing
2746
//        return StringUtils.wrapIfMissing(id,quote);
2747
        if (s.startsWith(quote)) {
2748
            return s;
2749
        }
2750
        return quote + s + quote;
2751

    
2752
    }
2753

    
2754
    @Override
2755
    public String as_string(byte[] data) {
2756
        return this.expressionBuilder.bytearray_0x(data);
2757
//        return this.expressionBuilder.bytearray_hex(data);
2758
//        return this.expressionBuilder.bytearray_x(data);
2759
    }
2760
    
2761
    @Override
2762
    public String as_string(boolean value) {
2763
        return value? "TRUE" : "FALSE";
2764
    }
2765

    
2766
    @Override
2767
    public String as_string(Number value) {
2768
        return Objects.toString(value);
2769
    }
2770
    
2771
    @Override
2772
    public String as_string(Object value) {
2773
        if( value == null ) {
2774
            return "NULL";
2775
        }
2776
        if( value instanceof CharSequence ) {
2777
            return as_string(value.toString());
2778
        }
2779
        if( value instanceof Number ) {
2780
            return as_string((Number)value);
2781
        }
2782
        if( value instanceof Boolean ) {
2783
            return as_string((boolean)value);
2784
        }
2785
        if( value instanceof byte[] ) {
2786
            return as_string((byte[])value);
2787
        }
2788
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2789
    }
2790
    
2791
    @Override
2792
    public GeometryExpressionBuilder expression() {
2793
        return this.expressionBuilder;
2794
    }
2795

    
2796
    @Override
2797
    public boolean has_spatial_functions() {
2798
        return this.hasSpatialFunctions;
2799
    }
2800

    
2801
    @Override
2802
    public GeometrySupportType geometry_support_type() {
2803
        return this.geometrySupportType;
2804
    }
2805

    
2806
    protected GeometryExpressionBuilder createExpressionBuilder() {
2807
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2808
    }
2809

    
2810
    @Override
2811
    public Object srs_id(IProjection projection) {
2812
        String abrev = projection.getAbrev();
2813
        return abrev.split(":")[1].trim();
2814
    }
2815

    
2816
    @Override
2817
    public String default_schema() {
2818
        return this.defaultSchema;
2819
    }
2820

    
2821
    @Override
2822
    public boolean support_schemas() {
2823
        return this.supportSchemas;
2824
    }
2825

    
2826
    @Override
2827
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2828
        switch (type) {
2829
            case DataTypes.BOOLEAN:
2830
                return type_boolean;
2831
            case DataTypes.CHAR:
2832
                return type_char;
2833

    
2834

    
2835
            case DataTypes.BYTE:
2836
                return type_byte;
2837
            case DataTypes.INT:
2838
                return type_int;
2839
            case DataTypes.LONG:
2840
                return type_long;
2841

    
2842
            case DataTypes.FLOAT:
2843
                return type_float;
2844
            case DataTypes.DOUBLE:
2845
                return type_double;
2846
            case DataTypes.DECIMAL:
2847
                if (precision < 1) {
2848
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2849
                }
2850
                if (scale < 1) {
2851
                  return MessageFormat.format(type_decimal_p, precision);
2852
                }
2853
                return MessageFormat.format(type_decimal_ps, precision, scale);
2854

    
2855
                
2856
            case DataTypes.STRING:
2857
                if (size < 0) {
2858
                    return type_string;
2859
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
2860
                    return MessageFormat.format(type_string_p, size);
2861
                }
2862
                return type_string;
2863

    
2864
                
2865
            case DataTypes.DATE:
2866
                return type_date;
2867
            case DataTypes.TIME:
2868
                return type_time;
2869
            case DataTypes.TIMESTAMP:
2870
                return type_timestamp;
2871

    
2872
            case DataTypes.BYTEARRAY:
2873
                return type_bytearray;
2874

    
2875
            case DataTypes.GEOMETRY:
2876
                return type_geometry;
2877

    
2878
            case DataTypes.VERSION:
2879
                return type_version;
2880
            case DataTypes.URI:
2881
                return type_URI;
2882
            case DataTypes.URL:
2883
                return type_URL;
2884
            case DataTypes.FILE:
2885
                return type_FILE;
2886
            case DataTypes.FOLDER:
2887
                return type_FOLDER;
2888
            default:
2889
                return null;
2890
        }
2891
    }
2892

    
2893
    @Override
2894
    public Object sqlgeometrytype(int type, int subtype) {
2895
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2896
        // identificadores numericos para el tipo y otros strings.
2897
        // Por defecto vamos a devolver strings.
2898
        if (sqlgeometrytypes == null) {
2899
            sqlgeometrytypes = new HashMap<>();
2900
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2901
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2902
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2903
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2904

    
2905
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2906
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2907
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2908
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2909

    
2910
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2911
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2912
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2913
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2914

    
2915
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2916
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2917
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2918
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2919

    
2920
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2921
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2922
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2923
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2924

    
2925
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2926
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2927
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2928
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2929

    
2930
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2931
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2932
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2933
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2934

    
2935
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2936
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2937
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2938
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2939

    
2940
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2941
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2942
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2943
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2944
        }
2945
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2946
    }
2947

    
2948
    @Override
2949
    public Object sqlgeometrydimension(int type, int subtype) {
2950
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2951
        // identificadores numericos para las dimensiones y otros strings.
2952
        // Por defecto vamos a devolver enteros.
2953
        switch (subtype) {
2954
            case Geometry.SUBTYPES.GEOM3D:
2955
                return 3;
2956
            case Geometry.SUBTYPES.GEOM2DM:
2957
                return 3;
2958
            case Geometry.SUBTYPES.GEOM3DM:
2959
                return 4;
2960
            case Geometry.SUBTYPES.GEOM2D:
2961
            default:
2962
                return 2;
2963
        }
2964
    }
2965

    
2966
    @Override
2967
    public TableNameBuilder createTableNameBuilder() {
2968
        return new TableNameBuilderBase();
2969
    }
2970

    
2971
    protected SelectColumnBuilder createSelectColumnBuilder() {
2972
        return new SelectColumnBuilderBase();
2973
    }
2974

    
2975
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2976
        return new UpdateColumnBuilderBase();
2977
    }
2978

    
2979
    protected InsertColumnBuilder createInsertColumnBuilder() {
2980
        return new InsertColumnBuilderBase();
2981
    }
2982

    
2983
    protected OrderByBuilder createOrderByBuilder() {
2984
        return new OrderByBuilderBase();
2985
    }
2986

    
2987
    protected FromBuilder createFromBuilder() {
2988
        return new FromBuilderBase();
2989
    }
2990

    
2991
    protected SelectBuilder createSelectBuilder() {
2992
        return new SelectBuilderBase();
2993
    }
2994

    
2995
    protected UpdateBuilder createUpdateBuilder() {
2996
        return new UpdateBuilderBase();
2997
    }
2998

    
2999
    protected DeleteBuilder createDeleteBuilder() {
3000
        return new DeleteBuilderBase();
3001
    }
3002

    
3003
    protected GrantBuilder createGrantBuilder() {
3004
        return new GrantBuilderBase();
3005
    }
3006

    
3007
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3008
        return new GrantRoleBuilderBase(table, role);
3009
    }
3010

    
3011
    protected DropTableBuilder createDropTableBuilder() {
3012
        return new DropTableBuilderBase();
3013
    }
3014

    
3015
    protected CreateTableBuilder createCreateTableBuilder() {
3016
        return new CreateTableBuilderBase();
3017
    }
3018

    
3019
    protected AlterTableBuilder createAlterTableBuilder() {
3020
        return new AlterTableBuilderBase();
3021
    }
3022

    
3023
    protected InsertBuilder createInsertBuilder() {
3024
        return new InsertBuilderBase();
3025
    }
3026

    
3027
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3028
        return new UpdateTableStatisticsBuilderBase();
3029
    }
3030

    
3031
    protected CreateIndexBuilder createCreateIndexBuilder() {
3032
        return new CreateIndexBuilderBase();
3033
    }
3034

    
3035
    protected DropIndexBuilder createDropIndexBuilder() {
3036
        return new DropIndexBuilderBase();
3037
    }
3038

    
3039
    @Override
3040
    public SelectBuilder select() {
3041
        if (this.select == null) {
3042
            this.select = this.createSelectBuilder();
3043
        }
3044
        return this.select;
3045
    }
3046

    
3047
    @Override
3048
    public UpdateBuilder update() {
3049
        if (this.update == null) {
3050
            this.update = this.createUpdateBuilder();
3051
        }
3052
        return this.update;
3053
    }
3054

    
3055
    @Override
3056
    public UpdateTableStatisticsBuilder update_table_statistics() {
3057
        if (this.update_table_statistics == null) {
3058
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3059
        }
3060
        return this.update_table_statistics;
3061
    }
3062

    
3063
    @Override
3064
    public DropTableBuilder drop_table() {
3065
        if (this.drop_table == null) {
3066
            this.drop_table = this.createDropTableBuilder();
3067
        }
3068
        return this.drop_table;
3069
    }
3070

    
3071
    @Override
3072
    public CreateIndexBuilder create_index() {
3073
        if (this.create_index == null) {
3074
            this.create_index = this.createCreateIndexBuilder();
3075
        }
3076
        return this.create_index;
3077
    }
3078

    
3079
    @Override
3080
    public DropIndexBuilder drop_index() {
3081
        if (this.drop_index == null) {
3082
            this.drop_index = this.createDropIndexBuilder();
3083
        }
3084
        return this.drop_index;
3085
    }
3086

    
3087
    @Override
3088
    public DeleteBuilder delete() {
3089
        if (this.delete == null) {
3090
            this.delete = this.createDeleteBuilder();
3091
        }
3092
        return this.delete;
3093
    }
3094

    
3095
    @Override
3096
    public InsertBuilder insert() {
3097
        if (this.insert == null) {
3098
            this.insert = this.createInsertBuilder();
3099
        }
3100
        return this.insert;
3101
    }
3102

    
3103
    @Override
3104
    public TableNameBuilder table_name() {
3105
        if (this.table_name == null) {
3106
            this.table_name = this.createTableNameBuilder();
3107
        }
3108
        return this.table_name;
3109
    }
3110

    
3111
    
3112
    @Override
3113
    public AlterTableBuilder alter_table() {
3114
        if (this.alter_table == null) {
3115
            this.alter_table = this.createAlterTableBuilder();
3116
        }
3117
        return this.alter_table;
3118
    }
3119

    
3120
    @Override
3121
    public CreateTableBuilder create_table() {
3122
        if (this.create_table == null) {
3123
            this.create_table = this.createCreateTableBuilder();
3124
        }
3125
        return this.create_table;
3126
    }
3127

    
3128
    @Override
3129
    public GrantBuilder grant() {
3130
        if (this.grant == null) {
3131
            this.grant = this.createGrantBuilder();
3132
        }
3133
        return this.grant;
3134
    }
3135
    
3136
    @Override
3137
    public Column column(String name) {
3138
        ColumnBase col = new ColumnBase(null, name);
3139
        return col;
3140
    }
3141

    
3142
    @Override
3143
    public Column column(TableNameBuilder table, String name) {
3144
        ColumnBase col = new ColumnBase(table, name);
3145
        return col;
3146
    }
3147
    
3148
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3149
        return new JoinBase(type, table, expression);
3150
    }
3151

    
3152
    public void accept(Visitor visitor, VisitorFilter filter) {
3153
        if (this.select != null) {
3154
            this.select.accept(visitor, filter);
3155
        }
3156
        if (this.update != null) {
3157
            this.update.accept(visitor, filter);
3158
        }
3159
        if (this.insert != null) {
3160
            this.insert.accept(visitor, filter);
3161
        }
3162
        if (this.delete != null) {
3163
            this.delete.accept(visitor, filter);
3164
        }
3165
        if (this.alter_table != null) {
3166
            this.alter_table.accept(visitor, filter);
3167
        }
3168
        if (this.create_table != null) {
3169
            this.create_table.accept(visitor, filter);
3170
        }
3171
        if (this.drop_table != null) {
3172
            this.drop_table.accept(visitor, filter);
3173
        }
3174
        if (this.table_name != null) {
3175
            this.table_name.accept(visitor, filter);
3176
        }
3177
    }
3178

    
3179
        @Override
3180
    public Formatter formatter() {
3181
        return expression().formatter();
3182
    }
3183

    
3184
    @Override
3185
    public String toString() {
3186
        return this.toString(formatter());
3187
    }
3188

    
3189
    @Override
3190
    public String toString(Formatter formatter) {
3191
        if (this.select != null) {
3192
            return this.select.toString(formatter);
3193
        }
3194
        if (this.update != null) {
3195
            return this.update.toString(formatter);
3196
        }
3197
        if (this.insert != null) {
3198
            return this.insert.toString(formatter);
3199
        }
3200
        if (this.delete != null) {
3201
            return this.delete.toString(formatter);
3202
        }
3203
        if (this.alter_table != null) {
3204
            return this.alter_table.toString(formatter);
3205
        }
3206
        if (this.create_table != null) {
3207
            return this.create_table.toString(formatter);
3208
        }
3209
        if (this.drop_table != null) {
3210
            return this.drop_table.toString(formatter);
3211
        }
3212
        if (this.update_table_statistics != null) {
3213
            return this.update_table_statistics.toString(formatter);
3214
        }
3215
        if (this.create_index != null) {
3216
            return this.create_index.toString(formatter);
3217
        }
3218
        if (this.drop_index != null) {
3219
            return this.drop_index.toString(formatter);
3220
        }
3221
        if (this.table_name != null) {
3222
            return this.table_name.toString(formatter);
3223
        }
3224
        return "";
3225
    }
3226

    
3227
    @Override
3228
    public CountBuilder count() {
3229
        return new CountBuilderBase();
3230
    }
3231

    
3232
    @Override
3233
    public List<Parameter> parameters() {
3234
        final List<Parameter> params = new ArrayList<>();
3235
        this.accept(new Visitor() {
3236
            @Override
3237
            public void visit(Visitable value) {
3238
                params.add((Parameter) value);
3239
            }
3240
        }, new ClassVisitorFilter(Parameter.class));
3241
        return params;
3242
    }
3243

    
3244
    @Override
3245
    public List<Variable> variables() {
3246
        final List<Variable> vars = new ArrayList<>();
3247
        this.accept(new Visitor() {
3248
            @Override
3249
            public void visit(Visitable value) {
3250
                if (!vars.contains((Variable) value)) {
3251
                    vars.add((Variable) value);
3252
                }
3253
            }
3254
        }, new ClassVisitorFilter(Variable.class));
3255
        return vars;
3256
    }
3257

    
3258
    @Override
3259
    public List<String> parameters_names() {
3260
        List<String> params = new ArrayList<>();
3261
        for (Parameter param : parameters()) {
3262
            String s;
3263
            switch (param.type()) {
3264
                case PARAMETER_TYPE_CONSTANT:
3265
                    Object theValue = param.value();
3266
                    if (theValue == null) {
3267
                        s = "null";
3268
                    } else if (theValue instanceof String) {
3269
                        s = "'" + (String) theValue + "'";
3270
                    } else {
3271
                        s = theValue.toString();
3272
                    }
3273
                    break;
3274
                case PARAMETER_TYPE_VARIABLE:
3275
                default:
3276
                    s = "\"" + param.name() + "\"";
3277
            }
3278
            params.add(s);
3279
        }
3280
        return params;
3281
    }
3282

    
3283
    @Override
3284
    public List<String> variables_names() {
3285
        List<String> vars = new ArrayList<>();
3286
        for (Variable var : this.variables()) {
3287
            vars.add(var.name());
3288
        }
3289
        Collections.sort(vars);
3290
        return vars;
3291
    }    
3292
}