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

History | View | Annotate | Download (116 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.fmap.geom.GeometryUtils;
54
import org.gvsig.fmap.geom.primitive.Envelope;
55
import org.gvsig.tools.dataTypes.DataType;
56
import org.gvsig.tools.dynobject.Tags;
57
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
59

    
60
@SuppressWarnings("UseSpecificCatch")
61
public class SQLBuilderBase implements SQLBuilder {
62

    
63
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
64

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

    
78
    protected abstract class AbstractStatementPart extends AbstractValue {
79
        
80
    }
81

    
82
    protected abstract class AbstractStatement extends AbstractStatementPart {
83
        @Override
84
        public Value clone() throws CloneNotSupportedException {
85
            throw new CloneNotSupportedException();
86
        }
87
    }
88

    
89
    protected class ColumnDescriptorBase implements ColumnDescriptor {
90

    
91
        private String name;
92
        private int type;
93
        private int size;
94
        private int precision;
95
        private int scale;
96
        private boolean isPk;
97
        private boolean _allowNulls;
98
        private boolean _isAutomatic;
99
        private Object defaultValue;
100
        private int geom_type;
101
        private int geom_subtype;
102
        private Object geom_srsdbcode;
103
        private Envelope tablebbox;
104
        private boolean _isIndexed;
105
        private DataStoreParameters parameters = null;
106

    
107
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
108
            this.name = name;
109
            this.type = type;
110
            this.size = -1;
111
            this.precision = -1;
112
            this.scale = -1;
113
            this.isPk = false;
114
            this._allowNulls = true;
115
            this._isAutomatic = false;
116
            this.defaultValue = defaultValue;
117
            this.geom_type = Geometry.TYPES.GEOMETRY;
118
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
119
            this.geom_srsdbcode = null;
120
            this.tablebbox = null;
121
            this._isIndexed = false;
122
        }
123

    
124
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
125
            this.name = name;
126
            this.type = type;
127
            this.size = size;
128
            this.precision = precision;
129
            this.scale = scale;
130
            this.isPk = isPk;
131
            this._allowNulls = allowNulls;
132
            this._isAutomatic = isAutomatic;
133
            this.defaultValue = defaultValue;
134
            this.geom_type = Geometry.TYPES.GEOMETRY;
135
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
136
            this.geom_srsdbcode = null;
137
            this.tablebbox = null;
138
            this._isIndexed = isIndexed;
139
        }
140

    
141
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
142
            this.name = name;
143
            this.type = DataTypes.GEOMETRY;
144
            this.size = 0;
145
            this.precision = 0;
146
            this.scale = 0;
147
            this.isPk = false;
148
            this._allowNulls = allowNulls;
149
            this._isAutomatic = false;
150
            this.defaultValue = null;
151
            this.geom_type = geom_type;
152
            this.geom_subtype = geom_subtype;
153
            this.geom_srsdbcode = srs_id(proj);
154
            this.tablebbox = null;
155
            this._isIndexed = isIndexed;
156
        }
157

    
158
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
159
            this.name = name;
160
            this.type = DataTypes.GEOMETRY;
161
            this.size = 0;
162
            this.precision = 0;
163
            this.scale = 0;
164
            this.isPk = false;
165
            this._allowNulls = allowNulls;
166
            this._isAutomatic = false;
167
            this.defaultValue = null;
168
            this.geom_type = geom_type;
169
            this.geom_subtype = geom_subtype;
170
            this.geom_srsdbcode = srsdbcode;
171
            this.tablebbox = null;
172
            this._isIndexed = isIndexed;
173
        }
174

    
175
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
176
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
177
            this.precision = fad.getPrecision();
178
            this.size = fad.getSize();
179
            this.scale = fad.getScale();
180
            this.isPk = fad.isPrimaryKey();
181
            this._allowNulls = fad.allowNull();
182
            this._isAutomatic = fad.isAutomatic();
183
            this._isIndexed = fad.isIndexed();
184

    
185
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
186
                this.geom_type = fad.getGeomType().getType();
187
                this.geom_subtype = fad.getGeomType().getSubType();
188
                this.geom_srsdbcode =  srs_id(fad.getSRS());
189
                this.tablebbox = null;
190
                Tags tags = fad.getTags();
191
                String s = tags.getString("tablebbox", null);
192
                if( StringUtils.isNotBlank(s) ) {
193
                    try {
194
                        Geometry g = GeometryUtils.createFrom(s);
195
                        if( g!=null ) {
196
                            this.tablebbox = g.getEnvelope();
197
                        }
198
                    } catch(Exception ex) {
199
                        LOGGER.warn("Can't parse tablebbox for column '"+s+"'.",ex);
200
                    }
201
                }
202
            }
203
        }
204
    
205

    
206
        @Override
207
        public String getName() {
208
            return this.name;
209
        }
210

    
211
        @Override
212
        public void setName(String name) {
213
            this.name = name;
214
        }
215

    
216
        @Override
217
        public int getType() {
218
            return this.type;
219
        }
220

    
221
        @Override
222
        public void setType(int type) {
223
            this.type = type;
224
        }
225

    
226
        @Override
227
        public int getPrecision() {
228
            return precision;
229
        }
230

    
231
        @Override
232
        public void setPrecision(int precision) {
233
            this.precision = precision;
234
        }
235

    
236
        @Override
237
        public int getScale() {
238
            return scale;
239
        }
240

    
241
        @Override
242
        public void setScale(int scale) {
243
            this.scale = scale;
244
        }
245

    
246
        @Override
247
        public int getSize() {
248
            return size;
249
        }
250

    
251
        @Override
252
        public void setSize(int size) {
253
            this.size = size;
254
        }
255

    
256
        @Override
257
        public boolean isPrimaryKey() {
258
            return isPk;
259
        }
260

    
261
        @Override
262
        public void setIsPrimaryKey(boolean isPk) {
263
            this.isPk = isPk;
264
        }
265

    
266
        @Override
267
        public boolean allowNulls() {
268
            return _allowNulls;
269
        }
270

    
271
        @Override
272
        public void setAllowNulls(boolean allowNulls) {
273
            this._allowNulls = allowNulls;
274
        }
275

    
276
        @Override
277
        public boolean isAutomatic() {
278
            return _isAutomatic;
279
        }
280

    
281
        @Override
282
        public boolean isIndexed() {
283
            return _isIndexed;
284
        }
285

    
286
        @Override
287
        public void setIsAutomatic(boolean isAutomatic) {
288
            this._isAutomatic = isAutomatic;
289
        }
290

    
291
        @Override
292
        public Object getDefaultValue() {
293
            return defaultValue;
294
        }
295

    
296
        @Override
297
        public void setDefaultValue(Object defaultValue) {
298
            this.defaultValue = defaultValue;
299
        }
300

    
301
        @Override
302
        public int getGeometryType() {
303
            return geom_type;
304
        }
305

    
306
        @Override
307
        public void setGeometryType(int geom_type) {
308
            this.geom_type = geom_type;
309
        }
310

    
311
        @Override
312
        public int getGeometrySubtype() {
313
            return geom_subtype;
314
        }
315

    
316
        @Override
317
        public void setGeometrySubtype(int geom_subtype) {
318
            this.geom_subtype = geom_subtype;
319
        }
320

    
321
        @Override
322
        public Object getGeometrySRSId() {
323
            return geom_srsdbcode;
324
        }
325

    
326
        @Override
327
        public void setGeometrySRSId(Object geom_srsid) {
328
            this.geom_srsdbcode = geom_srsid;
329
        }
330

    
331
        @Override
332
        public boolean isGeometry() {
333
            return this.type == DataTypes.GEOMETRY;
334
        }
335

    
336
        private void setStoreParameters(DataStoreParameters parameters) {
337
            this.parameters = parameters;
338
        }
339

    
340
        @Override
341
        public DataStoreParameters getStoreParameters() {
342
            return this.parameters;
343
        }
344
        
345
        public Envelope getTableBBox() {
346
            return this.tablebbox;
347
        }
348
        
349
        public void setTableBBox(Envelope bbox) {
350
            this.tablebbox = bbox;
351
        }
352
    }
353

    
354
    public class ColumnBase extends AbstractValue implements Column {
355

    
356
        private final String name;
357
        private TableNameBuilder table;
358

    
359
        public ColumnBase(TableNameBuilder table, String name) {
360
            this.name = name;
361
            this.table = table;
362
        }
363
        
364
        @Override
365
        public ColumnBase clone() throws CloneNotSupportedException {
366
            ColumnBase other = (ColumnBase) super.clone();
367
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
368
            return other;
369
        }
370

    
371

    
372
        @Override
373
        public String name() {
374
            return this.name;
375
        }
376

    
377
        @Override
378
        public TableNameBuilder table() {
379
            return this.table;
380
        }
381

    
382
        @Override
383
        public TableNameBuilder table(TableNameBuilder table) {
384
            this.table = table;
385
            return this.table;
386
        }
387

    
388
        @Override
389
        public String toString() {
390
            return this.toString(formatter());
391
        }
392
        
393
        @Override
394
        public String toString(Formatter<Value> formatter) {
395
            if( formatter!=null && formatter.canApply(this) ) {
396
                return formatter.format(this);
397
            }
398
            if( this.table==null ) {
399
                return as_identifier(this.name);
400
            }
401
            return this.table.toString(formatter) + "." + as_identifier(this.name);
402
        }
403

    
404
        @Override
405
        public int compareTo(Variable o) {
406
            return this.name.compareTo(o.name());
407
        }
408

    
409
        @Override
410
        public boolean equals(Object obj) {
411
            if (!(obj instanceof Variable)) {
412
                return false;
413
            }
414
            return StringUtils.equals(this.toString(), ((Variable) obj).toString());
415
        }
416

    
417
        @Override
418
        public int hashCode() {
419
            int hash = 7;
420
            hash = 37 * hash + Objects.hashCode(this.toString());
421
            return hash;
422
        }
423
    }
424

    
425
    public class TableNameBuilderBase
426
            extends AbstractStatementPart
427
            implements TableNameBuilder {
428

    
429
        public String tableName;
430
        public String schemaName;
431
        private String databaseName;
432

    
433
        public TableNameBuilderBase() {
434
        }
435
        
436
        @Override
437
        public void accept(Visitor visitor, VisitorFilter filter) {
438
            if (filter==null || filter.accept(this)) {
439
                visitor.visit(this);
440
            }
441
        }
442

    
443
        @Override
444
        public TableNameBuilder database(String name) {
445
            this.databaseName = name;
446
            return this;
447
        }
448

    
449
        @Override
450
        public TableNameBuilder schema(String name) {
451
            if (support_schemas()) {
452
                this.schemaName = name;
453
            }
454
            return this;
455
        }
456

    
457
        @Override
458
        public TableNameBuilder name(String name) {
459
            this.tableName = name;
460
            return this;
461
        }
462

    
463
        @Override
464
        public String getDatabase() {
465
            return this.databaseName;
466
        }
467

    
468
        @Override
469
        public String getSchema() {
470
            return this.schemaName;
471
        }
472

    
473
        @Override
474
        public String getName() {
475
            return this.tableName;
476
        }
477

    
478
        @Override
479
        public boolean has_schema() {
480
            if (!support_schemas()) {
481
                return false;
482
            }
483
            return !StringUtils.isEmpty(this.schemaName);
484
        }
485

    
486
        @Override
487
        public boolean has_database() {
488
            return !StringUtils.isEmpty(this.databaseName);
489
        }
490

    
491
        @Override
492
        public String toString() {
493
            return this.toString(formatter());
494
        }
495

    
496
        @Override
497
        public String toString(Formatter<Value> formatter) {
498
            if (formatter!=null && formatter.canApply(this)) {
499
                return formatter.format(this);
500
            }
501
            if (this.has_database()) {
502
                if (this.has_schema()) {
503
                    return as_identifier(this.databaseName) + "."
504
                            + as_identifier(this.schemaName) + "."
505
                            + as_identifier(this.tableName);
506
                }
507
            } else {
508
                if (this.has_schema()) {
509
                    return as_identifier(this.schemaName) + "."
510
                            + as_identifier(this.tableName);
511
                }
512
            }
513
            return as_identifier(this.tableName);
514
        }
515

    
516
        @Override
517
        public boolean equals(Object obj) {
518
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
519
                return false;
520
            }
521
            TableNameBuilder other = (TableNameBuilder) obj;
522
            
523
            if (this.has_database() != other.has_database()) {
524
                return false;
525
            }
526
            String thisSchema = null;
527
            String otherSchema = null;
528
            if(support_schemas()) {
529
                thisSchema = this.schemaName;
530
                if (StringUtils.isBlank(thisSchema)) {
531
                    thisSchema = default_schema();
532
                }
533
                otherSchema = other.getSchema();
534
                if (StringUtils.isBlank(otherSchema)) {
535
                    otherSchema = default_schema();
536
                }
537
            }
538
            if (this.has_database()) {
539
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
540
                           StringUtils.equals(thisSchema, otherSchema) &&
541
                           StringUtils.equals(this.tableName,other.getName());
542
            } else {
543
                    return StringUtils.equals(thisSchema, otherSchema) &&
544
                           StringUtils.equals(this.tableName,other.getName());
545
            }
546
        }
547

    
548
        @Override
549
        public int hashCode() {
550
            int hash = 7;
551
            hash = 37 * hash + Objects.hashCode(this.toString());
552
            return hash;
553
        }
554

    
555
    }
556

    
557
    public class CountBuilderBase
558
            extends AbstractStatementPart
559
            implements CountBuilder {
560

    
561
        protected Value value;
562
        protected boolean distinct;
563
        protected boolean all;
564

    
565
        public CountBuilderBase() {
566
            this.value = null;
567
            this.distinct = false;
568
            this.all = false;
569
        }
570
        
571
        @Override
572
        public CountBuilderBase clone() throws CloneNotSupportedException {
573
            CountBuilderBase other = (CountBuilderBase) super.clone();
574
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
575
            return other;
576
        }
577
        
578
        @Override
579
        public CountBuilder all() {
580
            this.all = true;
581
            return this;
582
        }
583

    
584
        @Override
585
        public CountBuilder column(Value value) {
586
            this.value = value;
587
            return this;
588
        }
589

    
590
        @Override
591
        public CountBuilder distinct() {
592
            this.distinct = true;
593
            return this;
594
        }
595

    
596
        @Override
597
        public String toString() {
598
            return this.toString(formatter());
599
        }
600

    
601
        @Override
602
        public String toString(Formatter formatter) {
603
            if (formatter!=null && formatter.canApply(this)) {
604
                return formatter.format(this);
605
            }
606
            if (this.all) {
607
                return "COUNT(*)";
608
            }
609
            if (this.distinct) {
610
                return MessageFormat.format(
611
                        "COUNT(DISTINCT {0})",
612
                        value.toString(formatter)
613
                );
614
            }
615
            return MessageFormat.format(
616
                    "COUNT({0})",
617
                    value.toString(formatter)
618
            );
619
        }
620

    
621
    }
622

    
623
    protected class JoinBase 
624
            extends AbstractStatementPart
625
            implements StatementPart 
626
        {
627
        protected String type;
628
        protected TableNameBuilder table;
629
        protected Value expression;
630
        
631
        public JoinBase(String type, TableNameBuilder table, Value expression) {
632
            this.type = type;
633
            this.table = table;
634
            this.expression = expression;
635
        }
636
        
637
        @Override
638
        public JoinBase clone() throws CloneNotSupportedException {
639
            JoinBase other = (JoinBase) super.clone();
640
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
641
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
642
            return other;
643
        }
644

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

    
650
        @Override
651
        public String toString(Formatter<Value> formatter) {
652
            if (formatter!=null && formatter.canApply(this)) {
653
                return formatter.format(this);
654
            }
655
            StringBuilder builder = new StringBuilder();
656
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
657
            builder.append(this.type.toUpperCase());
658
            builder.append(" JOIN ");
659
            builder.append(this.table.toString(formatter));
660
            builder.append(" ON ");
661
            builder.append(this.expression.toString(formatter));
662
            return builder.toString();
663
        }
664
        
665
        
666
    }
667
    
668
    public class FromBuilderBase
669
            extends AbstractStatementPart
670
            implements FromBuilder {
671

    
672
        protected TableNameBuilder tableName;
673
        protected String subquery;
674
        protected String passthrough;
675
        protected List<JoinBase> joins;
676

    
677
        public FromBuilderBase() {
678
            this.tableName = null;
679
            this.subquery = null;
680
            this.passthrough = null;
681
            this.joins = null;
682
        }
683
        
684
        @Override
685
        public FromBuilderBase clone() throws CloneNotSupportedException {
686
            FromBuilderBase other = (FromBuilderBase) super.clone();
687
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
688
            if (joins!=null) {
689
                for (int i = 0; i < joins.size(); i++) {
690
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
691
                }
692
            }
693
            return other;
694
        }
695

    
696
        @Override
697
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
698
            JoinBase join = createJoin("LEFT", table, expression);
699
            if( this.joins==null ) {
700
                this.joins = new ArrayList<>();
701
            }
702
            this.joins.add(join);
703
            return this;
704
        }
705
        
706
        @Override
707
        public TableNameBuilder table() {
708
            if (tableName == null) {
709
                this.tableName = createTableNameBuilder();
710
            }
711
            return this.tableName;
712
        }
713

    
714
        @Override
715
        public void accept(Visitor visitor, VisitorFilter filter) {
716
            if (filter==null || filter.accept(this)) {
717
                visitor.visit(this);
718
            }
719
            if (this.tableName != null) {
720
                this.tableName.accept(visitor, filter);
721
            }
722
        }
723

    
724
        @Override
725
        public FromBuilder custom(String passthrough) {
726
            this.passthrough = passthrough;
727
            return this;
728
        }
729

    
730
        @Override
731
        public FromBuilder subquery(String subquery) {
732
            this.subquery = subquery;
733
            return this;
734
        }
735

    
736
        @Override
737
        public String toString() {
738
            return this.toString(formatter());
739
        }
740

    
741
        @Override
742
        public String toString(Formatter<Value> formatter) {
743
            if (formatter!=null && formatter.canApply(this)) {
744
                return formatter.format(this);
745
            }
746
            if (!StringUtils.isEmpty(passthrough)) {
747
                return passthrough;
748
            }
749
            if (!StringUtils.isEmpty(subquery)) {
750
                return "( " + this.subquery + ") as _subquery_alias_ ";
751
            }
752
            if( this.joins==null || this.joins.isEmpty() ) {
753
                return this.tableName.toString(formatter);
754
            }
755
            StringBuilder builder = new StringBuilder();
756
            builder.append(this.tableName.toString(formatter));
757
            for (JoinBase join : this.joins) {
758
                builder.append(" ");
759
                builder.append(join.toString(formatter));
760
            }
761
            return builder.toString();
762
        }
763

    
764
    }
765

    
766
    public class SelectColumnBuilderBase
767
            extends AbstractStatementPart
768
            implements SelectColumnBuilder {
769

    
770
        protected Variable name = null;
771
        protected String alias = null;
772
        protected Value value = null;
773
        protected boolean asGeometry = false;
774
        protected TableNameBuilder table;
775
        protected SQLBuilder sqlbuilder;
776
        
777
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
778
            this.sqlbuilder = sqlbuilder;
779
        }
780
        
781
        @Override
782
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
783
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
784
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
785
            other.name = (Variable) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
786
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
787
            return other;
788
        }
789

    
790
        @Override
791
        public void accept(Visitor visitor, VisitorFilter filter) {
792
            if (filter==null || filter.accept(this)) {
793
                visitor.visit(this);
794
            }
795
            if (this.name != null) {
796
                this.name.accept(visitor, filter);
797
            }
798
            if (this.value != null) {
799
                this.value.accept(visitor, filter);
800
            }
801
        }
802

    
803
        @Override
804
        public void replace(Value target, Value replacement) {
805
            if (this.name!=null ) {
806
                if( this.name == target) {
807
                    this.name = (Variable) replacement;
808
                }
809
            }
810
            if( this.value!=null ) {
811
                if (this.value == target) {
812
                    this.value = replacement;
813
                } else {
814
                    this.value.replace(target, replacement);
815
                }
816
            }
817
        }
818

    
819
        @Override
820
        public SelectColumnBuilder name(String name) {
821
            return this.name(null, name);
822
        }
823

    
824
        @Override
825
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
826
            String quote = quote_for_identifiers();
827
            if (name.startsWith(quote)) {
828
                // Remove quotes
829
                name = name.substring(1, name.length() - 1);
830
            }
831
            this.name = expression().variable(name);
832
            this.table = table;
833
            this.value = null;
834
            this.asGeometry = false;
835
            return this;
836
        }
837

    
838
        @Override
839
        public SelectColumnBuilder all() {
840
            this.name = null;
841
            this.value = expression().custom("*");
842
            this.asGeometry = false;
843
            return this;
844
        }
845

    
846
        @Override
847
        public SelectColumnBuilder as_geometry() {
848
            this.asGeometry = true;
849
            return this;
850
        }
851

    
852
        @Override
853
        public SelectColumnBuilder value(Value value) {
854
            this.value = value;
855
            this.name = null;
856
            return this;
857
        }
858

    
859
        @Override
860
        public SelectColumnBuilder as(String alias) {
861
            this.alias = alias;
862
            return this;
863
        }
864

    
865
        @Override
866
        public String getName() {
867
            if (this.name==null) {
868
                return null;
869
            }
870
            return this.name.name();
871
        }
872

    
873
        @Override
874
        public String getAlias() {
875
            return this.alias;
876
        }
877

    
878
        @Override
879
        public String getValue() {
880
            return this.alias;
881
        }
882

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

    
888
        @Override
889
        public String toString(Formatter<Value> formatter) {
890
            if (formatter!=null && formatter.canApply(this)) {
891
                return formatter.format(this);
892
            }
893
            StringBuilder builder = new StringBuilder();
894
            if (this.asGeometry) {
895
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
896
            } else {
897
                if (this.name != null) {
898
                    if( this.table==null ) {
899
                        builder.append(this.name.toString(formatter));
900
                    } else {
901
                        builder.append(this.table.toString(formatter));
902
                        builder.append(".");
903
                        builder.append(this.name.toString(formatter));
904
                    }
905
                } else {
906
                    builder.append(this.value.toString(formatter));
907
                }
908
            }
909
            if (this.alias != null) {
910
                builder.append(" AS ");
911
                builder.append(as_identifier(this.alias));
912
            }
913
            return builder.toString();
914
        }
915
        
916
        @Override
917
        public boolean isGeometry() {
918
            return this.asGeometry;
919
        }
920
        
921
        @Override
922
        public TableNameBuilder getTable() {
923
            return this.table;
924
        }
925
        
926
        @Override
927
        public boolean isAggregateFunction() {
928
            if( this.value == null ) {
929
                return false;
930
            }
931
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
932
                return false;
933
            }
934
            String funcname = ((ExpressionBuilder.Function)this.value).name();
935
            return this.sqlbuilder.isAggregateFunction(funcname);
936
        }
937
    }
938

    
939
    public class OrderByBuilderBase
940
            extends AbstractStatementPart
941
            implements OrderByBuilder {
942

    
943
        protected Value value;
944
        protected String custom;
945
        protected boolean ascending;
946
        protected int nullsMode;
947

    
948
        public OrderByBuilderBase() {
949
            this.ascending = true;
950
            this.nullsMode = MODE_NULLS_LAST;
951
        }
952
        
953
        @Override
954
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
955
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
956
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
957
            return other;
958
        }
959
        
960
        @Override
961
        public void accept(Visitor visitor, VisitorFilter filter) {
962
            if (filter==null || filter.accept(this)) {
963
                visitor.visit(this);
964
            }
965
            if (this.value!=null) {
966
                this.value.accept(visitor, filter);
967
            }
968
        }
969

    
970
        @Override
971
        public OrderByBuilder column(String name) {
972
            this.value = expression().variable(name);
973
            return this;
974
        }
975
        
976
        @Override
977
        public boolean isColumn(String name) {
978
            if(this.value instanceof ExpressionBuilder.Variable){
979
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
980
            }
981
            return false;
982
        }
983
        
984
        @Override
985
        public boolean isColumn(Value value) {
986
            if(value instanceof ExpressionBuilder.Variable){
987
                return isColumn(((ExpressionBuilder.Variable)value).name());
988
            }
989
            return this.value == value;
990
        }
991
        
992
        @Override
993
        public OrderByBuilder value(Value expression) {
994
            this.value = expression;
995
            return this;
996
        }
997
        
998
        @Override
999
        public OrderByBuilder custom(String order) {
1000
            this.custom = order;
1001
            return this;
1002
        }
1003

    
1004
        @Override
1005
        public OrderByBuilder ascending() {
1006
            this.ascending = true;
1007
            return this;
1008
        }
1009

    
1010
        @Override
1011
        public OrderByBuilder ascending(boolean asc) {
1012
            this.ascending = asc;
1013
            return this;
1014
        }
1015

    
1016
        @Override
1017
        public OrderByBuilder descending() {
1018
            this.ascending = false;
1019
            return this;
1020
        }
1021

    
1022
        @Override
1023
        public OrderByBuilder nulls(int mode) {
1024
            this.nullsMode = mode;
1025
            return this;
1026
        }
1027

    
1028
        @Override
1029
        public int getNullsMode() {
1030
            return this.nullsMode;
1031
        }
1032

    
1033
        @Override
1034
        public String toString() {
1035
            return this.toString(formatter());
1036
        }
1037

    
1038
        @Override
1039
        public String toString(Formatter<Value> formatter) {
1040
            if (formatter!=null && formatter.canApply(this)) {
1041
                return formatter.format(this);
1042
            }
1043
            if (!StringUtils.isEmpty(this.custom)) {
1044
                return this.custom;
1045
            }
1046
            String order_s = this.value.toString(formatter);
1047
            if (this.ascending) {
1048
                order_s += " ASC";
1049
            } else {
1050
                order_s += " DESC";
1051
            }
1052
            switch(this.nullsMode) {
1053
                case MODE_NULLS_NOT_SPECIFIED:
1054
                    break;
1055
                case MODE_NULLS_FIRST:
1056
                    order_s += " NULLS FIRST";
1057
                    break;
1058
                case MODE_NULLS_LAST:
1059
                default:
1060
                    order_s += " NULLS LAST";
1061
                    break;
1062
            }
1063
            return order_s;
1064
        }
1065
    }
1066

    
1067
    public class SelectBuilderBase
1068
            extends AbstractStatement
1069
            implements SelectBuilder {
1070

    
1071
        protected FromBuilder from;
1072
        protected GeometryExpressionBuilder where;
1073
        protected long limit = -1;
1074
        protected long offset = -1;
1075
        protected List<SelectColumnBuilder> columns;
1076
        protected List<OrderByBuilder> order_by;
1077
        protected boolean distinct;
1078
        protected List<Value> groupColumn;
1079
        protected boolean check_order_and_offset = true;
1080

    
1081
        public SelectBuilderBase() {
1082
            this.columns = new ArrayList<>();
1083
            this.distinct = false;
1084
        }
1085
        @Override
1086
        public List<Value> getGroups() {
1087
            return this.groupColumn;
1088
        }
1089
        
1090
        @Override
1091
        public List<SelectColumnBuilder> getColumns() {
1092
            return Collections.unmodifiableList(this.columns);
1093
    }
1094
        
1095
        @Override
1096
        public void remove_column(String columnName) {
1097
            SelectColumnBuilder found = null;
1098
            for (SelectColumnBuilder column : columns) {
1099
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1100
                    found = column;
1101
                    break;
1102
                }
1103
                    
1104
            }
1105
            if(found!=null) {
1106
                columns.remove(found);
1107
            }
1108
        }
1109

    
1110
        @Override
1111
        public SelectBuilder group_by(Value... columns) {
1112
            if( this.groupColumn==null ) {
1113
                this.groupColumn = new ArrayList<>();
1114
            }
1115
            for (Value column : columns) {
1116
                this.groupColumn.add(column);
1117
            }
1118
            return this;
1119
        }
1120

    
1121
        @Override
1122
        public void accept(Visitor visitor, VisitorFilter filter) {
1123
            if (filter==null || filter.accept(this)) {
1124
                visitor.visit(this);
1125
            }
1126
            for (SelectColumnBuilder column : columns) {
1127
                column.accept(visitor, filter);
1128
            }
1129
            if (this.has_from()) {
1130
                this.from.accept(visitor, filter);
1131
            }
1132
            if (this.has_where()) {
1133
                this.where.accept(visitor, filter);
1134
            }
1135
            if (this.has_order_by()) {
1136
                for (OrderByBuilder order : order_by) {
1137
                    order.accept(visitor, filter);
1138
                }
1139
            }
1140
            if (this.has_group_by()) {
1141
                for (Value group : groupColumn) {
1142
                    group.accept(visitor, filter);
1143
                }
1144
            }
1145
        }
1146

    
1147
        @Override
1148
        public void replace(Value target, Value replacement) {
1149
            if( this.columns!=null ) {
1150
                for (int i = 0; i < columns.size(); i++) {
1151
                    SelectColumnBuilder column = columns.get(i);
1152
                    if( column == target ) {
1153
                        columns.set(i, (SelectColumnBuilder) replacement);
1154
                    } else {
1155
                        column.replace(target, replacement);
1156
                    }
1157
                }
1158
            }
1159
            if (this.has_from()) {
1160
                if( this.from == target ) {
1161
                    this.from = (FromBuilder) replacement;
1162
                } else {
1163
                    this.from.replace(target, replacement);
1164
                }
1165
            }
1166
            if (this.has_where()) {
1167
                if( this.where == target ) {
1168
                    this.where = (GeometryExpressionBuilder) replacement;
1169
                } else if( this.where.value() == target ) {
1170
                    this.where.value(replacement);
1171
                } else {
1172
                    this.where.value().replace(target, replacement);
1173
                }
1174
            }
1175
            if (this.has_order_by()) {
1176
                for (int i = 0; i < order_by.size(); i++) {
1177
                    OrderByBuilder order = order_by.get(i);
1178
                    if( order == target ) {
1179
                        order_by.set(i, (OrderByBuilder) replacement);
1180
                    } else {
1181
                        order.replace(target, replacement);
1182
                    }
1183
                }
1184
            }
1185
            if (this.has_group_by()) {
1186
                for (int i = 0; i < groupColumn.size(); i++) {
1187
                    Value group = groupColumn.get(i);
1188
                    if( group == target ) {
1189
                        groupColumn.set(i, replacement);
1190
                    } else {
1191
                        group.replace(target, replacement);
1192
                    }
1193
                }
1194
            }
1195
        }
1196

    
1197
        @Override
1198
        public SelectBuilder distinct() {
1199
            this.distinct = true;
1200
            return this;
1201
        }
1202

    
1203
        @Override
1204
        public SelectColumnBuilder column() {
1205
            SelectColumnBuilder builder = createSelectColumnBuilder();
1206
            this.columns.add(builder);
1207
            return builder;
1208
        }
1209

    
1210
        @Override
1211
        public SelectBuilder remove_all_columns() {
1212
            this.columns = new ArrayList<>();
1213
            return this;
1214
        }
1215
        
1216
        @Override
1217
        public boolean has_column(String name) {
1218
            for (SelectColumnBuilder column : columns) {
1219
                if (StringUtils.equals(name, column.getName())) {
1220
                    return true;
1221
                }
1222
                if (StringUtils.equals(name, column.getAlias())) {
1223
                    return true;
1224
                }
1225
            }
1226
            return false;
1227
        }
1228

    
1229
        @Override
1230
        public FromBuilder from() {
1231
            if (this.from == null) {
1232
                this.from = createFromBuilder();
1233
            }
1234
            return this.from;
1235
        }
1236

    
1237
        @Override
1238
        public boolean has_from() {
1239
            return this.from != null;
1240
        }
1241

    
1242
        @Override
1243
        public GeometryExpressionBuilder where() {
1244
            if (this.where == null) {
1245
                this.where = createExpressionBuilder();
1246
            }
1247
            return this.where;
1248
        }
1249

    
1250
        @Override
1251
        public boolean has_where() {
1252
            if (this.where == null) {
1253
                return false;
1254
            }
1255
            return this.where.value() != null;
1256
        }
1257

    
1258
        @Override
1259
        public SelectBuilder limit(long limit) {
1260
            this.limit = limit;
1261
            return this;
1262
        }
1263

    
1264
        @Override
1265
        public SelectBuilder limit(Long limit) {
1266
            if (limit == null) {
1267
                this.limit = -1;
1268
            } else {
1269
                this.limit = limit;
1270
            }
1271
            return this;
1272
        }
1273

    
1274
        @Override
1275
        public boolean has_limit() {
1276
            return this.limit >= 0;
1277
        }
1278

    
1279
        @Override
1280
        public SelectBuilder offset(long offset) {
1281
            this.offset = offset;
1282
            return this;
1283
        }
1284

    
1285
        @Override
1286
        public boolean has_offset() {
1287
            return this.offset > 0;
1288
        }
1289

    
1290
        @Override
1291
        public OrderByBuilder order_by() {
1292
            if (this.order_by == null) {
1293
                this.order_by = new ArrayList<>();
1294
            }
1295
            OrderByBuilder order = createOrderByBuilder();
1296
            this.order_by.add(order);
1297
            return order;
1298
        }
1299
        
1300
        @Override
1301
        public OrderByBuilder getOrderBy(Value column) {
1302
            if(this.order_by == null){
1303
                return null;
1304
            }
1305
            for (OrderByBuilder orderByBuilder : this.order_by) {
1306
                if(orderByBuilder.isColumn(column)){
1307
                    return orderByBuilder;
1308
                }
1309
            }
1310
            return null;
1311
        }
1312
        
1313
        @Override
1314
        public OrderByBuilder getOrderBy(String column) {
1315
            if(this.order_by == null){
1316
                return null;
1317
            }
1318
            for (OrderByBuilder orderByBuilder : this.order_by) {
1319
                if(orderByBuilder.isColumn(column)){
1320
                    return orderByBuilder;
1321
                }
1322
            }
1323
            return null;
1324
        }
1325

    
1326
        @Override
1327
        public boolean has_order_by() {
1328
            if (this.order_by == null) {
1329
                return false;
1330
            }
1331
            return !this.order_by.isEmpty();
1332
        }
1333
        
1334
        @Override
1335
        public boolean has_group_by() {
1336
            if (this.groupColumn == null) {
1337
                return false;
1338
            }
1339
            return !this.groupColumn.isEmpty();
1340
        }
1341
        
1342
        @Override
1343
        public boolean has_aggregate_functions() {
1344
            if (this.columns == null || this.columns.isEmpty() ) {
1345
                return false;
1346
            }
1347
            for (SelectColumnBuilder column : this.columns) {
1348
                if( column.isAggregateFunction() ) {
1349
                    return true;
1350
                }
1351
            }
1352
            return false;
1353
        }
1354
        
1355
        @Override
1356
        public void disable_check_order_and_offset() {
1357
          this.check_order_and_offset = false;
1358
        }
1359
        
1360
        protected boolean isValid(StringBuilder message) {
1361
            if (message == null) {
1362
                message = new StringBuilder();
1363
            }
1364
            if( this.check_order_and_offset ) {
1365
              if (this.has_offset() && !this.has_order_by()) {
1366
                  // Algunos gestores de BBDD requieren que se especifique un
1367
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1368
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1369
                  // siempre.
1370
                  message.append("Can't use OFFSET without an ORDER BY.");
1371
                  return false;
1372
              }
1373
            }
1374
            return true;
1375
        }
1376

    
1377
        @Override
1378
        public String toString() {
1379
            return this.toString(formatter());
1380
        }
1381

    
1382
        @Override
1383
        public String toString(Formatter<Value> formatter) {
1384
            if (formatter!=null && formatter.canApply(this)) {
1385
                return formatter.format(this);
1386
            }
1387
            StringBuilder builder = new StringBuilder();
1388
            if (!this.isValid(builder)) {
1389
                throw new IllegalStateException(builder.toString());
1390
            }
1391
            builder.append("SELECT ");
1392
            if (this.distinct) {
1393
                builder.append("DISTINCT ");
1394
            }
1395
            boolean first = true;
1396
            for (SelectColumnBuilder column : columns) {
1397
                if (first) {
1398
                    first = false;
1399
                } else {
1400
                    builder.append(", ");
1401
                }
1402
                builder.append(column.toString(formatter));
1403
            }
1404

    
1405
            if (this.has_from()) {
1406
                builder.append(" FROM ");
1407
                builder.append(this.from.toString(formatter));
1408
            }
1409
            if (this.has_where()) {
1410
                builder.append(" WHERE ");
1411
                builder.append(this.where.toString(formatter));
1412
            }
1413
            if( this.has_group_by() ) {
1414
                builder.append(" GROUP BY ");
1415
                builder.append(this.groupColumn.get(0).toString(formatter));
1416
                for (int i = 1; i < groupColumn.size(); i++) {
1417
                    builder.append(", ");
1418
                    builder.append(this.groupColumn.get(i).toString(formatter));
1419
                }
1420
            }
1421
            if (this.has_order_by()) {
1422
                builder.append(" ORDER BY ");
1423
                first = true;
1424
                for (OrderByBuilder item : this.order_by) {
1425
                    if (first) {
1426
                        first = false;
1427
                    } else {
1428
                        builder.append(", ");
1429
                    }
1430
                    builder.append(item.toString(formatter));
1431
                }
1432
            }
1433

    
1434
            if (this.has_limit()) {
1435
                builder.append(" LIMIT ");
1436
                builder.append(this.limit);
1437
            }
1438
            if (this.has_offset()) {
1439
                builder.append(" OFFSET ");
1440
                builder.append(this.offset);
1441
            }
1442
            return builder.toString();
1443

    
1444
        }
1445
    }
1446

    
1447
    public class DropTableBuilderBase
1448
            extends AbstractStatement
1449
            implements DropTableBuilder {
1450

    
1451
        protected TableNameBuilder table;
1452

    
1453
        @Override
1454
        public TableNameBuilder table() {
1455
            if (table == null) {
1456
                table = createTableNameBuilder();
1457
            }
1458
            return table;
1459
        }
1460

    
1461
        @Override
1462
        public void accept(Visitor visitor, VisitorFilter filter) {
1463
            if (filter==null || filter.accept(this)) {
1464
                visitor.visit(this);
1465
            }
1466
            this.table.accept(visitor, filter);
1467
        }
1468

    
1469
        @Override
1470
        public String toString() {
1471
            return this.toString(formatter());
1472
        }
1473

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

    
1495
        @Override
1496
        public List<String> toStrings() {
1497
            return this.toStrings(formatter());
1498
        }
1499

    
1500
        @Override
1501
        public List<String> toStrings(Formatter formatter) {
1502
            List<String> sqls = new ArrayList<>();
1503

    
1504
            sqls.add(
1505
                    MessageFormat.format(
1506
                            STMT_DROP_TABLE_table,
1507
                            this.table.toString(formatter)
1508
                    )
1509
            );
1510
            String sql;
1511
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1512
                if (this.table.has_schema()) {
1513
                    sql = MessageFormat.format(
1514
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1515
                            as_string(this.table.getSchema()),
1516
                            as_string(this.table.getName())
1517
                    );
1518
                } else {
1519
                    sql = MessageFormat.format(
1520
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1521
                            as_identifier(this.table.getName())
1522
                    );
1523
                }
1524
                if (!StringUtils.isEmpty(sql)) {
1525
                    sqls.add(sql);
1526
                }
1527
            }
1528
            return sqls;
1529
        }
1530
    }
1531

    
1532
    public class GrantRoleBuilderBase
1533
            extends AbstractStatementPart
1534
            implements GrantRoleBuilder {
1535

    
1536
        protected TableNameBuilder table;
1537
        protected String role;
1538
        protected Set<Privilege> privileges;
1539

    
1540
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1541
            this.table = table;
1542
            this.role = role;
1543
            this.privileges = new HashSet<>();
1544
        }
1545
        
1546
        @Override
1547
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1548
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1549
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1550
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1551
            
1552
            return other;
1553
        }
1554

    
1555
        @Override
1556
        public GrantRoleBuilder privilege(Privilege privilege) {
1557
            privileges.add(privilege);
1558
            return this;
1559
        }
1560

    
1561
        @Override
1562
        public GrantRoleBuilder select() {
1563
            privileges.add(Privilege.SELECT);
1564
            return this;
1565
        }
1566

    
1567
        @Override
1568
        public GrantRoleBuilder update() {
1569
            privileges.add(Privilege.UPDATE);
1570
            return this;
1571
        }
1572

    
1573
        @Override
1574
        public GrantRoleBuilder insert() {
1575
            privileges.add(Privilege.INSERT);
1576
            return this;
1577
        }
1578

    
1579
        @Override
1580
        public GrantRoleBuilder delete() {
1581
            privileges.add(Privilege.DELETE);
1582
            return this;
1583
        }
1584

    
1585
        @Override
1586
        public GrantRoleBuilder truncate() {
1587
            privileges.add(Privilege.TRUNCATE);
1588
            return this;
1589
        }
1590

    
1591
        @Override
1592
        public GrantRoleBuilder reference() {
1593
            privileges.add(Privilege.REFERENCE);
1594
            return this;
1595
        }
1596

    
1597
        @Override
1598
        public GrantRoleBuilder trigger() {
1599
            privileges.add(Privilege.TRIGGER);
1600
            return this;
1601
        }
1602

    
1603
        @Override
1604
        public GrantRoleBuilder all() {
1605
            privileges.add(Privilege.ALL);
1606
            return this;
1607
        }
1608

    
1609
        protected String getPrivilegeName(Privilege privilege) {
1610
            switch (privilege) {
1611
                case DELETE:
1612
                    return "DELETE";
1613
                case INSERT:
1614
                    return "INSERT";
1615
                case REFERENCE:
1616
                    return "REFERENCE";
1617
                case SELECT:
1618
                    return "SELECT";
1619
                case TRIGGER:
1620
                    return "TRIGGER";
1621
                case TRUNCATE:
1622
                    return "TRUNCATE";
1623
                case UPDATE:
1624
                    return "UPDATE";
1625
                case ALL:
1626
                default:
1627
                    return "ALL";
1628
            }
1629
        }
1630

    
1631
        @Override
1632
        public String toString() {
1633
            return this.toString(formatter());
1634
        }
1635

    
1636
        @Override
1637
        public String toString(Formatter<Value> formatter) {
1638
            if (formatter!=null && formatter.canApply(this)) {
1639
                return formatter.format(this);
1640
            }
1641
            StringBuilder builder = new StringBuilder();
1642
            boolean first = true;
1643
            for (Privilege privilege : privileges) {
1644
                if (first) {
1645
                    first = false;
1646
                } else {
1647
                    builder.append(", ");
1648
                }
1649
                builder.append(this.getPrivilegeName(privilege));
1650
            }
1651
            String sql = MessageFormat.format(
1652
                    STMT_GRANT_privileges_ON_table_TO_role,
1653
                    builder.toString(),
1654
                    table.toString(formatter),
1655
                    role
1656
            );
1657
            return sql;
1658
        }
1659
    }
1660

    
1661
    public class GrantBuilderBase
1662
            extends AbstractStatement
1663
            implements GrantBuilder {
1664

    
1665
        protected TableNameBuilder table;
1666
        protected Map<String, GrantRoleBuilder> roles;
1667

    
1668
        public GrantBuilderBase() {
1669
            this.roles = new HashMap<>();
1670
        }
1671

    
1672
        @Override
1673
        public TableNameBuilder table() {
1674
            if (table == null) {
1675
                table = createTableNameBuilder();
1676
            }
1677
            return table;
1678
        }
1679

    
1680
        @Override
1681
        public void accept(Visitor visitor, VisitorFilter filter) {
1682
            if (filter==null || filter.accept(this)) {
1683
                visitor.visit(this);
1684
            }
1685
            if (this.table != null) {
1686
                this.table.accept(visitor, filter);
1687
            }
1688
        }
1689

    
1690
        @Override
1691
        public GrantRoleBuilder role(String role) {
1692
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1693
            if (roleBuilder == null) {
1694
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1695
                this.roles.put(role, roleBuilder);
1696
            }
1697
            return roleBuilder;
1698
        }
1699

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

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

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

    
1731
        @Override
1732
        public List<String> toStrings(Formatter formatter) {
1733
            List<String> sqls = new ArrayList<>();
1734
            for (GrantRoleBuilder role : roles.values()) {
1735
                sqls.add(role.toString(formatter));
1736
            }
1737
            return sqls;
1738
        }
1739
    }
1740

    
1741
    public class UpdateColumnBuilderBase
1742
            extends InsertColumnBuilderBase
1743
            implements UpdateColumnBuilder {
1744

    
1745
        public UpdateColumnBuilderBase() {
1746
            super();
1747
        }
1748

    
1749
        @Override
1750
        public UpdateColumnBuilder name(String name) {
1751
            return (UpdateColumnBuilder) super.name(name);
1752
        }
1753

    
1754
        @Override
1755
        public UpdateColumnBuilder with_value(Value value) {
1756
            return (UpdateColumnBuilder) super.with_value(value);
1757
        }
1758

    
1759
    }
1760

    
1761
    public class UpdateBuilderBase
1762
            extends AbstractStatement
1763
            implements UpdateBuilder {
1764

    
1765
        protected GeometryExpressionBuilder where;
1766
        protected List<UpdateColumnBuilder> columns;
1767
        protected TableNameBuilder table;
1768

    
1769
        public UpdateBuilderBase() {
1770
            this.columns = new ArrayList<>();
1771
        }
1772

    
1773
        @Override
1774
        public void accept(Visitor visitor, VisitorFilter filter) {
1775
            if (filter==null || filter.accept(this)) {
1776
                visitor.visit(this);
1777
            }
1778
            if (this.table != null) {
1779
                this.table.accept(visitor, filter);
1780
            }
1781
            for (UpdateColumnBuilder column : columns) {
1782
                column.accept(visitor, filter);
1783
            }
1784
            if (this.has_where()) {
1785
                this.where.accept(visitor, filter);
1786
            }
1787
        }
1788

    
1789
        @Override
1790
        public GeometryExpressionBuilder where() {
1791
            if (this.where == null) {
1792
                this.where = createExpressionBuilder();
1793
            }
1794
            return this.where;
1795
        }
1796

    
1797
        @Override
1798
        public TableNameBuilder table() {
1799
            if (table == null) {
1800
                table = createTableNameBuilder();
1801
            }
1802
            return table;
1803
        }
1804

    
1805
        @Override
1806
        public UpdateColumnBuilder column() {
1807
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1808
            this.columns.add(column);
1809
            return column;
1810
        }
1811

    
1812
        @Override
1813
        public boolean has_where() {
1814
            return this.where != null;
1815
        }
1816

    
1817
        @Override
1818
        public String toString() {
1819
            return this.toString(formatter());
1820
        }
1821

    
1822
        @Override
1823
        public String toString(Formatter<Value> formatter) {
1824
            if (formatter!=null && formatter.canApply(this)) {
1825
                return formatter.format(this);
1826
            }
1827
            /*
1828
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1829
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1830
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1831
             * output_expression [ AS output_name ] [, ...] ]
1832
             */
1833
            StringBuilder columnsAndValues = new StringBuilder();
1834

    
1835
            boolean first = true;
1836
            for (UpdateColumnBuilder column : columns) {
1837
                if (first) {
1838
                    first = false;
1839
                } else {
1840
                    columnsAndValues.append(", ");
1841
                }
1842
                columnsAndValues.append(as_identifier(column.getName()));
1843
                columnsAndValues.append(" = ");
1844
                columnsAndValues.append(column.getValue().toString(formatter));
1845
            }
1846

    
1847
            String sql;
1848
            if (this.has_where()) {
1849
                sql = MessageFormat.format(
1850
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1851
                        this.table.toString(formatter),
1852
                        columnsAndValues.toString(),
1853
                        this.where.toString(formatter)
1854
                );
1855
            } else {
1856
                sql = MessageFormat.format(
1857
                        STMT_UPDATE_table_SET_columnsAndValues,
1858
                        this.table.toString(formatter),
1859
                        columnsAndValues.toString()
1860
                );
1861
            }
1862
            return sql;
1863
        }
1864
    }
1865

    
1866
    public class DeleteBuilderBase
1867
            extends AbstractStatement
1868
            implements DeleteBuilder {
1869

    
1870
        protected GeometryExpressionBuilder where;
1871
        protected TableNameBuilder table;
1872

    
1873
        public DeleteBuilderBase() {
1874
        }
1875

    
1876
        @Override
1877
        public void accept(Visitor visitor, VisitorFilter filter) {
1878
            if (filter==null || filter.accept(this)) {
1879
                visitor.visit(this);
1880
            }
1881
            if (this.table != null) {
1882
                this.table.accept(visitor, filter);
1883
            }
1884
            if (this.has_where()) {
1885
                this.where.accept(visitor, filter);
1886
            }
1887
        }
1888

    
1889
        @Override
1890
        public GeometryExpressionBuilder where() {
1891
            if (this.where == null) {
1892
                this.where = createExpressionBuilder();
1893
            }
1894
            return this.where;
1895
        }
1896

    
1897
        @Override
1898
        public TableNameBuilder table() {
1899
            if (table == null) {
1900
                table = createTableNameBuilder();
1901
            }
1902
            return table;
1903
        }
1904

    
1905
        @Override
1906
        public boolean has_where() {
1907
            return this.where != null;
1908
        }
1909

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

    
1915
        @Override
1916
        public String toString(Formatter<Value> formatter) {
1917
            if (formatter!=null && formatter.canApply(this)) {
1918
                return formatter.format(this);
1919
            }
1920
            /*
1921
             * DELETE FROM table_name
1922
             * WHERE some_column=some_value; 
1923
             */
1924
            String sql;
1925
            if (this.has_where()) {
1926
                sql = MessageFormat.format(
1927
                        STMT_DELETE_FROM_table_WHERE_expresion,
1928
                        this.table.toString(formatter),
1929
                        this.where.toString(formatter)
1930
                );
1931
            } else {
1932
                sql = MessageFormat.format(
1933
                        STMT_DELETE_FROM_table,
1934
                        this.table.toString(formatter)
1935
                );
1936
            }
1937
            return sql;
1938
        }
1939
    }
1940

    
1941
    public class CreateIndexBuilderBase
1942
            extends AbstractStatement
1943
            implements CreateIndexBuilder {
1944

    
1945
        protected boolean ifNotExist = false;
1946
        protected boolean isUnique = false;
1947
        protected String indexName;
1948
        protected boolean isSpatial = false;
1949
        protected TableNameBuilder table;
1950
        protected final List<String> columns;
1951

    
1952
        public CreateIndexBuilderBase() {
1953
            this.columns = new ArrayList<>();
1954
        }
1955

    
1956
        @Override
1957
        public CreateIndexBuilder unique() {
1958
            this.isUnique = true;
1959
            return this;
1960
        }
1961

    
1962
        @Override
1963
        public CreateIndexBuilder if_not_exist() {
1964
            this.ifNotExist = true;
1965
            return this;
1966
        }
1967

    
1968
        @Override
1969
        public CreateIndexBuilder name(String name) {
1970
            this.indexName = name;
1971
            return this;
1972
        }
1973

    
1974
        @Override
1975
        public CreateIndexBuilder name(String tableName, String columnName) {
1976
            this.indexName = tableName + "_IDX_" + columnName;
1977
            return this;
1978
        }
1979

    
1980
        @Override
1981
        public CreateIndexBuilder spatial() {
1982
            this.isSpatial = true;
1983
            return this;
1984
        }
1985

    
1986
        @Override
1987
        public CreateIndexBuilder column(String name) {
1988
            this.columns.add(name);
1989
            return this;
1990
        }
1991

    
1992
        @Override
1993
        public TableNameBuilder table() {
1994
            if (table == null) {
1995
                table = createTableNameBuilder();
1996
            }
1997
            return table;
1998
        }
1999

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

    
2010
        @Override
2011
        public String toString() {
2012
            return this.toString(formatter());
2013
        }
2014

    
2015
        @Override
2016
        public String toString(Formatter<Value> formatter) {
2017
            if (formatter!=null && formatter.canApply(this)) {
2018
                return formatter.format(this);
2019
            }
2020
            StringBuilder builder = new StringBuilder();
2021
            boolean first = true;
2022
            for (String sql : toStrings(formatter)) {
2023
                if (StringUtils.isEmpty(sql)) {
2024
                    continue;
2025
                }
2026
                if (first) {
2027
                    first = false;
2028
                } else {
2029
                    builder.append("; ");
2030
                }
2031
                builder.append(sql);
2032
            }
2033
            return builder.toString();
2034
        }
2035

    
2036
        @Override
2037
        public List<String> toStrings() {
2038
            return this.toStrings(formatter());
2039
        }
2040

    
2041
        @Override
2042
        public List<String> toStrings(Formatter formatter) {
2043
            StringBuilder builder = new StringBuilder();
2044
            builder.append("CREATE ");
2045
            if (this.isUnique) {
2046
                builder.append("UNIQUE ");
2047
            }
2048
            builder.append("INDEX ");
2049
            if (this.ifNotExist) {
2050
                builder.append("IF NOT EXISTS ");
2051
            }
2052
            builder.append(as_identifier(this.indexName));
2053
            builder.append(" ON ");
2054
            builder.append(this.table.toString(formatter));
2055
            if (this.isSpatial) {
2056
                builder.append(" USING GIST ");
2057
            }
2058
            builder.append(" ( ");
2059
            boolean is_first_column = true;
2060
            for (String column : this.columns) {
2061
                if (is_first_column) {
2062
                    is_first_column = false;
2063
                } else {
2064
                    builder.append(", ");
2065
                }
2066
                builder.append(column);
2067
            }
2068
            builder.append(" )");
2069

    
2070
            List<String> sqls = new ArrayList<>();
2071
            sqls.add(builder.toString());
2072
            return sqls;
2073
        }
2074

    
2075
    }
2076

    
2077
    public class DropIndexBuilderBase
2078
            extends AbstractStatement
2079
            implements DropIndexBuilder {
2080

    
2081
        protected boolean ifNotExist = false;
2082
        protected String indexName;
2083

    
2084
        public DropIndexBuilderBase() {
2085
        }
2086

    
2087
        @Override
2088
        public DropIndexBuilder if_not_exist() {
2089
            this.ifNotExist = true;
2090
            return this;
2091
        }
2092

    
2093
        @Override
2094
        public DropIndexBuilder name(String name) {
2095
            this.indexName = name;
2096
            return this;
2097
        }
2098

    
2099
        @Override
2100
        public DropIndexBuilder name(String tableName, String columnName) {
2101
            this.indexName = tableName + "_IDX_" + columnName;
2102
            return this;
2103
        }
2104

    
2105
        @Override
2106
        public String toString() {
2107
            return this.toString(formatter());
2108
        }
2109

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

    
2131
        @Override
2132
        public List<String> toStrings() {
2133
            return this.toStrings(formatter());
2134
        }
2135

    
2136
        @Override
2137
        public List<String> toStrings(Formatter formatter) {
2138
            StringBuilder builder = new StringBuilder();
2139
            builder.append("DROP INDEX ");
2140
            if (this.ifNotExist) {
2141
                builder.append("IF NOT EXISTS ");
2142
            }
2143
            builder.append(as_identifier(this.indexName));
2144
            List<String> sqls = new ArrayList<>();
2145
            sqls.add(builder.toString());
2146
            return sqls;
2147
        }
2148

    
2149
    }
2150

    
2151
    public class AlterTableBuilderBase
2152
            extends AbstractStatement
2153
            implements AlterTableBuilder {
2154

    
2155
        protected TableNameBuilder table;
2156
        protected List<String> drops;
2157
        protected List<ColumnDescriptor> adds;
2158
        protected List<ColumnDescriptor> alters;
2159
        protected List<Pair<String, String>> renames;
2160
        protected String drop_primary_key_column;
2161

    
2162
        public AlterTableBuilderBase() {
2163
            this.drops = new ArrayList<>();
2164
            this.adds = new ArrayList<>();
2165
            this.alters = new ArrayList<>();
2166
            this.renames = new ArrayList<>();
2167
        }
2168

    
2169
        @Override
2170
        public boolean isEmpty() {
2171
            return this.drops.isEmpty()
2172
                    && this.adds.isEmpty()
2173
                    && this.alters.isEmpty()
2174
                    && this.renames.isEmpty();
2175
        }
2176

    
2177
        @Override
2178
        public void accept(Visitor visitor, VisitorFilter filter) {
2179
            if (filter==null || filter.accept(this)) {
2180
                visitor.visit(this);
2181
            }
2182
            if (this.table != null) {
2183
                this.table.accept(visitor, filter);
2184
            }
2185
        }
2186

    
2187
        @Override
2188
        public TableNameBuilder table() {
2189
            if (table == null) {
2190
                table = createTableNameBuilder();
2191
            }
2192
            return table;
2193
        }
2194

    
2195
        @Override
2196
        public AlterTableBuilder drop_column(String columnName) {
2197
            this.drops.add(columnName);
2198
            return this;
2199
        }
2200

    
2201
        @Override
2202
        public AlterTableBuilder drop_primary_key(String columnName) {
2203
            this.drop_primary_key_column = columnName;
2204
            return this;
2205
        }
2206

    
2207
        @Override
2208
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2209
            this.adds.add(new ColumnDescriptorBase(fad));
2210
            return this;
2211
        }
2212

    
2213
        @Override
2214
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2215
            if (isPk || isAutomatic) {
2216
                allowNulls = false;
2217
            }
2218
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2219
            return this;
2220
        }
2221

    
2222
        @Override
2223
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2224
            if (StringUtils.isEmpty(columnName)) {
2225
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2226
            }
2227
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2228
            return this;
2229
        }
2230

    
2231
        @Override
2232
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2233
            if (StringUtils.isEmpty(columnName)) {
2234
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2235
            }
2236
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2237
            return this;
2238
        }
2239

    
2240
        @Override
2241
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2242
            this.alters.add(new ColumnDescriptorBase(fad));
2243
            return this;
2244
        }
2245

    
2246
        @Override
2247
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2248
            if (isPk || isAutomatic) {
2249
                allowNulls = false;
2250
            }
2251
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2252
            return this;
2253
        }
2254

    
2255
        @Override
2256
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2257
            if (StringUtils.isEmpty(columnName)) {
2258
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2259
            }
2260
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2261
            return this;
2262
        }
2263

    
2264
        @Override
2265
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2266
            if (StringUtils.isEmpty(columnName)) {
2267
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2268
            }
2269
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2270
            return this;
2271
        }
2272

    
2273
        @Override
2274
        public AlterTableBuilder rename_column(String source, String target) {
2275
            this.renames.add(new ImmutablePair(source, target));
2276
            return this;
2277
        }
2278

    
2279
        protected String getConstrainName(String constrainType, String columnName) {
2280
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2281
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2282
            return constraint_name;
2283
        }
2284

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

    
2290
        @Override
2291
        public String toString(Formatter<Value> formatter) {
2292
            if (formatter!=null && formatter.canApply(this)) {
2293
                return formatter.format(this);
2294
            }
2295
            StringBuilder builder = new StringBuilder();
2296
            boolean first = true;
2297
            for (String sql : toStrings(formatter)) {
2298
                if (StringUtils.isEmpty(sql)) {
2299
                    continue;
2300
                }
2301
                if (first) {
2302
                    first = false;
2303
                } else {
2304
                    builder.append("; ");
2305
                }
2306
                builder.append(sql);
2307
            }
2308
            return builder.toString();
2309
        }
2310

    
2311
        @Override
2312
        public List<String> toStrings() {
2313
            return this.toStrings(formatter());
2314
        }
2315

    
2316
        @Override
2317
        public List<String> toStrings(Formatter formatter) {
2318
            List<String> sqls = new ArrayList<>();
2319
            if (this.isEmpty()) {
2320
                return sqls;
2321
            }
2322
            for (String column : drops) {
2323
                StringBuilder builder = new StringBuilder();
2324
                builder.append("ALTER TABLE ");
2325
                builder.append(this.table.toString(formatter));
2326
                builder.append(" DROP COLUMN IF EXISTS ");
2327
                builder.append(as_identifier(column));
2328
                sqls.add(builder.toString());
2329
            }
2330
            for (ColumnDescriptor column : adds) {
2331
                StringBuilder builder = new StringBuilder();
2332
                builder.append("ALTER TABLE ");
2333
                builder.append(this.table.toString(formatter));
2334
                builder.append(" ADD COLUMN ");
2335
                builder.append(as_identifier(column.getName()));
2336
                builder.append(" ");
2337
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2338
                    builder.append(" SERIAL");
2339
                } else {
2340
                    builder.append(
2341
                            sqltype(
2342
                                    column.getType(),
2343
                                    column.getSize(),
2344
                                    column.getPrecision(),
2345
                                    column.getScale(),
2346
                                    column.getGeometryType(),
2347
                                    column.getGeometrySubtype()
2348
                            )
2349
                    );
2350
                }
2351
                if (column.getDefaultValue() == null) {
2352
                    if (column.allowNulls()) {
2353
                        builder.append(" DEFAULT NULL");
2354
                    }
2355
                } else {
2356
                    builder.append(" DEFAULT '");
2357
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2358
                    builder.append("'");
2359
                }
2360
                if (column.allowNulls()) {
2361
                    builder.append(" NULL");
2362
                } else {
2363
                    builder.append(" NOT NULL");
2364
                }
2365
                if (column.isPrimaryKey()) {
2366
                    builder.append(" PRIMARY KEY");
2367
                }
2368
                sqls.add(builder.toString());
2369
            }
2370
            for (ColumnDescriptor column : alters) {
2371
                StringBuilder builder = new StringBuilder();
2372
                builder.append("ALTER TABLE ");
2373
                builder.append(this.table.toString(formatter));
2374
                builder.append(" ALTER COLUMN ");
2375
                builder.append(as_identifier(column.getName()));
2376
                builder.append(" SET DATA TYPE ");
2377
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2378
                    builder.append(" SERIAL");
2379
                } else {
2380
                    builder.append(
2381
                            sqltype(
2382
                                    column.getType(),
2383
                                    column.getSize(),
2384
                                    column.getPrecision(),
2385
                                    column.getScale(),
2386
                                    column.getGeometryType(),
2387
                                    column.getGeometrySubtype()
2388
                            )
2389
                    );
2390
                }
2391
                if (column.getDefaultValue() == null) {
2392
                    if (column.allowNulls()) {
2393
                        builder.append(" DEFAULT NULL");
2394
                    } else {
2395
                        builder.append(" DROP DEFAULT");
2396
                    }
2397
                } else {
2398
                    builder.append(" DEFAULT '");
2399
                    builder.append(column.getDefaultValue().toString());
2400
                    builder.append("'");
2401
                }
2402
                sqls.add(builder.toString());
2403
            }
2404
            for (Pair<String, String> pair : renames) {
2405
                StringBuilder builder = new StringBuilder();
2406
                builder.append("ALTER TABLE ");
2407
                builder.append(this.table.toString(formatter));
2408
                builder.append(" RENAME COLUMN ");
2409
                builder.append(as_identifier(pair.getLeft()));
2410
                builder.append(" TO ");
2411
                builder.append(as_identifier(pair.getRight()));
2412
                sqls.add(builder.toString());
2413
            }
2414
            return sqls;
2415
        }
2416

    
2417
    }
2418

    
2419
    public class CreateTableBuilderBase
2420
            extends AbstractStatement
2421
            implements CreateTableBuilder {
2422

    
2423
        protected TableNameBuilder table;
2424
        protected List<ColumnDescriptor> columns;
2425

    
2426
        public CreateTableBuilderBase() {
2427
            this.columns = new ArrayList<>();
2428
        }
2429

    
2430
        @Override
2431
        public void accept(Visitor visitor, VisitorFilter filter) {
2432
            if (filter==null || filter.accept(this)) {
2433
                visitor.visit(this);
2434
            }
2435
            if (this.table != null) {
2436
                this.table.accept(visitor, filter);
2437
            }
2438
        }
2439

    
2440
        @Override
2441
        public TableNameBuilder table() {
2442
            if (table == null) {
2443
                table = createTableNameBuilder();
2444
            }
2445
            return table;
2446
        }
2447

    
2448
        @Override
2449
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2450
            this.columns.add(new ColumnDescriptorBase(fad));
2451
            return this;
2452
        }
2453

    
2454
        @Override
2455
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2456
            if (StringUtils.isEmpty(columnName)) {
2457
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2458
            }
2459
            if (isPk || isAutomatic) {
2460
                allowNulls = false;
2461
            }
2462
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2463
            return this;
2464
        }
2465

    
2466
        @Override
2467
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2468
            if (StringUtils.isEmpty(columnName)) {
2469
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2470
            }
2471
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2472
            return this;
2473
        }
2474

    
2475
        @Override
2476
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2477
            if (StringUtils.isEmpty(columnName)) {
2478
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2479
            }
2480
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2481
            return this;
2482
        }
2483

    
2484
        @Override
2485
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2486
            if (StringUtils.isEmpty(columnName)) {
2487
                return null;
2488
            }
2489
            for (ColumnDescriptor column : columns) {
2490
                if (columnName.equals(column.getName())) {
2491
                    return column;
2492
                }
2493
            }
2494
            return null;
2495
        }
2496

    
2497
        @Override
2498
        public String toString() {
2499
            return this.toString(formatter());
2500
        }
2501

    
2502
        @Override
2503
        public String toString(Formatter<Value> formatter) {
2504
            if (formatter!=null && formatter.canApply(this)) {
2505
                return formatter.format(this);
2506
            }
2507
            StringBuilder builder = new StringBuilder();
2508
            boolean first = true;
2509
            for (String sql : toStrings(formatter)) {
2510
                if (StringUtils.isEmpty(sql)) {
2511
                    continue;
2512
                }
2513
                if (first) {
2514
                    first = false;
2515
                } else {
2516
                    builder.append("; ");
2517
                }
2518
                builder.append(sql);
2519
            }
2520
            return builder.toString();
2521
        }
2522

    
2523
        @Override
2524
        public List<String> toStrings() {
2525
            return this.toStrings(formatter());
2526
        }
2527

    
2528
        @Override
2529
        /*
2530
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
2531
        */
2532
        public List<String> toStrings(Formatter formatter) {
2533
            List<String> sqls = new ArrayList<>();
2534
            /**
2535
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2536
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2537
             * column_constraint [ ... ] ] | table_constraint | LIKE
2538
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2539
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2540
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2541
             *
2542
             * where column_constraint is:
2543
             *
2544
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2545
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2546
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2547
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2548
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2549
             *
2550
             * and table_constraint is:
2551
             *
2552
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2553
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2554
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2555
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2556
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2557
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2558
             */
2559
            
2560
            StringBuilder builder = new StringBuilder();
2561

    
2562
            builder.append("CREATE TABLE ");
2563
            builder.append(this.table.toString(formatter));
2564
            builder.append(" (");
2565
            boolean first = true;
2566
            for (ColumnDescriptor column : columns) {
2567
                if (first) {
2568
                    first = false;
2569
                } else {
2570
                    builder.append(", ");
2571
                }
2572
                builder.append(as_identifier(column.getName()));
2573
                builder.append(" ");
2574
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2575
                    builder.append("SERIAL");
2576
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2577
                    builder.append("BIGSERIAL");
2578
                } else {
2579
                    builder.append(sqltype(
2580
                            column.getType(),
2581
                            column.getSize(),
2582
                            column.getPrecision(),
2583
                            column.getScale(),
2584
                            column.getGeometryType(),
2585
                            column.getGeometrySubtype()
2586
                    )
2587
                    );
2588
                }
2589
                if (column.getDefaultValue() == null) {
2590
                    if (column.allowNulls()) {
2591
                        builder.append(" DEFAULT NULL");
2592
                    }
2593
                } else {
2594
                    builder.append(" DEFAULT '");
2595
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2596
                    builder.append("'");
2597
                }
2598
                if (column.allowNulls()) {
2599
                    builder.append(" NULL");
2600
                } else {
2601
                    builder.append(" NOT NULL");
2602
                }
2603
                if (column.isPrimaryKey()) {
2604
                    builder.append(" PRIMARY KEY");
2605
                }
2606
            }
2607
            builder.append(" )");
2608
            sqls.add(builder.toString());
2609
            return sqls;
2610
        }
2611
    }
2612

    
2613
    public class InsertColumnBuilderBase
2614
            extends AbstractStatement
2615
            implements InsertColumnBuilder {
2616

    
2617
        protected Variable name;
2618
        protected Value value;
2619

    
2620
        public InsertColumnBuilderBase() {
2621
        }
2622

    
2623
        @Override
2624
        public void accept(Visitor visitor, VisitorFilter filter) {
2625
            if (filter==null || filter.accept(this)) {
2626
                visitor.visit(this);
2627
            }
2628
            if (this.name != null) {
2629
                this.name.accept(visitor, filter);
2630
            }
2631
            if (this.value != null) {
2632
                this.value.accept(visitor, filter);
2633
            }
2634
        }
2635

    
2636
        @Override
2637
        public InsertColumnBuilder name(String name) {
2638
            this.name = expression().variable(name);
2639
            return this;
2640
        }
2641

    
2642
        @Override
2643
        public InsertColumnBuilder with_value(Value value) {
2644
            this.value = value;
2645
            return this;
2646
        }
2647

    
2648
        @Override
2649
        public String getName() {
2650
            return this.name.name();
2651
        }
2652

    
2653
        @Override
2654
        public Value getValue() {
2655
            return this.value;
2656
        }
2657

    
2658
        @Override
2659
        public String toString() {
2660
            return this.toString(formatter());
2661
        }
2662

    
2663
        @Override
2664
        public String toString(Formatter<Value> formatter) {
2665
            if (formatter!=null && formatter.canApply(this)) {
2666
                return formatter.format(this);
2667
            }
2668
            return this.value.toString(formatter);
2669
        }
2670
    }
2671

    
2672
    public class InsertBuilderBase
2673
            extends AbstractStatement
2674
            implements InsertBuilder {
2675

    
2676
        protected List<InsertColumnBuilder> columns;
2677
        protected TableNameBuilder table;
2678

    
2679
        public InsertBuilderBase() {
2680
            this.columns = new ArrayList<>();
2681
        }
2682

    
2683
        @Override
2684
        public void accept(Visitor visitor, VisitorFilter filter) {
2685
            if (filter==null || filter.accept(this)) {
2686
                visitor.visit(this);
2687
            }
2688
            if (this.table != null) {
2689
                this.table.accept(visitor, filter);
2690
            }
2691
            for (InsertColumnBuilder column : columns) {
2692
                column.accept(visitor, filter);
2693
            }
2694
        }
2695

    
2696
        @Override
2697
        public TableNameBuilder table() {
2698
            if (table == null) {
2699
                table = createTableNameBuilder();
2700
            }
2701
            return table;
2702
        }
2703

    
2704
        @Override
2705
        public InsertColumnBuilder column() {
2706
            InsertColumnBuilder column = createInsertColumnBuilder();
2707
            this.columns.add(column);
2708
            return column;
2709
        }
2710

    
2711
        @Override
2712
        public String toString() {
2713
            return this.toString(formatter());
2714
        }
2715

    
2716
        @Override
2717
        public String toString(Formatter<Value> formatter) {
2718
            if (formatter!=null && formatter.canApply(this)) {
2719
                return formatter.format(this);
2720
            }
2721
            /*
2722
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2723
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2724
             * output_expression [ AS output_name ] [, ...] ]
2725
             */
2726
            StringBuilder builderColumns = new StringBuilder();
2727
            StringBuilder builderValues = new StringBuilder();
2728

    
2729
            boolean first = true;
2730
            for (InsertColumnBuilder column : columns) {
2731
                if (first) {
2732
                    first = false;
2733
                } else {
2734
                    builderColumns.append(", ");
2735
                }
2736
                builderColumns.append(as_identifier(column.getName()));
2737
            }
2738
            first = true;
2739
            for (InsertColumnBuilder column : columns) {
2740
                if (first) {
2741
                    first = false;
2742
                } else {
2743
                    builderValues.append(", ");
2744
                }
2745
                builderValues.append(column.toString(formatter));
2746
            }
2747

    
2748
            String sql = MessageFormat.format(
2749
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2750
                    this.table.toString(formatter),
2751
                    builderColumns.toString(),
2752
                    builderValues.toString()
2753
            );
2754
            return sql;
2755

    
2756
        }
2757
    }
2758

    
2759
    public class UpdateTableStatisticsBuilderBase
2760
            extends AbstractStatement
2761
            implements UpdateTableStatisticsBuilder {
2762

    
2763
        protected TableNameBuilder table;
2764

    
2765
        @Override
2766
        public void accept(Visitor visitor, VisitorFilter filter) {
2767
            if (filter==null || filter.accept(this)) {
2768
                visitor.visit(this);
2769
            }
2770
            if (this.table != null) {
2771
                this.table.accept(visitor, filter);
2772
            }
2773
        }
2774

    
2775
        @Override
2776
        public TableNameBuilder table() {
2777
            if (table == null) {
2778
                table = createTableNameBuilder();
2779
            }
2780
            return table;
2781
        }
2782

    
2783
        @Override
2784
        public String toString() {
2785
            return this.toString(formatter());
2786
        }
2787

    
2788
        @Override
2789
        public String toString(Formatter<Value> formatter) {
2790
            if (formatter!=null && formatter.canApply(this)) {
2791
                return formatter.format(this);
2792
            }
2793
            StringBuilder builder = new StringBuilder();
2794
            boolean first = true;
2795
            for (String sql : toStrings(formatter)) {
2796
                if (StringUtils.isEmpty(sql)) {
2797
                    continue;
2798
                }
2799
                if (first) {
2800
                    first = false;
2801
                } else {
2802
                    builder.append("; ");
2803
                }
2804
                builder.append(sql);
2805
            }
2806
            return builder.toString();
2807
        }
2808

    
2809
        @Override
2810
        public List<String> toStrings() {
2811
            return this.toStrings(formatter());
2812
        }
2813

    
2814
        @Override
2815
        public List<String> toStrings(Formatter formatter) {
2816
            List<String> sqls = new ArrayList<>();
2817

    
2818
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2819
                String sql = MessageFormat.format(
2820
                        STMT_UPDATE_TABLE_STATISTICS_table,
2821
                        table.toString(formatter)
2822
                );
2823
                if (!StringUtils.isEmpty(sql)) {
2824
                    sqls.add(sql);
2825
                }
2826
            }
2827
            return sqls;
2828
        }
2829
    }
2830

    
2831
    protected GeometryExpressionBuilder expressionBuilder;
2832

    
2833
    protected String defaultSchema;
2834
    protected boolean supportSchemas;
2835
    protected boolean hasSpatialFunctions;
2836
    protected GeometrySupportType geometrySupportType;
2837
    protected boolean allowAutomaticValues;
2838

    
2839
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2840

    
2841
    protected String constant_true = "(1=1)";
2842
    protected String constant_false = "(1<>1)";
2843

    
2844
    protected String type_boolean = "BOOLEAN";
2845
    protected String type_byte = "TINYINT";
2846
    protected String type_bytearray = "BYTEA";
2847
    protected String type_geometry = "TEXT";
2848
    protected String type_char = "CHARACTER(1)";
2849
    protected String type_date = "DATE";
2850
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2851
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2852
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2853
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2854
    protected String type_int = "INT";
2855
    protected String type_long = "BIGINT";
2856
    protected String type_string = "TEXT";
2857
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2858
    protected String type_time = "TIME";
2859
    protected String type_timestamp = "TIMESTAMP";
2860
    protected String type_version = "VARCHAR(30)";
2861
    protected String type_URI = "TEXT";
2862
    protected String type_URL = "TEXT";
2863
    protected String type_FILE = "TEXT";
2864
    protected String type_FOLDER = "TEXT";
2865

    
2866
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2867
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2868
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2869
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2870
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2871
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2872
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2873
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2874
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2875
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2876

    
2877
    public SQLBuilderBase() {
2878
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2879

    
2880
        this.hasSpatialFunctions = false;
2881
        this.supportSchemas = true;
2882
        this.geometrySupportType = GeometrySupportType.WKT;
2883

    
2884
        this.defaultSchema = "public";
2885
        this.allowAutomaticValues = true;
2886

    
2887
    }
2888
    
2889
    @Override
2890
    public void setProperties(Class filter, final Object... values) {
2891
        this.expressionBuilder.setProperties(filter, values);
2892
        this.accept((Visitable v) -> {
2893
            for (int i = 0; i < values.length; i+=2) {
2894
                ((Value)v).setProperty((String) values[i], values[i+1]);
2895
            }
2896
        }, new ClassVisitorFilter(filter) );
2897
    }
2898

    
2899
    public String quote_for_identifiers() {
2900
        return "\"";
2901
    }
2902

    
2903
    public String quote_for_strings() {
2904
        return "'";
2905
    }
2906

    
2907
    @Override
2908
    public String as_identifier(String id) {
2909
        String quote = this.quote_for_identifiers();
2910
//        No se porque no esta disponible wrapIfMissing
2911
//        return StringUtils.wrapIfMissing(id,quote);
2912
        if (id.startsWith(quote)) {
2913
            return id;
2914
        }
2915
        return quote + id + quote;
2916

    
2917
    }
2918

    
2919
    @Override
2920
    public String as_string(String s) {
2921
        String quote = this.quote_for_strings();
2922
//        No se porque no esta disponible wrapIfMissing
2923
//        return StringUtils.wrapIfMissing(id,quote);
2924
        if (s.startsWith(quote)) {
2925
            return s;
2926
        }
2927
        return quote + s + quote;
2928

    
2929
    }
2930

    
2931
    @Override
2932
    public String as_string(byte[] data) {
2933
        return this.expressionBuilder.bytearray_0x(data);
2934
//        return this.expressionBuilder.bytearray_hex(data);
2935
//        return this.expressionBuilder.bytearray_x(data);
2936
    }
2937
    
2938
    @Override
2939
    public String as_string(boolean value) {
2940
        return value? "TRUE" : "FALSE";
2941
    }
2942

    
2943
    @Override
2944
    public String as_string(Number value) {
2945
        return Objects.toString(value);
2946
    }
2947
    
2948
    @Override
2949
    public String as_string(Object value) {
2950
        if( value == null ) {
2951
            return "NULL";
2952
        }
2953
        if( value instanceof CharSequence ) {
2954
            return as_string(value.toString());
2955
        }
2956
        if( value instanceof Number ) {
2957
            return as_string((Number)value);
2958
        }
2959
        if( value instanceof Boolean ) {
2960
            return as_string((boolean)value);
2961
        }
2962
        if( value instanceof byte[] ) {
2963
            return as_string((byte[])value);
2964
        }
2965
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2966
    }
2967
    
2968
    @Override
2969
    public GeometryExpressionBuilder expression() {
2970
        return this.expressionBuilder;
2971
    }
2972

    
2973
    @Override
2974
    public boolean has_spatial_functions() {
2975
        return this.hasSpatialFunctions;
2976
    }
2977

    
2978
    @Override
2979
    public GeometrySupportType geometry_support_type() {
2980
        return this.geometrySupportType;
2981
    }
2982

    
2983
    protected GeometryExpressionBuilder createExpressionBuilder() {
2984
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2985
    }
2986

    
2987
    @Override
2988
    public Object srs_id(IProjection projection) {
2989
        String abrev = projection.getAbrev();
2990
        return abrev.split(":")[1].trim();
2991
    }
2992

    
2993
    @Override
2994
    public String default_schema() {
2995
        return this.defaultSchema;
2996
    }
2997

    
2998
    @Override
2999
    public boolean support_schemas() {
3000
        return this.supportSchemas;
3001
    }
3002

    
3003
    @Override
3004
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3005
        switch (type) {
3006
            case DataTypes.BOOLEAN:
3007
                return type_boolean;
3008
            case DataTypes.CHAR:
3009
                return type_char;
3010

    
3011

    
3012
            case DataTypes.BYTE:
3013
                return type_byte;
3014
            case DataTypes.INT:
3015
                return type_int;
3016
            case DataTypes.LONG:
3017
                return type_long;
3018

    
3019
            case DataTypes.FLOAT:
3020
                return type_float;
3021
            case DataTypes.DOUBLE:
3022
                return type_double;
3023
            case DataTypes.DECIMAL:
3024
                if (precision < 1) {
3025
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3026
                }
3027
                if (scale < 1) {
3028
                  return MessageFormat.format(type_decimal_p, precision);
3029
                }
3030
                return MessageFormat.format(type_decimal_ps, precision, scale);
3031

    
3032
                
3033
            case DataTypes.STRING:
3034
                if (size < 0) {
3035
                    return type_string;
3036
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3037
                    return MessageFormat.format(type_string_p, size);
3038
                }
3039
                return type_string;
3040

    
3041
                
3042
            case DataTypes.DATE:
3043
                return type_date;
3044
            case DataTypes.TIME:
3045
                return type_time;
3046
            case DataTypes.TIMESTAMP:
3047
                return type_timestamp;
3048

    
3049
            case DataTypes.BYTEARRAY:
3050
                return type_bytearray;
3051

    
3052
            case DataTypes.GEOMETRY:
3053
                return type_geometry;
3054

    
3055
            case DataTypes.VERSION:
3056
                return type_version;
3057
            case DataTypes.URI:
3058
                return type_URI;
3059
            case DataTypes.URL:
3060
                return type_URL;
3061
            case DataTypes.FILE:
3062
                return type_FILE;
3063
            case DataTypes.FOLDER:
3064
                return type_FOLDER;
3065
            default:
3066
                return null;
3067
        }
3068
    }
3069

    
3070
    @Override
3071
    public Object sqlgeometrytype(int type, int subtype) {
3072
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3073
        // identificadores numericos para el tipo y otros strings.
3074
        // Por defecto vamos a devolver strings.
3075
        if (sqlgeometrytypes == null) {
3076
            sqlgeometrytypes = new HashMap<>();
3077
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3078
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3079
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3080
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3081

    
3082
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3083
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3084
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3085
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3086

    
3087
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3088
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3089
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3090
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3091

    
3092
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3093
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3094
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3095
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3096

    
3097
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3098
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3099
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3100
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3101

    
3102
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3103
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3104
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3105
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3106

    
3107
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3108
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3109
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3110
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3111

    
3112
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3113
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3114
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3115
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3116

    
3117
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3118
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3119
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3120
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3121
        }
3122
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3123
    }
3124

    
3125
    @Override
3126
    public Object sqlgeometrydimension(int type, int subtype) {
3127
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3128
        // identificadores numericos para las dimensiones y otros strings.
3129
        // Por defecto vamos a devolver enteros.
3130
        switch (subtype) {
3131
            case Geometry.SUBTYPES.GEOM3D:
3132
                return 3;
3133
            case Geometry.SUBTYPES.GEOM2DM:
3134
                return 3;
3135
            case Geometry.SUBTYPES.GEOM3DM:
3136
                return 4;
3137
            case Geometry.SUBTYPES.GEOM2D:
3138
            default:
3139
                return 2;
3140
        }
3141
    }
3142

    
3143
    @Override
3144
    public TableNameBuilder createTableNameBuilder() {
3145
        return new TableNameBuilderBase();
3146
    }
3147

    
3148
    protected SelectColumnBuilder createSelectColumnBuilder() {
3149
        return new SelectColumnBuilderBase(this);
3150
    }
3151

    
3152
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3153
        return new UpdateColumnBuilderBase();
3154
    }
3155

    
3156
    protected InsertColumnBuilder createInsertColumnBuilder() {
3157
        return new InsertColumnBuilderBase();
3158
    }
3159

    
3160
    protected OrderByBuilder createOrderByBuilder() {
3161
        return new OrderByBuilderBase();
3162
    }
3163

    
3164
    protected FromBuilder createFromBuilder() {
3165
        return new FromBuilderBase();
3166
    }
3167

    
3168
    protected SelectBuilder createSelectBuilder() {
3169
        return new SelectBuilderBase();
3170
    }
3171

    
3172
    protected UpdateBuilder createUpdateBuilder() {
3173
        return new UpdateBuilderBase();
3174
    }
3175

    
3176
    protected DeleteBuilder createDeleteBuilder() {
3177
        return new DeleteBuilderBase();
3178
    }
3179

    
3180
    protected GrantBuilder createGrantBuilder() {
3181
        return new GrantBuilderBase();
3182
    }
3183

    
3184
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3185
        return new GrantRoleBuilderBase(table, role);
3186
    }
3187

    
3188
    protected DropTableBuilder createDropTableBuilder() {
3189
        return new DropTableBuilderBase();
3190
    }
3191

    
3192
    protected CreateTableBuilder createCreateTableBuilder() {
3193
        return new CreateTableBuilderBase();
3194
    }
3195

    
3196
    protected AlterTableBuilder createAlterTableBuilder() {
3197
        return new AlterTableBuilderBase();
3198
    }
3199

    
3200
    protected InsertBuilder createInsertBuilder() {
3201
        return new InsertBuilderBase();
3202
    }
3203

    
3204
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3205
        return new UpdateTableStatisticsBuilderBase();
3206
    }
3207

    
3208
    protected CreateIndexBuilder createCreateIndexBuilder() {
3209
        return new CreateIndexBuilderBase();
3210
    }
3211

    
3212
    protected DropIndexBuilder createDropIndexBuilder() {
3213
        return new DropIndexBuilderBase();
3214
    }
3215

    
3216
    @Override
3217
    public SelectBuilder select() {
3218
        if (this.select == null) {
3219
            this.select = this.createSelectBuilder();
3220
        }
3221
        return this.select;
3222
    }
3223

    
3224
    @Override
3225
    public UpdateBuilder update() {
3226
        if (this.update == null) {
3227
            this.update = this.createUpdateBuilder();
3228
        }
3229
        return this.update;
3230
    }
3231

    
3232
    @Override
3233
    public UpdateTableStatisticsBuilder update_table_statistics() {
3234
        if (this.update_table_statistics == null) {
3235
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3236
        }
3237
        return this.update_table_statistics;
3238
    }
3239

    
3240
    @Override
3241
    public DropTableBuilder drop_table() {
3242
        if (this.drop_table == null) {
3243
            this.drop_table = this.createDropTableBuilder();
3244
        }
3245
        return this.drop_table;
3246
    }
3247

    
3248
    @Override
3249
    public CreateIndexBuilder create_index() {
3250
        if (this.create_index == null) {
3251
            this.create_index = this.createCreateIndexBuilder();
3252
        }
3253
        return this.create_index;
3254
    }
3255

    
3256
    @Override
3257
    public DropIndexBuilder drop_index() {
3258
        if (this.drop_index == null) {
3259
            this.drop_index = this.createDropIndexBuilder();
3260
        }
3261
        return this.drop_index;
3262
    }
3263

    
3264
    @Override
3265
    public DeleteBuilder delete() {
3266
        if (this.delete == null) {
3267
            this.delete = this.createDeleteBuilder();
3268
        }
3269
        return this.delete;
3270
    }
3271

    
3272
    @Override
3273
    public InsertBuilder insert() {
3274
        if (this.insert == null) {
3275
            this.insert = this.createInsertBuilder();
3276
        }
3277
        return this.insert;
3278
    }
3279

    
3280
    @Override
3281
    public TableNameBuilder table_name() {
3282
        if (this.table_name == null) {
3283
            this.table_name = this.createTableNameBuilder();
3284
        }
3285
        return this.table_name;
3286
    }
3287

    
3288
    
3289
    @Override
3290
    public AlterTableBuilder alter_table() {
3291
        if (this.alter_table == null) {
3292
            this.alter_table = this.createAlterTableBuilder();
3293
        }
3294
        return this.alter_table;
3295
    }
3296

    
3297
    @Override
3298
    public CreateTableBuilder create_table() {
3299
        if (this.create_table == null) {
3300
            this.create_table = this.createCreateTableBuilder();
3301
        }
3302
        return this.create_table;
3303
    }
3304

    
3305
    @Override
3306
    public GrantBuilder grant() {
3307
        if (this.grant == null) {
3308
            this.grant = this.createGrantBuilder();
3309
        }
3310
        return this.grant;
3311
    }
3312
    
3313
    @Override
3314
    public Column column(String name) {
3315
        ColumnBase col = new ColumnBase(null, name);
3316
        return col;
3317
    }
3318

    
3319
    @Override
3320
    public Column column(TableNameBuilder table, String name) {
3321
        ColumnBase col = new ColumnBase(table, name);
3322
        return col;
3323
    }
3324
    
3325
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3326
        return new JoinBase(type, table, expression);
3327
    }
3328

    
3329
    public void accept(Visitor visitor, VisitorFilter filter) {
3330
        if (this.select != null) {
3331
            this.select.accept(visitor, filter);
3332
        }
3333
        if (this.update != null) {
3334
            this.update.accept(visitor, filter);
3335
        }
3336
        if (this.insert != null) {
3337
            this.insert.accept(visitor, filter);
3338
        }
3339
        if (this.delete != null) {
3340
            this.delete.accept(visitor, filter);
3341
        }
3342
        if (this.alter_table != null) {
3343
            this.alter_table.accept(visitor, filter);
3344
        }
3345
        if (this.create_table != null) {
3346
            this.create_table.accept(visitor, filter);
3347
        }
3348
        if (this.drop_table != null) {
3349
            this.drop_table.accept(visitor, filter);
3350
        }
3351
        if (this.table_name != null) {
3352
            this.table_name.accept(visitor, filter);
3353
        }
3354
    }
3355

    
3356
        @Override
3357
    public Formatter formatter() {
3358
        return expression().formatter();
3359
    }
3360

    
3361
    @Override
3362
    public String toString() {
3363
        return this.toString(formatter());
3364
    }
3365

    
3366
    @Override
3367
    public String toString(Formatter formatter) {
3368
        if (this.select != null) {
3369
            return this.select.toString(formatter);
3370
        }
3371
        if (this.update != null) {
3372
            return this.update.toString(formatter);
3373
        }
3374
        if (this.insert != null) {
3375
            return this.insert.toString(formatter);
3376
        }
3377
        if (this.delete != null) {
3378
            return this.delete.toString(formatter);
3379
        }
3380
        if (this.alter_table != null) {
3381
            return this.alter_table.toString(formatter);
3382
        }
3383
        if (this.create_table != null) {
3384
            return this.create_table.toString(formatter);
3385
        }
3386
        if (this.drop_table != null) {
3387
            return this.drop_table.toString(formatter);
3388
        }
3389
        if (this.update_table_statistics != null) {
3390
            return this.update_table_statistics.toString(formatter);
3391
        }
3392
        if (this.create_index != null) {
3393
            return this.create_index.toString(formatter);
3394
        }
3395
        if (this.drop_index != null) {
3396
            return this.drop_index.toString(formatter);
3397
        }
3398
        if (this.table_name != null) {
3399
            return this.table_name.toString(formatter);
3400
        }
3401
        return "";
3402
    }
3403

    
3404
    @Override
3405
    public CountBuilder count() {
3406
        return new CountBuilderBase();
3407
    }
3408

    
3409
    @Override
3410
    public List<Parameter> parameters() {
3411
        final List<Parameter> params = new ArrayList<>();
3412
        this.accept((Visitable value) -> {
3413
            params.add((Parameter) value);
3414
        }, new ClassVisitorFilter(Parameter.class));
3415
        return params;
3416
    }
3417

    
3418
    @Override
3419
    public List<Variable> variables() {
3420
        final List<Variable> vars = new ArrayList<>();
3421
        this.accept(new Visitor() {
3422
            @Override
3423
            public void visit(Visitable value) {
3424
                if (!vars.contains((Variable) value)) {
3425
                    vars.add((Variable) value);
3426
                }
3427
            }
3428
        }, new ClassVisitorFilter(Variable.class));
3429
        return vars;
3430
    }
3431

    
3432
    @Override
3433
    public List<String> parameters_names() {
3434
        List<String> params = new ArrayList<>();
3435
        for (Parameter param : parameters()) {
3436
            String s;
3437
            switch (param.type()) {
3438
                case PARAMETER_TYPE_CONSTANT:
3439
                    Object theValue = param.value();
3440
                    if (theValue == null) {
3441
                        s = "null";
3442
                    } else if (theValue instanceof String) {
3443
                        s = "'" + (String) theValue + "'";
3444
                    } else {
3445
                        s = theValue.toString();
3446
                    }
3447
                    break;
3448
                case PARAMETER_TYPE_VARIABLE:
3449
                default:
3450
                    s = "\"" + param.name() + "\"";
3451
            }
3452
            params.add(s);
3453
        }
3454
        return params;
3455
    }
3456

    
3457
    @Override
3458
    public List<String> variables_names() {
3459
        List<String> vars = new ArrayList<>();
3460
        for (Variable var : this.variables()) {
3461
            vars.add(var.name());
3462
        }
3463
        Collections.sort(vars);
3464
        return vars;
3465
    }    
3466
    
3467
    protected String[] aggregateFunctionNames = new String[] {
3468
        "MAX",
3469
        "MIN",
3470
        "COUNT",
3471
        "SUM"
3472
    };
3473
    
3474
    @Override
3475
    public boolean isAggregateFunction(String funcname) {
3476
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
3477
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
3478
                return true;
3479
            }
3480
        }
3481
        return false;
3482
    }
3483

    
3484
    @Override
3485
    public int getMaxRecomendedSQLLength() {
3486
        return DEFAULT_RECOMENDED_SQL_LENGTH;
3487
    }
3488
    
3489
    
3490
}