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

History | View | Annotate | Download (142 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 static org.gvsig.expressionevaluator.ExpressionBuilder.VALUE_NULL;
23
import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
24
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
25
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
26
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
27
import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
28
import org.gvsig.expressionevaluator.Formatter;
29
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
30
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
31
import org.gvsig.expressionevaluator.GeometryExpressionEvaluatorLocator;
32
import org.gvsig.fmap.dal.DataManager;
33
import org.gvsig.fmap.dal.DataStoreParameters;
34
import org.gvsig.fmap.dal.DataTypes;
35
import org.gvsig.fmap.dal.SQLBuilder;
36
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
37
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
38
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
41
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
42
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
43
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
44
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
45
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
46
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
47
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
48
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
49
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
50
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
51
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
52
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
53
import org.gvsig.fmap.dal.feature.FeatureType;
54
import org.gvsig.fmap.geom.Geometry;
55
import org.gvsig.fmap.geom.GeometryUtils;
56
import org.gvsig.fmap.geom.primitive.Envelope;
57
import org.gvsig.tools.dataTypes.DataType;
58
import org.gvsig.tools.dynobject.Tags;
59
import org.gvsig.tools.lang.CloneableUtils;
60
import org.gvsig.tools.util.Bitmask;
61
import org.gvsig.tools.util.PropertiesSupport;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64

    
65
@SuppressWarnings("UseSpecificCatch")
66
public class SQLBuilderBase implements SQLBuilder {
67

    
68
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
69

    
70
    protected SelectBuilder select;
71
    protected UpdateBuilder update;
72
    protected MergeBuilder merge;
73
    protected InsertBuilder insert;
74
    protected DeleteBuilder delete;
75
    protected AlterTableBuilder alter_table;
76
    protected CreateTableBuilder create_table;
77
    protected GrantBuilder grant;
78
    protected DropTableBuilder drop_table;
79
    protected UpdateTableStatisticsBuilder update_table_statistics;
80
    protected CreateIndexBuilder create_index;
81
    protected DropIndexBuilder drop_index;
82
    protected TableNameBuilder table_name;
83

    
84
    protected abstract class AbstractStatementPart extends AbstractValue {
85
        
86
    }
87

    
88
    protected abstract class AbstractStatement extends AbstractStatementPart {
89
        @Override
90
        public Value clone() throws CloneNotSupportedException {
91
            throw new CloneNotSupportedException();
92
        }
93
    }
94

    
95
    protected class ColumnDescriptorBase implements ColumnDescriptor {
96

    
97
        private String name;
98
        private int type;
99
        private int size;
100
        private int precision;
101
        private int scale;
102
        private boolean isPk;
103
        private boolean _allowNulls;
104
        private boolean _allowIndexDuplicateds;
105
        private boolean _isAutomatic;
106
        private Object defaultValue;
107
        private int geom_type;
108
        private int geom_subtype;
109
        private Object geom_srsdbcode;
110
        private Envelope tablebbox;
111
        private boolean _isIndexed;
112
        private DataStoreParameters parameters = null;
113

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

    
132
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
133
            this(name, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, true);
134
        }
135
        
136
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue, boolean allowIndexDuplicateds) {
137
            this.name = name;
138
            this.type = type;
139
            this.size = size;
140
            this.precision = precision;
141
            this.scale = scale;
142
            this.isPk = isPk;
143
            this._allowNulls = allowNulls;
144
            this._isAutomatic = isAutomatic;
145
            this.defaultValue = defaultValue;
146
            this.geom_type = Geometry.TYPES.GEOMETRY;
147
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
148
            this.geom_srsdbcode = null;
149
            this.tablebbox = null;
150
            this._isIndexed = isIndexed;
151
            this._allowIndexDuplicateds = allowIndexDuplicateds;
152
        }
153

    
154
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
155
            this.name = name;
156
            this.type = DataTypes.GEOMETRY;
157
            this.size = 0;
158
            this.precision = 0;
159
            this.scale = 0;
160
            this.isPk = false;
161
            this._allowNulls = allowNulls;
162
            this._isAutomatic = false;
163
            this.defaultValue = null;
164
            this.geom_type = geom_type;
165
            this.geom_subtype = geom_subtype;
166
            this.geom_srsdbcode = srs_id(proj);
167
            this.tablebbox = null;
168
            this._isIndexed = isIndexed;
169
            this._allowIndexDuplicateds = true;
170
        }
171

    
172
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
173
            this.name = name;
174
            this.type = DataTypes.GEOMETRY;
175
            this.size = 0;
176
            this.precision = 0;
177
            this.scale = 0;
178
            this.isPk = false;
179
            this._allowNulls = allowNulls;
180
            this._isAutomatic = false;
181
            this.defaultValue = null;
182
            this.geom_type = geom_type;
183
            this.geom_subtype = geom_subtype;
184
            this.geom_srsdbcode = srsdbcode;
185
            this.tablebbox = null;
186
            this._isIndexed = isIndexed;
187
            this._allowIndexDuplicateds = true;
188
        }
189

    
190
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
191
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
192
            this.precision = fad.getPrecision();
193
            this.size = fad.getSize();
194
            this.scale = fad.getScale();
195
            this.isPk = fad.isPrimaryKey();
196
            this._allowNulls = fad.allowNull();
197
            this._isAutomatic = fad.isAutomatic();
198
            this._isIndexed = fad.isIndexed();
199
            this._allowIndexDuplicateds = fad.allowIndexDuplicateds();
200

    
201
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
202
                this.geom_type = fad.getGeomType().getType();
203
                this.geom_subtype = fad.getGeomType().getSubType();
204
                this.geom_srsdbcode =  srs_id(fad.getSRS());
205
                this.tablebbox = null;
206
                Tags tags = fad.getTags();
207
                String s = tags.getString("tablebbox", null);
208
                if( StringUtils.isNotBlank(s) ) {
209
                    try {
210
                        Geometry g = GeometryUtils.createFrom(s);
211
                        if( g!=null ) {
212
                            this.tablebbox = g.getEnvelope();
213
                        }
214
                    } catch(Exception ex) {
215
                        LOGGER.warn("Can't parse tablebbox for column '"+s+"'.",ex);
216
                    }
217
                }
218
            }
219
        }
220
    
221

    
222
        @Override
223
        public String getName() {
224
            return this.name;
225
        }
226

    
227
        @Override
228
        public void setName(String name) {
229
            this.name = name;
230
        }
231

    
232
        @Override
233
        public int getType() {
234
            return this.type;
235
        }
236

    
237
        @Override
238
        public void setType(int type) {
239
            this.type = type;
240
        }
241

    
242
        @Override
243
        public int getPrecision() {
244
            return precision;
245
        }
246

    
247
        @Override
248
        public void setPrecision(int precision) {
249
            this.precision = precision;
250
        }
251

    
252
        @Override
253
        public int getScale() {
254
            return scale;
255
        }
256

    
257
        @Override
258
        public void setScale(int scale) {
259
            this.scale = scale;
260
        }
261

    
262
        @Override
263
        public int getSize() {
264
            return size;
265
        }
266

    
267
        @Override
268
        public void setSize(int size) {
269
            this.size = size;
270
        }
271

    
272
        @Override
273
        public boolean isPrimaryKey() {
274
            return isPk;
275
        }
276

    
277
        @Override
278
        public void setIsPrimaryKey(boolean isPk) {
279
            this.isPk = isPk;
280
        }
281

    
282
        @Override
283
        public boolean allowNulls() {
284
            return _allowNulls;
285
        }
286

    
287
        @Override
288
        public void setAllowNulls(boolean allowNulls) {
289
            this._allowNulls = allowNulls;
290
        }
291

    
292
        @Override
293
        public boolean isAutomatic() {
294
            return _isAutomatic;
295
        }
296

    
297
        @Override
298
        public boolean isIndexed() {
299
            return _isIndexed;
300
        }
301

    
302
        @Override
303
        public void setIsAutomatic(boolean isAutomatic) {
304
            this._isAutomatic = isAutomatic;
305
        }
306

    
307
        @Override
308
        public Object getDefaultValue() {
309
            return defaultValue;
310
        }
311

    
312
        @Override
313
        public void setDefaultValue(Object defaultValue) {
314
            this.defaultValue = defaultValue;
315
        }
316

    
317
        @Override
318
        public int getGeometryType() {
319
            return geom_type;
320
        }
321

    
322
        @Override
323
        public void setGeometryType(int geom_type) {
324
            this.geom_type = geom_type;
325
        }
326

    
327
        @Override
328
        public int getGeometrySubtype() {
329
            return geom_subtype;
330
        }
331

    
332
        @Override
333
        public void setGeometrySubtype(int geom_subtype) {
334
            this.geom_subtype = geom_subtype;
335
        }
336

    
337
        @Override
338
        public Object getGeometrySRSId() {
339
            return geom_srsdbcode;
340
        }
341

    
342
        @Override
343
        public void setGeometrySRSId(Object geom_srsid) {
344
            this.geom_srsdbcode = geom_srsid;
345
        }
346

    
347
        @Override
348
        public boolean isGeometry() {
349
            return this.type == DataTypes.GEOMETRY;
350
        }
351

    
352
        private void setStoreParameters(DataStoreParameters parameters) {
353
            this.parameters = parameters;
354
        }
355

    
356
        @Override
357
        public DataStoreParameters getStoreParameters() {
358
            return this.parameters;
359
        }
360
        
361
        public Envelope getTableBBox() {
362
            return this.tablebbox;
363
        }
364
        
365
        public void setTableBBox(Envelope bbox) {
366
            this.tablebbox = bbox;
367
        }
368

    
369
        @Override
370
        public boolean allowIndexDuplicateds() {
371
            return this._allowIndexDuplicateds;
372
        }
373

    
374
        @Override
375
        public void setAllowIndexDuplicateds(boolean allowIndexDuplicateds) {
376
            this._allowIndexDuplicateds = allowIndexDuplicateds;
377
        }
378
        
379
    }
380

    
381
    public class ColumnBase extends AbstractValue implements Column {
382

    
383
        private final String name;
384
        private TableNameBuilder table;
385

    
386
        public ColumnBase(TableNameBuilder table, String name) {
387
            this.name = name;
388
            this.table = table;
389
        }
390
        
391
        @Override
392
        public ColumnBase clone() throws CloneNotSupportedException {
393
            ColumnBase other = (ColumnBase) super.clone();
394
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
395
            return other;
396
        }
397

    
398

    
399
        @Override
400
        public String name() {
401
            return this.name;
402
        }
403

    
404
        @Override
405
        public TableNameBuilder table() {
406
            return this.table;
407
        }
408

    
409
        @Override
410
        public TableNameBuilder table(TableNameBuilder table) {
411
            this.table = table;
412
            return this.table;
413
        }
414

    
415
        @Override
416
        public String toString() {
417
            return this.toString(formatter());
418
        }
419
        
420
        @Override
421
        public String toString(Formatter<Value> formatter) {
422
            if( formatter!=null && formatter.canApply(this) ) {
423
                return formatter.format(this);
424
            }
425
            if( this.table==null ) {
426
                return as_identifier(this.name);
427
            }
428
            return this.table.toString(formatter) + "." + as_identifier(this.name);
429
        }
430

    
431
        @Override
432
        public int compareTo(Variable o) {
433
            return this.name.compareTo(o.name());
434
        }
435

    
436
        @Override
437
        public boolean equals(Object obj) {
438
            if (!(obj instanceof Variable)) {
439
                return false;
440
            }
441
            return StringUtils.equals(this.toString(), ((Variable) obj).toString());
442
        }
443

    
444
        @Override
445
        public int hashCode() {
446
            int hash = 7;
447
            hash = 37 * hash + Objects.hashCode(this.toString());
448
            return hash;
449
        }
450

    
451
        @Override
452
        public void setProperty(String name, Object value) {
453
            super.setProperty(name, value);
454
            if(this.table != null){
455
                this.table.setProperty(name, value);
456
            }
457
        }
458
        
459
        
460
    }
461

    
462
    public class TableNameBuilderBase
463
            extends AbstractStatementPart
464
            implements TableNameBuilder {
465

    
466
        public String tableName;
467
        public String schemaName;
468
        private String databaseName;
469
        private FeatureType featureType;
470

    
471
        public TableNameBuilderBase() {
472
        }
473
        
474
        @Override
475
        public void accept(Visitor visitor, VisitorFilter filter) {
476
            if (filter==null || filter.accept(this)) {
477
                visitor.visit(this);
478
            }
479
        }
480

    
481
        @Override
482
        public TableNameBuilder database(String name) {
483
            this.databaseName = name;
484
            return this;
485
        }
486

    
487
        @Override
488
        public TableNameBuilder schema(String name) {
489
            if (support_schemas()) {
490
                this.schemaName = name;
491
            }
492
            return this;
493
        }
494

    
495
        @Override
496
        public TableNameBuilder name(String name) {
497
            this.tableName = name;
498
            return this;
499
        }
500

    
501
        protected String databaseName2provider() {
502
            return this.databaseName;
503
        }
504

    
505
        protected String schemaName2provider() {
506
            return this.schemaName;
507
        }
508

    
509
        protected String tableName2provider() {
510
            return this.tableName;
511
        }
512

    
513
        @Override
514
        public String getDatabase() {
515
            return this.databaseName;
516
        }
517

    
518
        @Override
519
        public String getSchema() {
520
            return this.schemaName;
521
        }
522

    
523
        @Override
524
        public String getName() {
525
            return this.tableName;
526
        }
527

    
528
        @Override
529
        public boolean has_schema() {
530
            if (!support_schemas()) {
531
                return false;
532
            }
533
            return StringUtils.isNotBlank(this.schemaName);
534
        }
535

    
536
        @Override
537
        public boolean has_name() {
538
            return StringUtils.isNotBlank(this.tableName);
539
        }
540

    
541
        @Override
542
        public boolean has_database() {
543
            return StringUtils.isNotBlank(this.databaseName);
544
        }
545

    
546
        @Override
547
        public boolean isEmpty() {
548
            return !this.has_database() && !this.has_schema() && !this.has_name();
549
        }
550

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

    
556
        @Override
557
        public String toString(Formatter<Value> formatter) {
558
            if (formatter!=null && formatter.canApply(this)) {
559
                return formatter.format(this);
560
            }
561
            if (this.has_database()) {
562
                if (this.has_schema()) {
563
                    return as_identifier(this.databaseName2provider()) + "."
564
                            + as_identifier(this.schemaName2provider()) + "."
565
                            + as_identifier(this.tableName2provider());
566
                }
567
//                return as_identifier(this.databaseName) + "."
568
//                        + as_identifier(this.tableName);
569
            } else {
570
                if (this.has_schema()) {
571
                    return as_identifier(this.schemaName2provider()) + "."
572
                            + as_identifier(this.tableName2provider());
573
                }
574
            }
575
            return as_identifier(this.tableName2provider());
576
        }
577

    
578
        @Override
579
        public boolean equals(Object obj) {
580
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
581
                return false;
582
            }
583
            TableNameBuilder other = (TableNameBuilder) obj;
584
            
585
            if (this.has_database() != other.has_database()) {
586
                return false;
587
            }
588
            String thisSchema = null;
589
            String otherSchema = null;
590
            if(support_schemas()) {
591
                thisSchema = this.schemaName;
592
                if (StringUtils.isBlank(thisSchema)) {
593
                    thisSchema = default_schema();
594
                }
595
                otherSchema = other.getSchema();
596
                if (StringUtils.isBlank(otherSchema)) {
597
                    otherSchema = default_schema();
598
                }
599
            }
600
            if (this.has_database()) {
601
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
602
                           StringUtils.equals(thisSchema, otherSchema) &&
603
                           StringUtils.equals(this.tableName,other.getName());
604
            } else {
605
                    return StringUtils.equals(thisSchema, otherSchema) &&
606
                           StringUtils.equals(this.tableName,other.getName());
607
            }
608
        }
609

    
610
        @Override
611
        public int hashCode() {
612
            int hash = 7;
613
            hash = 37 * hash + Objects.hashCode(this.toString());
614
            return hash;
615
        }
616

    
617
        @Override
618
        public void setFeatureType(FeatureType featureType) {
619
            this.featureType=featureType;
620
        }
621

    
622
        @Override
623
        public FeatureType featureType() {
624
            return this.featureType;
625
        }
626
    }
627

    
628
    public class CountBuilderBase
629
            extends AbstractStatementPart
630
            implements CountBuilder {
631

    
632
        protected Value value;
633
        protected boolean distinct;
634
        protected boolean all;
635

    
636
        public CountBuilderBase() {
637
            this.value = null;
638
            this.distinct = false;
639
            this.all = false;
640
        }
641
        
642
        @Override
643
        public CountBuilderBase clone() throws CloneNotSupportedException {
644
            CountBuilderBase other = (CountBuilderBase) super.clone();
645
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
646
            return other;
647
        }
648
        
649
        @Override
650
        public CountBuilder all() {
651
            this.all = true;
652
            return this;
653
        }
654

    
655
        @Override
656
        public CountBuilder column(Value value) {
657
            this.value = value;
658
            return this;
659
        }
660

    
661
        @Override
662
        public CountBuilder distinct() {
663
            this.distinct = true;
664
            return this;
665
        }
666

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

    
672
        @Override
673
        public String toString(Formatter formatter) {
674
            if (formatter!=null && formatter.canApply(this)) {
675
                return formatter.format(this);
676
            }
677
            if (this.all) {
678
                return "COUNT(*)";
679
            }
680
            if (this.distinct) {
681
                return MessageFormat.format(
682
                        "COUNT(DISTINCT {0})",
683
                        value.toString(formatter)
684
                );
685
            }
686
            return MessageFormat.format(
687
                    "COUNT({0})",
688
                    value.toString(formatter)
689
            );
690
        }
691

    
692
    }
693

    
694
    protected class JoinBase 
695
            extends AbstractStatementPart
696
            implements JoinBuilder 
697
        {
698
        protected String type;
699
        protected TableNameBuilder table;
700
        protected Value expression;
701
        
702
        public JoinBase(String type, TableNameBuilder table, Value expression) {
703
            this.type = type;
704
            this.table = table;
705
            this.expression = expression;
706
        }
707
        
708
        @Override
709
        public JoinBase clone() throws CloneNotSupportedException {
710
            JoinBase other = (JoinBase) super.clone();
711
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
712
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
713
            return other;
714
        }
715

    
716
        @Override
717
        public String toString() {
718
            return this.toString(formatter());
719
        }
720

    
721
        @Override
722
        public String toString(Formatter<Value> formatter) {
723
            if (formatter!=null && formatter.canApply(this)) {
724
                return formatter.format(this);
725
            }
726
            StringBuilder builder = new StringBuilder();
727
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
728
            builder.append(this.type.toUpperCase());
729
            builder.append(" JOIN ");
730
            builder.append(this.table.toString(formatter));
731
            builder.append(" ON ");
732
            builder.append(this.expression.toString(formatter));
733
            return builder.toString();
734
        }
735
        
736
        @Override
737
        public TableNameBuilder getTable() {
738
            return this.table;
739
        }
740
        
741
        @Override
742
        public String getType() {
743
            return this.type;
744
        }
745

    
746
        @Override
747
        public Value getCondition() {
748
            return this.expression;
749
        }
750
        
751
        @Override
752
        public void accept(Visitor visitor, VisitorFilter filter) {
753
            boolean visitChildren = true;
754
            if (filter==null || filter.accept(this)) {
755
                visitor.visit(this);
756
            } else {
757
                visitChildren = !filter.skipChildren();
758
            }
759
            if(visitChildren){
760
                if (this.expression != null) {
761
                    this.expression.accept(visitor, filter);
762
                }
763
            }
764
        }
765

    
766
    }
767
    
768
    public class FromBuilderBase
769
            extends AbstractStatementPart
770
            implements FromBuilder {
771

    
772
        protected TableNameBuilder tableName;
773
        protected String subquery;
774
        protected String passthrough;
775
        protected List<JoinBuilder> joins;
776

    
777
        public FromBuilderBase() {
778
            this.tableName = null;
779
            this.subquery = null;
780
            this.passthrough = null;
781
            this.joins = null;
782
        }
783
        
784
        @Override
785
        public FromBuilderBase clone() throws CloneNotSupportedException {
786
            FromBuilderBase other = (FromBuilderBase) super.clone();
787
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
788
            if (joins!=null) {
789
                for (int i = 0; i < joins.size(); i++) {
790
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
791
                }
792
            }
793
            return other;
794
        }
795

    
796
        @Override
797
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
798
            JoinBase join = createJoin("LEFT", table, expression);
799
            if( this.joins==null ) {
800
                this.joins = new ArrayList<>();
801
            }
802
            this.joins.add(join);
803
            return this;
804
        }
805
        
806
        @Override
807
        public TableNameBuilder table() {
808
            if (tableName == null) {
809
                this.tableName = createTableNameBuilder();
810
            }
811
            return this.tableName;
812
        }
813

    
814
        @Override
815
        public void accept(Visitor visitor, VisitorFilter filter) {
816
            boolean visitChildren = true;
817
            if (filter==null || filter.accept(this)) {
818
                visitor.visit(this);
819
            } else {
820
                visitChildren = !filter.skipChildren();
821
            }
822
            if(visitChildren){
823
                if (this.tableName != null) {
824
                    this.tableName.accept(visitor, filter);
825
                }
826
                if(this.joins != null) {
827
                    for (JoinBuilder join : joins) {
828
                        join.accept(visitor, filter);
829
                    }
830
                }
831
            }
832
        }
833

    
834
        @Override
835
        public FromBuilder custom(String passthrough) {
836
            this.passthrough = passthrough;
837
            return this;
838
        }
839

    
840
        @Override
841
        public FromBuilder subquery(String subquery) {
842
            this.subquery = subquery;
843
            return this;
844
        }
845

    
846
        @Override
847
        public String toString() {
848
            return this.toString(formatter());
849
        }
850

    
851
        @Override
852
        public String toString(Formatter<Value> formatter) {
853
            if (formatter!=null && formatter.canApply(this)) {
854
                return formatter.format(this);
855
            }
856
            if (!StringUtils.isEmpty(passthrough)) {
857
                return passthrough;
858
            }
859
            if (!StringUtils.isEmpty(subquery)) {
860
                return "( " + this.subquery + ") AS _subquery_alias_ ";
861
            }
862
            if( this.joins==null || this.joins.isEmpty() ) {
863
                return this.tableName.toString(formatter);
864
            }
865
            StringBuilder builder = new StringBuilder();
866
            builder.append(this.tableName.toString(formatter));
867
            for (JoinBuilder join : this.joins) {
868
                builder.append(" ");
869
                builder.append(join.toString(formatter));
870
            }
871
            return builder.toString();
872
        }
873

    
874
        @Override
875
        public List<JoinBuilder> getJoins() {
876
            return this.joins;
877
        }
878

    
879
    }
880

    
881
    public class SelectColumnBuilderBase
882
            extends AbstractStatementPart
883
            implements SelectColumnBuilder {
884

    
885
        protected Column name = null;
886
        protected String alias = null;
887
        protected Value value = null;
888
        protected boolean asGeometry = false;
889
        protected TableNameBuilder table;
890
        protected SQLBuilder sqlbuilder;
891
        
892
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
893
            this.sqlbuilder = sqlbuilder;
894
        }
895
        
896
        @Override
897
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
898
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
899
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
900
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
901
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
902
            return other;
903
        }
904

    
905
        @Override
906
        public void accept(Visitor visitor, VisitorFilter filter) {
907
            boolean visitChildren = true;
908
            if (filter==null || filter.accept(this)) {
909
                visitor.visit(this);
910
            } else {
911
                visitChildren = !filter.skipChildren();
912
            }
913
            if(visitChildren){
914
                if (this.value != null) {
915
                    this.value.accept(visitor, filter);
916
                } else if (this.name != null) {
917
                    this.name.accept(visitor, filter);
918
                }
919
            }
920
        }
921

    
922
        @Override
923
        public void replace(Value target, Value replacement) {
924
            if (this.name!=null ) {
925
                if( this.name == target) {
926
                    if(replacement == null){
927
                        this.name = null;
928
                    } else if(replacement instanceof Column){
929
                        this.name = (Column) replacement;
930
                    } else if(replacement instanceof Variable){
931
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
932
                    } else {
933
                        this.value = replacement;
934
                    }
935
                }
936
            }
937
            if( this.value!=null ) {
938
                if (this.value == target) {
939
                    this.value = replacement;
940
                } else {
941
                    this.value.replace(target, replacement);
942
                }
943
            }
944
        }
945

    
946
        @Override
947
        public SelectColumnBuilder name(String name) {
948
            return this.name(this.table, name);
949
        }
950

    
951
        @Override
952
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
953
            String quote = quote_for_identifiers();
954
            if (name.startsWith(quote)) {
955
                // Remove quotes
956
                name = name.substring(1, name.length() - 1);
957
            }
958
            this.table = table;
959
            this.name = new ColumnBase(this.table, name);
960
            this.value = null;
961
            this.asGeometry = false;
962
            return this;
963
        }
964
        
965
        public SelectColumnBuilder table(TableNameBuilder table) {
966
            this.table = table;
967
            if(this.name != null){
968
                this.name.table(table);
969
            }
970
            return this;
971
        }
972
        
973
        @Override
974
        public SelectColumnBuilder all() {
975
            this.name = null;
976
            this.value = expression().custom("*");
977
            this.asGeometry = false;
978
            return this;
979
        }
980

    
981
        @Override
982
        public SelectColumnBuilder as_geometry() {
983
            this.asGeometry = true;
984
            return this;
985
        }
986

    
987
        @Override
988
        public SelectColumnBuilder value(Value value) {
989
            this.value = value;
990
            return this;
991
        }
992

    
993
        @Override
994
        public SelectColumnBuilder as(String alias) {
995
            this.alias = alias;
996
            return this;
997
        }
998

    
999
        @Override
1000
        public String getName() {
1001
            if (this.name==null) {
1002
                return null;
1003
            }
1004
            return this.name.name();
1005
        }
1006

    
1007
        @Override
1008
        public String getAlias() {
1009
            return this.alias;
1010
        }
1011

    
1012
        @Override
1013
        public Value getValue() {
1014
            return this.value;
1015
        }
1016

    
1017
        @Override
1018
        public String toString() {
1019
            return this.toString(formatter());
1020
        }
1021

    
1022
        @Override
1023
        public String toString(Formatter<Value> formatter) {
1024
            if (formatter!=null && formatter.canApply(this)) {
1025
                return formatter.format(this);
1026
            }
1027
            StringBuilder builder = new StringBuilder();
1028
            if (this.asGeometry) {
1029
                if(this.value == VALUE_NULL){
1030
                    builder.append(this.value.toString(formatter));
1031
                } else {
1032
                    switch(expression().geometry_support_type()) {
1033
                        case WKB:
1034
                            builder.append(expression().ST_AsBinary(this.name).toString(formatter));
1035
                            break;
1036
                        case EWKB:
1037
                            builder.append(expression().ST_AsEWKB(this.name).toString(formatter));
1038
                            break;
1039
                        case WKT:
1040
                            builder.append(expression().ST_AsText(this.name).toString(formatter));
1041
                            break;
1042
                        case NATIVE:
1043
                            builder.append(as_identifier(this.name.toString(formatter)));
1044
                            break;
1045
                    }
1046
                }
1047
            } else {
1048
                if (this.value == null) {
1049
                    builder.append(this.name.toString(formatter));
1050
                } else {
1051
                    builder.append(this.value.toString(formatter));
1052
                }
1053
            }
1054
            if (this.alias != null) {
1055
                builder.append(" AS ");
1056
                builder.append(as_identifier(this.alias));
1057
            }
1058
            return builder.toString();
1059
        }
1060
        
1061
        @Override
1062
        public boolean isGeometry() {
1063
            return this.asGeometry;
1064
        }
1065
        
1066
        @Override
1067
        public TableNameBuilder getTable() {
1068
            return this.table;
1069
        }
1070
        
1071
        @Override
1072
        public boolean isAggregateFunction() {
1073
            if( this.value == null ) {
1074
                return false;
1075
            }
1076
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
1077
                return false;
1078
            }
1079
            String funcname = ((ExpressionBuilder.Function)this.value).name();
1080
            return this.sqlbuilder.isAggregateFunction(funcname);
1081
        }
1082
    }
1083

    
1084
    public class OrderByBuilderBase
1085
            extends AbstractStatementPart
1086
            implements OrderByBuilder {
1087

    
1088
        protected Value value;
1089
        protected String custom;
1090
        protected boolean ascending;
1091
        protected int nullsMode;
1092

    
1093
        public OrderByBuilderBase() {
1094
            this.ascending = true;
1095
            this.nullsMode = MODE_NULLS_LAST;
1096
        }
1097
        
1098
        @Override
1099
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
1100
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
1101
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
1102
            return other;
1103
        }
1104
        
1105
        @Override
1106
        public void accept(Visitor visitor, VisitorFilter filter) {
1107
            boolean visitChildren = true;
1108
            if (filter==null || filter.accept(this)) {
1109
                visitor.visit(this);
1110
            } else {
1111
                visitChildren = !filter.skipChildren();
1112
            }
1113
            if(visitChildren){
1114
                if (this.value!=null) {
1115
                    this.value.accept(visitor, filter);
1116
                }
1117
            }
1118
        }
1119

    
1120
        @Override
1121
        public OrderByBuilder column(String name) {
1122
            this.value = expression().variable(name);
1123
            return this;
1124
        }
1125
        
1126
        @Override
1127
        public boolean isColumn(String name) {
1128
            if(this.value instanceof ExpressionBuilder.Variable){
1129
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1130
            }
1131
            return false;
1132
        }
1133
        
1134
        @Override
1135
        public boolean isColumn(Value value) {
1136
            if(value instanceof ExpressionBuilder.Variable){
1137
                return isColumn(((ExpressionBuilder.Variable)value).name());
1138
            }
1139
            return this.value == value;
1140
        }
1141
        
1142
        @Override
1143
        public OrderByBuilder value(Value expression) {
1144
            this.value = expression;
1145
            return this;
1146
        }
1147
        
1148
        @Override
1149
        public OrderByBuilder custom(String order) {
1150
            this.custom = order;
1151
            return this;
1152
        }
1153

    
1154
        @Override
1155
        public OrderByBuilder ascending() {
1156
            this.ascending = true;
1157
            return this;
1158
        }
1159

    
1160
        @Override
1161
        public OrderByBuilder ascending(boolean asc) {
1162
            this.ascending = asc;
1163
            return this;
1164
        }
1165

    
1166
        @Override
1167
        public OrderByBuilder descending() {
1168
            this.ascending = false;
1169
            return this;
1170
        }
1171

    
1172
        @Override
1173
        public OrderByBuilder nulls(int mode) {
1174
            this.nullsMode = mode;
1175
            return this;
1176
        }
1177

    
1178
        @Override
1179
        public int getNullsMode() {
1180
            return this.nullsMode;
1181
        }
1182

    
1183
        @Override
1184
        public String toString() {
1185
            return this.toString(formatter());
1186
        }
1187

    
1188
        @Override
1189
        public String toString(Formatter<Value> formatter) {
1190
            if (formatter!=null && formatter.canApply(this)) {
1191
                return formatter.format(this);
1192
            }
1193
            if (!StringUtils.isEmpty(this.custom)) {
1194
                return this.custom;
1195
            }
1196
            String order_s = this.value.toString(formatter);
1197
            if (this.ascending) {
1198
                order_s += " ASC";
1199
            } else {
1200
                order_s += " DESC";
1201
            }
1202
            switch(this.nullsMode) {
1203
                case MODE_NULLS_NOT_SPECIFIED:
1204
                    break;
1205
                case MODE_NULLS_FIRST:
1206
                    order_s += " NULLS FIRST";
1207
                    break;
1208
                case MODE_NULLS_LAST:
1209
                default:
1210
                    order_s += " NULLS LAST";
1211
                    break;
1212
            }
1213
            return order_s;
1214
        }
1215

    
1216
        @Override
1217
        public void replace(Value target, Value replacement) {
1218
            super.replace(target, replacement);
1219
            if(target == this.value){
1220
                this.value = replacement;
1221
                return;
1222
            }
1223
            if(this.value == null){
1224
                return;
1225
            }
1226
            this.value.replace(target, replacement);
1227
        }
1228
        
1229
        
1230
    }
1231

    
1232
    public class SelectBuilderBase
1233
            extends AbstractStatement
1234
            implements SelectBuilder {
1235

    
1236
        protected FromBuilder from;
1237
        protected GeometryExpressionBuilder where;
1238
        protected long limit = -1;
1239
        protected long offset = -1;
1240
        protected List<SelectColumnBuilder> columns;
1241
        protected List<OrderByBuilder> order_by;
1242
        protected boolean distinct;
1243
        protected List<Value> groupColumn;
1244
        protected boolean check_order_and_offset = true;
1245

    
1246
        public SelectBuilderBase() {
1247
            this.columns = new ArrayList<>();
1248
            this.distinct = false;
1249
        }
1250
        @Override
1251
        public List<Value> getGroups() {
1252
            return this.groupColumn;
1253
        }
1254
        
1255
        @Override
1256
        public List<SelectColumnBuilder> getColumns() {
1257
            return Collections.unmodifiableList(this.columns);
1258
    }
1259
        
1260
        @Override
1261
        public void remove_column(String columnName) {
1262
            SelectColumnBuilder found = null;
1263
            for (SelectColumnBuilder column : columns) {
1264
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1265
                    found = column;
1266
                    break;
1267
                }
1268
                    
1269
            }
1270
            if(found!=null) {
1271
                columns.remove(found);
1272
            }
1273
        }
1274

    
1275
        @Override
1276
        public SelectBuilder group_by(Value... columns) {
1277
            if( this.groupColumn==null ) {
1278
                this.groupColumn = new ArrayList<>();
1279
            }
1280
            for (Value column : columns) {
1281
                this.groupColumn.add(column);
1282
            }
1283
            return this;
1284
        }
1285

    
1286
        @Override
1287
        public void accept(Visitor visitor, VisitorFilter filter) {
1288
            boolean visitChildren = true;
1289
            if (filter==null || filter.accept(this)) {
1290
                visitor.visit(this);
1291
            } else {
1292
                visitChildren = !filter.skipChildren();
1293
            }
1294
            if(visitChildren){
1295
                for (SelectColumnBuilder column : columns) {
1296
                    column.accept(visitor, filter);
1297
                }
1298
                if (this.has_from()) {
1299
                    this.from.accept(visitor, filter);
1300
                }
1301
                if (this.has_where()) {
1302
                    this.where.accept(visitor, filter);
1303
                }
1304
                if (this.has_order_by()) {
1305
                    for (OrderByBuilder order : order_by) {
1306
                        order.accept(visitor, filter);
1307
                    }
1308
                }
1309
                if (this.has_group_by()) {
1310
                    for (Value group : groupColumn) {
1311
                        group.accept(visitor, filter);
1312
                    }
1313
                }
1314
            }
1315
        }
1316

    
1317
        @Override
1318
        public void replace(Value target, Value replacement) {
1319
            if( this.columns!=null ) {
1320
                for (int i = 0; i < columns.size(); i++) {
1321
                    SelectColumnBuilder column = columns.get(i);
1322
                    if( column == target ) {
1323
                        columns.set(i, (SelectColumnBuilder) replacement);
1324
                    } else {
1325
                        column.replace(target, replacement);
1326
                    }
1327
                }
1328
            }
1329
            if (this.has_from()) {
1330
                if( this.from == target ) {
1331
                    this.from = (FromBuilder) replacement;
1332
                } else {
1333
                    this.from.replace(target, replacement);
1334
                }
1335
            }
1336
            if (this.has_where()) {
1337
                if( this.where == target ) {
1338
                    this.where = (GeometryExpressionBuilder) replacement;
1339
                } else if( this.where.value() == target ) {
1340
                    this.where.value(replacement);
1341
                } else {
1342
                    this.where.value().replace(target, replacement);
1343
                }
1344
            }
1345
            if (this.has_order_by()) {
1346
                for (int i = 0; i < order_by.size(); i++) {
1347
                    OrderByBuilder order = order_by.get(i);
1348
                    if( order == target ) {
1349
                        order_by.set(i, (OrderByBuilder) replacement);
1350
                    } else {
1351
                        order.replace(target, replacement);
1352
                    }
1353
                }
1354
            }
1355
            if (this.has_group_by()) {
1356
                for (int i = 0; i < groupColumn.size(); i++) {
1357
                    Value group = groupColumn.get(i);
1358
                    if( group == target ) {
1359
                        groupColumn.set(i, replacement);
1360
                    } else {
1361
                        group.replace(target, replacement);
1362
                    }
1363
                }
1364
            }
1365
        }
1366

    
1367
        @Override
1368
        public SelectBuilder distinct() {
1369
            this.distinct = true;
1370
            return this;
1371
        }
1372

    
1373
        @Override
1374
        public SelectColumnBuilder column() {
1375
            return column(createSelectColumnBuilder());
1376
        }
1377

    
1378
        @Override
1379
        public SelectColumnBuilder column(SelectColumnBuilder columnBuilder) {
1380
            this.columns.add(columnBuilder);
1381
            if( this.has_from() && !this.from().table().isEmpty() ) {
1382
                TableNameBuilder table = (TableNameBuilder) CloneableUtils.cloneQuietly(this.from().table());
1383
                columnBuilder.table(table);
1384
            }
1385
            return columnBuilder;
1386
        }
1387

    
1388
        @Override
1389
        public SelectColumnBuilder column(String name) {
1390
            for (SelectColumnBuilder column : columns) {
1391
                if (StringUtils.equals(name, column.getName())) {
1392
                    return column;
1393
                }
1394
            }
1395
            return column(createSelectColumnBuilder()).name(name);
1396
        }
1397

    
1398
        @Override
1399
        public SelectColumnBuilder getColumn(String name) {
1400
            for (SelectColumnBuilder column : columns) {
1401
                if (StringUtils.equals(name, column.getName())) {
1402
                    return column;
1403
                }
1404
            }
1405
            return null;
1406
        }
1407
        
1408
        @Override
1409
        public SelectBuilder remove_all_columns() {
1410
            this.columns = new ArrayList<>();
1411
            return this;
1412
        }
1413
        
1414
        @Override
1415
        public boolean has_column(String name) {
1416
            for (SelectColumnBuilder column : columns) {
1417
                if (StringUtils.equals(name, column.getName())) {
1418
                    return true;
1419
                }
1420
                if (StringUtils.equals(name, column.getAlias())) {
1421
                    return true;
1422
                }
1423
            }
1424
            return false;
1425
        }
1426

    
1427
        @Override
1428
        public FromBuilder from() {
1429
            if (this.from == null) {
1430
                this.from = createFromBuilder();
1431
            }
1432
            return this.from;
1433
        }
1434

    
1435
        @Override
1436
        public boolean has_from() {
1437
            return this.from != null;
1438
        }
1439

    
1440
        @Override
1441
        public GeometryExpressionBuilder where() {
1442
            if (this.where == null) {
1443
                this.where = createExpressionBuilder();
1444
            }
1445
            return this.where;
1446
        }
1447

    
1448
        @Override
1449
        public boolean has_where() {
1450
            if (this.where == null) {
1451
                return false;
1452
            }
1453
            return this.where.value() != null;
1454
        }
1455

    
1456
        @Override
1457
        public SelectBuilder limit(long limit) {
1458
            this.limit = limit;
1459
            return this;
1460
        }
1461

    
1462
        @Override
1463
        public SelectBuilder limit(Long limit) {
1464
            if (limit == null) {
1465
                this.limit = -1;
1466
            } else {
1467
                this.limit = limit;
1468
            }
1469
            return this;
1470
        }
1471

    
1472
        @Override
1473
        public boolean has_limit() {
1474
            return this.limit >= 0;
1475
        }
1476

    
1477
        @Override
1478
        public SelectBuilder offset(long offset) {
1479
            this.offset = offset;
1480
            return this;
1481
        }
1482

    
1483
        @Override
1484
        public boolean has_offset() {
1485
            return this.offset > 0;
1486
        }
1487

    
1488
        @Override
1489
        public OrderByBuilder order_by() {
1490
            if (this.order_by == null) {
1491
                this.order_by = new ArrayList<>();
1492
            }
1493
            OrderByBuilder order = createOrderByBuilder();
1494
            this.order_by.add(order);
1495
            return order;
1496
        }
1497
        
1498
        @Override
1499
        public OrderByBuilder getOrderBy(Value column) {
1500
            if(this.order_by == null){
1501
                return null;
1502
            }
1503
            for (OrderByBuilder orderByBuilder : this.order_by) {
1504
                if(orderByBuilder.isColumn(column)){
1505
                    return orderByBuilder;
1506
                }
1507
            }
1508
            return null;
1509
        }
1510
        
1511
        @Override
1512
        public OrderByBuilder getOrderBy(String column) {
1513
            if(this.order_by == null){
1514
                return null;
1515
            }
1516
            for (OrderByBuilder orderByBuilder : this.order_by) {
1517
                if(orderByBuilder.isColumn(column)){
1518
                    return orderByBuilder;
1519
                }
1520
            }
1521
            return null;
1522
        }
1523
        
1524
        @Override
1525
        public boolean isGroupBy(String column) {
1526
            if(this.groupColumn == null){
1527
                return false;
1528
            }
1529
            for (Value group : this.groupColumn) {
1530
                if(group instanceof Variable){
1531
                    if(StringUtils.equalsIgnoreCase(((Variable)group).name(), column)){
1532
                        return true;
1533
                    }
1534
                }
1535
            }
1536
            return false;
1537
        }
1538

    
1539
        @Override
1540
        public boolean has_order_by() {
1541
            if (this.order_by == null) {
1542
                return false;
1543
            }
1544
            return !this.order_by.isEmpty();
1545
        }
1546
        
1547
        @Override
1548
        public boolean has_group_by() {
1549
            if (this.groupColumn == null) {
1550
                return false;
1551
            }
1552
            return !this.groupColumn.isEmpty();
1553
        }
1554
        
1555
        @Override
1556
        public boolean has_aggregate_functions() {
1557
            if (this.columns == null || this.columns.isEmpty() ) {
1558
                return false;
1559
            }
1560
            for (SelectColumnBuilder column : this.columns) {
1561
                if( column.isAggregateFunction() ) {
1562
                    return true;
1563
                }
1564
            }
1565
            return false;
1566
        }
1567
        
1568
        @Override
1569
        public void disable_check_order_and_offset() {
1570
          this.check_order_and_offset = false;
1571
        }
1572
        
1573
        protected boolean isValid(StringBuilder message) {
1574
            if (message == null) {
1575
                message = new StringBuilder();
1576
            }
1577
            if( this.check_order_and_offset ) {
1578
              if (this.has_offset() && !this.has_order_by()) {
1579
                  // Algunos gestores de BBDD requieren que se especifique un
1580
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1581
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1582
                  // siempre.
1583
                  message.append("Can't use OFFSET without an ORDER BY.");
1584
                  return false;
1585
              }
1586
            }
1587
            return true;
1588
        }
1589

    
1590
        @Override
1591
        public String toString() {
1592
            return this.toString(formatter());
1593
        }
1594

    
1595
        @Override
1596
        public String toString(Formatter<Value> formatter) {
1597
            if (formatter!=null && formatter.canApply(this)) {
1598
                return formatter.format(this);
1599
            }
1600
            StringBuilder builder = new StringBuilder();
1601
            if (!this.isValid(builder)) {
1602
                throw new IllegalStateException(builder.toString());
1603
            }
1604
            builder.append("SELECT ");
1605
            if (this.distinct) {
1606
                builder.append("DISTINCT ");
1607
            }
1608
            boolean first = true;
1609
            for (SelectColumnBuilder column : columns) {
1610
                if (first) {
1611
                    first = false;
1612
                } else {
1613
                    builder.append(", ");
1614
                }
1615
                builder.append(column.toString(formatter));
1616
            }
1617

    
1618
            if (this.has_from()) {
1619
                builder.append(" FROM ");
1620
                builder.append(this.from.toString(formatter));
1621
            }
1622
            if (this.has_where()) {
1623
                builder.append(" WHERE ");
1624
                builder.append(this.where.toString(formatter));
1625
            }
1626
            if( this.has_group_by() ) {
1627
                builder.append(" GROUP BY ");
1628
                builder.append(this.groupColumn.get(0).toString(formatter));
1629
                for (int i = 1; i < groupColumn.size(); i++) {
1630
                    builder.append(", ");
1631
                    builder.append(this.groupColumn.get(i).toString(formatter));
1632
                }
1633
            }
1634
            if (this.has_order_by()) {
1635
                builder.append(" ORDER BY ");
1636
                first = true;
1637
                for (OrderByBuilder item : this.order_by) {
1638
                    if (first) {
1639
                        first = false;
1640
                    } else {
1641
                        builder.append(", ");
1642
                    }
1643
                    builder.append(item.toString(formatter));
1644
                }
1645
            }
1646

    
1647
            if (this.has_limit()) {
1648
                builder.append(" LIMIT ");
1649
                builder.append(this.limit);
1650
            }
1651
            if (this.has_offset()) {
1652
                builder.append(" OFFSET ");
1653
                builder.append(this.offset);
1654
            }
1655
            return builder.toString();
1656

    
1657
        }
1658
    }
1659

    
1660
    public class DropTableBuilderBase
1661
            extends AbstractStatement
1662
            implements DropTableBuilder {
1663

    
1664
        protected TableNameBuilder table;
1665

    
1666
        @Override
1667
        public TableNameBuilder table() {
1668
            if (table == null) {
1669
                table = createTableNameBuilder();
1670
            }
1671
            return table;
1672
        }
1673

    
1674
        @Override
1675
        public void accept(Visitor visitor, VisitorFilter filter) {
1676
            boolean visitChildren = true;
1677
            if (filter==null || filter.accept(this)) {
1678
                visitor.visit(this);
1679
            } else {
1680
                visitChildren = !filter.skipChildren();
1681
            }
1682
            if(visitChildren){
1683
                this.table.accept(visitor, filter);
1684
            }
1685
        }
1686

    
1687
        @Override
1688
        public String toString() {
1689
            return this.toString(formatter());
1690
        }
1691

    
1692
        @Override
1693
        public String toString(Formatter<Value> formatter) {
1694
            if (formatter!=null && formatter.canApply(this)) {
1695
                return formatter.format(this);
1696
            }
1697
            StringBuilder builder = new StringBuilder();
1698
            boolean first = true;
1699
            for (String sql : toStrings(formatter)) {
1700
                if (StringUtils.isEmpty(sql)) {
1701
                    continue;
1702
                }
1703
                if (first) {
1704
                    first = false;
1705
                } else {
1706
                    builder.append("; ");
1707
                }
1708
                builder.append(sql);
1709
            }
1710
            return builder.toString();
1711
        }
1712

    
1713
        @Override
1714
        public List<String> toStrings() {
1715
            return this.toStrings(formatter());
1716
        }
1717

    
1718
        @Override
1719
        public List<String> toStrings(Formatter formatter) {
1720
            List<String> sqls = new ArrayList<>();
1721

    
1722
            sqls.add(
1723
                    MessageFormat.format(
1724
                            STMT_DROP_TABLE_table,
1725
                            this.table.toString(formatter)
1726
                    )
1727
            );
1728
            String sql;
1729
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1730
                if (this.table.has_schema()) {
1731
                    sql = MessageFormat.format(
1732
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1733
                            as_string(this.table.getSchema()),
1734
                            as_string(this.table.getName())
1735
                    );
1736
                } else {
1737
                    sql = MessageFormat.format(
1738
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1739
                            as_identifier(this.table.getName())
1740
                    );
1741
                }
1742
                if (!StringUtils.isEmpty(sql)) {
1743
                    sqls.add(sql);
1744
                }
1745
            }
1746
            return sqls;
1747
        }
1748
    }
1749

    
1750
    public class GrantRoleBuilderBase
1751
            extends AbstractStatementPart
1752
            implements GrantRoleBuilder {
1753

    
1754
        protected TableNameBuilder table;
1755
        protected String role;
1756
        protected Set<Privilege> privileges;
1757

    
1758
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1759
            this.table = table;
1760
            this.role = role;
1761
            this.privileges = new HashSet<>();
1762
        }
1763
        
1764
        @Override
1765
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1766
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1767
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1768
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1769
            
1770
            return other;
1771
        }
1772

    
1773
        @Override
1774
        public GrantRoleBuilder privilege(Privilege privilege) {
1775
            privileges.add(privilege);
1776
            return this;
1777
        }
1778

    
1779
        @Override
1780
        public GrantRoleBuilder select() {
1781
            privileges.add(Privilege.SELECT);
1782
            return this;
1783
        }
1784

    
1785
        @Override
1786
        public GrantRoleBuilder update() {
1787
            privileges.add(Privilege.UPDATE);
1788
            return this;
1789
        }
1790

    
1791
        @Override
1792
        public GrantRoleBuilder insert() {
1793
            privileges.add(Privilege.INSERT);
1794
            return this;
1795
        }
1796

    
1797
        @Override
1798
        public GrantRoleBuilder delete() {
1799
            privileges.add(Privilege.DELETE);
1800
            return this;
1801
        }
1802

    
1803
        @Override
1804
        public GrantRoleBuilder truncate() {
1805
            privileges.add(Privilege.TRUNCATE);
1806
            return this;
1807
        }
1808

    
1809
        @Override
1810
        public GrantRoleBuilder reference() {
1811
            privileges.add(Privilege.REFERENCE);
1812
            return this;
1813
        }
1814

    
1815
        @Override
1816
        public GrantRoleBuilder trigger() {
1817
            privileges.add(Privilege.TRIGGER);
1818
            return this;
1819
        }
1820

    
1821
        @Override
1822
        public GrantRoleBuilder all() {
1823
            privileges.add(Privilege.ALL);
1824
            return this;
1825
        }
1826

    
1827
        protected String getPrivilegeName(Privilege privilege) {
1828
            switch (privilege) {
1829
                case DELETE:
1830
                    return "DELETE";
1831
                case INSERT:
1832
                    return "INSERT";
1833
                case REFERENCE:
1834
                    return "REFERENCE";
1835
                case SELECT:
1836
                    return "SELECT";
1837
                case TRIGGER:
1838
                    return "TRIGGER";
1839
                case TRUNCATE:
1840
                    return "TRUNCATE";
1841
                case UPDATE:
1842
                    return "UPDATE";
1843
                case ALL:
1844
                default:
1845
                    return "ALL";
1846
            }
1847
        }
1848

    
1849
        @Override
1850
        public String toString() {
1851
            return this.toString(formatter());
1852
        }
1853

    
1854
        @Override
1855
        public String toString(Formatter<Value> formatter) {
1856
            if (formatter!=null && formatter.canApply(this)) {
1857
                return formatter.format(this);
1858
            }
1859
            StringBuilder builder = new StringBuilder();
1860
            boolean first = true;
1861
            for (Privilege privilege : privileges) {
1862
                if (first) {
1863
                    first = false;
1864
                } else {
1865
                    builder.append(", ");
1866
                }
1867
                builder.append(this.getPrivilegeName(privilege));
1868
            }
1869
            String sql = MessageFormat.format(
1870
                    STMT_GRANT_privileges_ON_table_TO_role,
1871
                    builder.toString(),
1872
                    table.toString(formatter),
1873
                    role
1874
            );
1875
            return sql;
1876
        }
1877
    }
1878

    
1879
    public class GrantBuilderBase
1880
            extends AbstractStatement
1881
            implements GrantBuilder {
1882

    
1883
        protected TableNameBuilder table;
1884
        protected Map<String, GrantRoleBuilder> roles;
1885

    
1886
        public GrantBuilderBase() {
1887
            this.roles = new HashMap<>();
1888
        }
1889

    
1890
        @Override
1891
        public TableNameBuilder table() {
1892
            if (table == null) {
1893
                table = createTableNameBuilder();
1894
            }
1895
            return table;
1896
        }
1897

    
1898
        @Override
1899
        public void accept(Visitor visitor, VisitorFilter filter) {
1900
            boolean visitChildren = true;
1901
            if (filter==null || filter.accept(this)) {
1902
                visitor.visit(this);
1903
            } else {
1904
                visitChildren = !filter.skipChildren();
1905
            }
1906
            if(visitChildren){
1907
                if (this.table != null) {
1908
                    this.table.accept(visitor, filter);
1909
                }
1910
            }
1911
        }
1912

    
1913
        @Override
1914
        public GrantRoleBuilder role(String role) {
1915
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1916
            if (roleBuilder == null) {
1917
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1918
                this.roles.put(role, roleBuilder);
1919
            }
1920
            return roleBuilder;
1921
        }
1922

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

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

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

    
1954
        @Override
1955
        public List<String> toStrings(Formatter formatter) {
1956
            List<String> sqls = new ArrayList<>();
1957
            for (GrantRoleBuilder role : roles.values()) {
1958
                sqls.add(role.toString(formatter));
1959
            }
1960
            return sqls;
1961
        }
1962
    }
1963

    
1964
    public class UpdateColumnBuilderBase
1965
            extends InsertColumnBuilderBase
1966
            implements UpdateColumnBuilder {
1967

    
1968
        public UpdateColumnBuilderBase() {
1969
            super();
1970
        }
1971

    
1972
        @Override
1973
        public UpdateColumnBuilder name(String name) {
1974
            return (UpdateColumnBuilder) super.name(name);
1975
        }
1976

    
1977
        @Override
1978
        public UpdateColumnBuilder with_value(Value value) {
1979
            return (UpdateColumnBuilder) super.with_value(value);
1980
        }
1981

    
1982
    }
1983

    
1984
    public class UpdateBuilderBase
1985
            extends AbstractStatement
1986
            implements UpdateBuilder {
1987

    
1988
        protected GeometryExpressionBuilder where;
1989
        protected List<UpdateColumnBuilder> columns;
1990
        protected TableNameBuilder table;
1991

    
1992
        public UpdateBuilderBase() {
1993
            this.columns = new ArrayList<>();
1994
        }
1995

    
1996
        @Override
1997
        public void accept(Visitor visitor, VisitorFilter filter) {
1998
            boolean visitChildren = true;
1999
            if (filter==null || filter.accept(this)) {
2000
                visitor.visit(this);
2001
            } else {
2002
                visitChildren = !filter.skipChildren();
2003
            }
2004
            if(visitChildren){
2005
                if (this.table != null) {
2006
                    this.table.accept(visitor, filter);
2007
                }
2008
                for (UpdateColumnBuilder column : columns) {
2009
                    column.accept(visitor, filter);
2010
                }
2011
                if (this.has_where()) {
2012
                    this.where.accept(visitor, filter);
2013
                }
2014
            }
2015
        }
2016

    
2017
        @Override
2018
        public GeometryExpressionBuilder where() {
2019
            if (this.where == null) {
2020
                this.where = createExpressionBuilder();
2021
            }
2022
            return this.where;
2023
        }
2024

    
2025
        @Override
2026
        public TableNameBuilder table() {
2027
            if (table == null) {
2028
                table = createTableNameBuilder();
2029
            }
2030
            return table;
2031
        }
2032

    
2033
        @Override
2034
        public UpdateColumnBuilder column() {
2035
            UpdateColumnBuilder column = createUpdateColumnBuilder();
2036
            this.columns.add(column);
2037
            return column;
2038
        }
2039

    
2040
        @Override
2041
        public boolean has_where() {
2042
            return this.where != null;
2043
        }
2044

    
2045
        @Override
2046
        public String toString() {
2047
            return this.toString(formatter());
2048
        }
2049

    
2050
        @Override
2051
        public String toString(Formatter<Value> formatter) {
2052
            if (formatter!=null && formatter.canApply(this)) {
2053
                return formatter.format(this);
2054
            }
2055
            /*
2056
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
2057
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
2058
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
2059
             * output_expression [ AS output_name ] [, ...] ]
2060
             */
2061
            StringBuilder columnsAndValues = new StringBuilder();
2062

    
2063
            boolean first = true;
2064
            for (UpdateColumnBuilder column : columns) {
2065
                if (first) {
2066
                    first = false;
2067
                } else {
2068
                    columnsAndValues.append(", ");
2069
                }
2070
                columnsAndValues.append(as_identifier(column.getName()));
2071
                columnsAndValues.append(" = ");
2072
                columnsAndValues.append(column.getValue().toString(formatter));
2073
            }
2074

    
2075
            String sql;
2076
            if (this.has_where()) {
2077
                sql = MessageFormat.format(
2078
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
2079
                        this.table.toString(formatter),
2080
                        columnsAndValues.toString(),
2081
                        this.where.toString(formatter)
2082
                );
2083
            } else {
2084
                sql = MessageFormat.format(
2085
                        STMT_UPDATE_table_SET_columnsAndValues,
2086
                        this.table.toString(formatter),
2087
                        columnsAndValues.toString()
2088
                );
2089
            }
2090
            return sql;
2091
        }
2092
    }
2093

    
2094
    public class DeleteBuilderBase
2095
            extends AbstractStatement
2096
            implements DeleteBuilder {
2097

    
2098
        protected GeometryExpressionBuilder where;
2099
        protected TableNameBuilder table;
2100

    
2101
        public DeleteBuilderBase() {
2102
        }
2103

    
2104
        @Override
2105
        public void accept(Visitor visitor, VisitorFilter filter) {
2106
            boolean visitChildren = true;
2107
            if (filter==null || filter.accept(this)) {
2108
                visitor.visit(this);
2109
            } else {
2110
                visitChildren = !filter.skipChildren();
2111
            }
2112
            if(visitChildren){
2113
                if (this.table != null) {
2114
                    this.table.accept(visitor, filter);
2115
                }
2116
                if (this.has_where()) {
2117
                    this.where.accept(visitor, filter);
2118
                }
2119
            }
2120
        }
2121

    
2122
        @Override
2123
        public GeometryExpressionBuilder where() {
2124
            if (this.where == null) {
2125
                this.where = createExpressionBuilder();
2126
            }
2127
            return this.where;
2128
        }
2129

    
2130
        @Override
2131
        public TableNameBuilder table() {
2132
            if (table == null) {
2133
                table = createTableNameBuilder();
2134
            }
2135
            return table;
2136
        }
2137

    
2138
        @Override
2139
        public boolean has_where() {
2140
            return this.where != null;
2141
        }
2142

    
2143
        @Override
2144
        public String toString() {
2145
            return this.toString(formatter());
2146
        }
2147

    
2148
        @Override
2149
        public String toString(Formatter<Value> formatter) {
2150
            if (formatter!=null && formatter.canApply(this)) {
2151
                return formatter.format(this);
2152
            }
2153
            /*
2154
             * DELETE FROM table_name
2155
             * WHERE some_column=some_value; 
2156
             */
2157
            String sql;
2158
            if (this.has_where()) {
2159
                sql = MessageFormat.format(
2160
                        STMT_DELETE_FROM_table_WHERE_expresion,
2161
                        this.table.toString(formatter),
2162
                        this.where.toString(formatter)
2163
                );
2164
            } else {
2165
                sql = MessageFormat.format(
2166
                        STMT_DELETE_FROM_table,
2167
                        this.table.toString(formatter)
2168
                );
2169
            }
2170
            return sql;
2171
        }
2172
    }
2173

    
2174
    public class CreateIndexBuilderBase
2175
            extends AbstractStatement
2176
            implements CreateIndexBuilder {
2177

    
2178
        protected boolean ifNotExist = false;
2179
        protected boolean isUnique = false;
2180
        protected String indexName;
2181
        protected boolean isSpatial = false;
2182
        protected TableNameBuilder table;
2183
        protected final List<String> columns;
2184
        protected FeatureType type;
2185

    
2186
        public CreateIndexBuilderBase() {
2187
            this.columns = new ArrayList<>();
2188
        }
2189

    
2190
        @Override
2191
        public CreateIndexBuilder unique() {
2192
            this.isUnique = true;
2193
            return this;
2194
        }
2195

    
2196
        @Override
2197
        public CreateIndexBuilder if_not_exist() {
2198
            this.ifNotExist = true;
2199
            return this;
2200
        }
2201

    
2202
        @Override
2203
        public CreateIndexBuilder name(String name) {
2204
            this.indexName = name;
2205
            return this;
2206
        }
2207

    
2208
        @Override
2209
        public CreateIndexBuilder name(String tableName, String columnName) {
2210
            this.indexName = tableName + "_IDX_" + columnName;
2211
            return this;
2212
        }
2213

    
2214
        @Override
2215
        public CreateIndexBuilder spatial() {
2216
            this.isSpatial = true;
2217
            return this;
2218
        }
2219

    
2220
        @Override
2221
        public CreateIndexBuilder column(String name) {
2222
            this.columns.add(name);
2223
            return this;
2224
        }
2225

    
2226
        @Override
2227
        public TableNameBuilder table() {
2228
            if (table == null) {
2229
                table = createTableNameBuilder();
2230
            }
2231
            return table;
2232
        }
2233

    
2234
        @Override
2235
        public void setFeatureType(FeatureType type) {
2236
            this.type = type;
2237
        }
2238

    
2239
        @Override
2240
        public void accept(Visitor visitor, VisitorFilter filter) {
2241
            boolean visitChildren = true;
2242
            if (filter==null || filter.accept(this)) {
2243
                visitor.visit(this);
2244
            } else {
2245
                visitChildren = !filter.skipChildren();
2246
            }
2247
            if(visitChildren){
2248
                if (this.table != null) {
2249
                    this.table.accept(visitor, filter);
2250
                }
2251
            }
2252
        }
2253

    
2254
        @Override
2255
        public String toString() {
2256
            return this.toString(formatter());
2257
        }
2258

    
2259
        @Override
2260
        public String toString(Formatter<Value> formatter) {
2261
            if (formatter!=null && formatter.canApply(this)) {
2262
                return formatter.format(this);
2263
            }
2264
            StringBuilder builder = new StringBuilder();
2265
            boolean first = true;
2266
            for (String sql : toStrings(formatter)) {
2267
                if (StringUtils.isEmpty(sql)) {
2268
                    continue;
2269
                }
2270
                if (first) {
2271
                    first = false;
2272
                } else {
2273
                    builder.append("; ");
2274
                }
2275
                builder.append(sql);
2276
            }
2277
            return builder.toString();
2278
        }
2279

    
2280
        @Override
2281
        public List<String> toStrings() {
2282
            return this.toStrings(formatter());
2283
        }
2284

    
2285
        @Override
2286
        public List<String> toStrings(Formatter formatter) {
2287
            StringBuilder builder = new StringBuilder();
2288
            builder.append("CREATE ");
2289
            if (this.isUnique) {
2290
                builder.append("UNIQUE ");
2291
            }
2292
            builder.append("INDEX ");
2293
            if (this.ifNotExist) {
2294
                builder.append("IF NOT EXISTS ");
2295
            }
2296
            builder.append(as_identifier(this.indexName));
2297
            builder.append(" ON ");
2298
            builder.append(this.table.toString(formatter));
2299
            if (this.isSpatial) {
2300
                builder.append(" USING GIST ");
2301
            }
2302
            builder.append(" ( ");
2303
            boolean is_first_column = true;
2304
            for (String column : this.columns) {
2305
                if (is_first_column) {
2306
                    is_first_column = false;
2307
                } else {
2308
                    builder.append(", ");
2309
                }
2310
                builder.append(column);
2311
            }
2312
            builder.append(" )");
2313

    
2314
            List<String> sqls = new ArrayList<>();
2315
            sqls.add(builder.toString());
2316
            return sqls;
2317
        }
2318

    
2319
    }
2320

    
2321
    public class DropIndexBuilderBase
2322
            extends AbstractStatement
2323
            implements DropIndexBuilder {
2324

    
2325
        protected boolean ifExist = false;
2326
        protected String indexName;
2327

    
2328
        public DropIndexBuilderBase() {
2329
        }
2330

    
2331
        @Override
2332
        public DropIndexBuilder if_exist() {
2333
            this.ifExist = true;
2334
            return this;
2335
        }
2336

    
2337
        @Override
2338
        public DropIndexBuilder name(String name) {
2339
            this.indexName = name;
2340
            return this;
2341
        }
2342

    
2343
        @Override
2344
        public DropIndexBuilder name(String tableName, String columnName) {
2345
            this.indexName = tableName + "_IDX_" + columnName;
2346
            return this;
2347
        }
2348

    
2349
        @Override
2350
        public String toString() {
2351
            return this.toString(formatter());
2352
        }
2353

    
2354
        @Override
2355
        public String toString(Formatter<Value> formatter) {
2356
            if (formatter!=null && formatter.canApply(this)) {
2357
                return formatter.format(this);
2358
            }
2359
            StringBuilder builder = new StringBuilder();
2360
            boolean first = true;
2361
            for (String sql : toStrings(formatter)) {
2362
                if (StringUtils.isEmpty(sql)) {
2363
                    continue;
2364
                }
2365
                if (first) {
2366
                    first = false;
2367
                } else {
2368
                    builder.append("; ");
2369
                }
2370
                builder.append(sql);
2371
            }
2372
            return builder.toString();
2373
        }
2374

    
2375
        @Override
2376
        public List<String> toStrings() {
2377
            return this.toStrings(formatter());
2378
        }
2379

    
2380
        @Override
2381
        public List<String> toStrings(Formatter formatter) {
2382
            StringBuilder builder = new StringBuilder();
2383
            builder.append("DROP INDEX ");
2384
            if (this.ifExist) {
2385
                builder.append("IF EXISTS ");
2386
            }
2387
            builder.append(as_identifier(this.indexName));
2388
            List<String> sqls = new ArrayList<>();
2389
            sqls.add(builder.toString());
2390
            return sqls;
2391
        }
2392

    
2393
    }
2394

    
2395
    public class AlterTableBuilderBase
2396
            extends AbstractStatement
2397
            implements AlterTableBuilder {
2398
             
2399
        protected TableNameBuilder table;
2400
        protected List<String> drops;
2401
        protected List<ColumnDescriptor> adds;
2402
        
2403
        // alters debera dejarse de usar en favor de operations
2404
        @Deprecated
2405
        protected List<ColumnDescriptor> alters;
2406
        protected List<Pair<Bitmask,ColumnDescriptor>> operations;
2407
        
2408
        protected List<Pair<String, String>> renames;
2409
        protected String drop_primary_key_column;
2410
        protected final SQLBuilderBase sqlbuilder;
2411

    
2412
        public AlterTableBuilderBase(SQLBuilderBase sqlbuilder) {
2413
            this.sqlbuilder = sqlbuilder;
2414
            this.drops = new ArrayList<>();
2415
            this.adds = new ArrayList<>();
2416
            this.alters = new ArrayList<>();
2417
            this.operations = new ArrayList<>();
2418
            this.renames = new ArrayList<>();
2419
        }
2420

    
2421
        public List<Pair<Bitmask,ColumnDescriptor>> getOperations() {
2422
            return this.operations;
2423
        }
2424
        
2425
        @Override
2426
        public boolean isEmpty() {
2427
            return this.drops.isEmpty()
2428
                    && this.adds.isEmpty()
2429
                    && this.alters.isEmpty()
2430
                    && this.operations.isEmpty()
2431
                    && this.renames.isEmpty();
2432
        }
2433

    
2434
        @Override
2435
        public void accept(Visitor visitor, VisitorFilter filter) {
2436
            boolean visitChildren = true;
2437
            if (filter==null || filter.accept(this)) {
2438
                visitor.visit(this);
2439
            } else {
2440
                visitChildren = !filter.skipChildren();
2441
            }
2442
            if(visitChildren){
2443
                if (this.table != null) {
2444
                    this.table.accept(visitor, filter);
2445
                }
2446
            }
2447
        }
2448

    
2449
        @Override
2450
        public TableNameBuilder table() {
2451
            if (table == null) {
2452
                table = createTableNameBuilder();
2453
            }
2454
            return table;
2455
        }
2456

    
2457
        @Override
2458
        public AlterTableBuilder drop_column(String columnName) {
2459
            this.drops.add(columnName);
2460
            return this;
2461
        }
2462

    
2463
        @Override
2464
        public AlterTableBuilder drop_primary_key(String columnName) {
2465
            this.drop_primary_key_column = columnName;
2466
            return this;
2467
        }
2468

    
2469
        @Override
2470
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2471
            this.adds.add(new ColumnDescriptorBase(fad));
2472
            return this;
2473
        }
2474

    
2475
        @Override
2476
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue, boolean allowIndexDuplicateds) {
2477
            if (isPk || isAutomatic) {
2478
                allowNulls = false;
2479
            }
2480
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds));
2481
            return this;
2482
        }
2483

    
2484
        @Override
2485
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2486
            if (StringUtils.isEmpty(columnName)) {
2487
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2488
            }
2489
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2490
            return this;
2491
        }
2492

    
2493
        @Override
2494
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2495
            if (StringUtils.isEmpty(columnName)) {
2496
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2497
            }
2498
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2499
            return this;
2500
        }
2501

    
2502
        protected void update_or_add_alters(ColumnDescriptorBase column) {
2503
            int i = 0;
2504
            for (; i < alters.size(); i++) {
2505
                ColumnDescriptor prevColumn = alters.get(i);
2506
                if( prevColumn.getName().equalsIgnoreCase(column.getName()) ) {
2507
                    // Si ya existia la actualizamos
2508
                    alters.set(i, column);
2509
                    break;
2510
                }
2511
                
2512
            }
2513
            if( i >= alters.size() ) {
2514
                // Si no existis la a?adimos
2515
                this.alters.add(column);
2516
            }
2517
        }
2518
        
2519
        @Override
2520
        public AlterTableBuilder alter_column(Bitmask operation, FeatureAttributeDescriptor fad) {
2521
            ColumnDescriptorBase column = new ColumnDescriptorBase(fad);
2522
            update_or_add_alters(column);
2523
            if( operation==null ) {
2524
                operation = Bitmask.createBitmask(0);
2525
            }
2526
            if( operation.isEmpty() ) {
2527
                operation.setBit(ALTER_COLUMN_ALL);
2528
            }
2529
            this.operations.add(new ImmutablePair<>(operation,column));
2530
            return this;
2531
        }
2532

    
2533
        @Override
2534
        public AlterTableBuilder alter_column(Bitmask operation, String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue, boolean allowIndexDuplicateds) {
2535
            if ( (isPk || isAutomatic) && allowNulls) {
2536
                allowNulls = false;
2537
                operation.setBit(ALTER_COLUMN_SET_NULL);
2538
            }
2539
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds);
2540
            update_or_add_alters(column);
2541
            if( operation == null ) {
2542
                operation = Bitmask.createBitmask(0);
2543
            }
2544
            if( operation.isEmpty() ) {
2545
                operation.setBit(ALTER_COLUMN_ALL);
2546
            }
2547
            this.operations.add(new ImmutablePair<>(operation,column));
2548
            return this;
2549
        }
2550

    
2551
//        @Override
2552
//        public AlterTableBuilder alter_column(Bitmask operation,String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2553
//            if ( (isPk || isAutomatic) && allowNulls) {
2554
//                allowNulls = false;
2555
//                operation.setBit(ALTER_COLUMN_SET_NULL);
2556
//            }
2557
//            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue);
2558
//            update_or_add_alters(column);
2559
//            this.operations.add(new ImmutablePair<>(operation,column));
2560
//            return this;
2561
//        }
2562

    
2563
        @Override
2564
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2565
            if (StringUtils.isEmpty(columnName)) {
2566
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2567
            }
2568
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls);
2569
            update_or_add_alters(column);
2570
            if( operation == null ) {
2571
                operation = Bitmask.createBitmask(0);
2572
            }
2573
            if( operation.isEmpty() ) {
2574
                operation.setBit(ALTER_COLUMN_ALL);
2575
            }
2576
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2577
            this.operations.add(new ImmutablePair<>(operation,column));
2578
            return this;
2579
        }
2580

    
2581
        @Override
2582
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2583
            if (StringUtils.isEmpty(columnName)) {
2584
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2585
            }
2586
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls);
2587
            update_or_add_alters(column);
2588
            if( operation == null ) {
2589
                operation = Bitmask.createBitmask(0);
2590
            }
2591
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2592
            this.operations.add(new ImmutablePair<>(operation,column));
2593
            return this;
2594
        }
2595

    
2596
        @Override
2597
        public AlterTableBuilder rename_column(String source, String target) {
2598
            this.renames.add(new ImmutablePair(source, target));
2599
            return this;
2600
        }
2601

    
2602
        protected String getConstrainName(String constrainType, String columnName) {
2603
            return this.sqlbuilder.getConstrainName(table, columnName, constrainType);
2604
        }
2605

    
2606
        protected List<String> alter_table_add_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2607
            // ALTER TABLE table_name ADD CONSTRAINT IF NOT EXISTS constraint_name PRIMARY KEY(column_name)
2608
            List<String> sqls = new ArrayList<>();
2609
            StringBuilder builder = new StringBuilder();
2610
            builder.append("ALTER TABLE ");
2611
            builder.append(this.table.toString(formatter));
2612
            builder.append(" ADD CONSTRAINT ");
2613
            builder.append("IF NOT EXISTS ");
2614
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2615
            builder.append(" PRIMARY KEY( ");
2616
            builder.append(as_identifier(column.getName()));
2617
            builder.append(" )");
2618
            sqls.add(builder.toString());
2619
            return sqls;
2620
        }
2621

    
2622
        protected List<String> alter_table_drop_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2623
            // ALTER TABLE table_name DROP CONSTRAINT constraint_name
2624
            StringBuilder builder = new StringBuilder();
2625
            builder.append("ALTER TABLE ");
2626
            builder.append(this.table.toString(formatter));
2627
            builder.append(" DROP CONSTRAINT ");
2628
            builder.append("IF EXISTS ");
2629
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2630
            return Collections.singletonList(builder.toString());
2631
        }
2632
        
2633
        protected List<String> create_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2634
            CreateIndexBuilder createIndex = this.sqlbuilder.createCreateIndexBuilder();
2635
            if( column.isGeometry() ) {
2636
                createIndex.spatial();
2637
            }
2638
            createIndex.if_not_exist();
2639
            createIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2640
            createIndex.column(column.getName());
2641
            createIndex.table()
2642
                    .database(this.table.getDatabase())
2643
                    .schema(this.table.getSchema())
2644
                    .name(this.table.getName()
2645
            );
2646
            if(!column.allowIndexDuplicateds()){
2647
                createIndex.unique();
2648
            }
2649
            return createIndex.toStrings();
2650
        }
2651

    
2652
        protected List<String> drop_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2653
            DropIndexBuilder dropIndex = this.sqlbuilder.createDropIndexBuilder();
2654
            dropIndex.if_exist();
2655
            dropIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2656
            return dropIndex.toStrings();
2657
        }
2658

    
2659
        protected List<String> alter_table_alter_column_set_data_type_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2660
            StringBuilder builder = new StringBuilder();
2661
            builder.append("ALTER TABLE ");
2662
            builder.append(this.table.toString(formatter));
2663
            builder.append(" ALTER COLUMN ");
2664
            builder.append(as_identifier(column.getName()));
2665
            builder.append(" SET DATA TYPE ");
2666
            if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2667
                builder.append(" SERIAL");
2668
            } else {
2669
                builder.append(
2670
                        sqltype(
2671
                                column.getType(),
2672
                                column.getSize(),
2673
                                column.getPrecision(),
2674
                                column.getScale(),
2675
                                column.getGeometryType(),
2676
                                column.getGeometrySubtype()
2677
                        )
2678
                );
2679
            }
2680
            return Collections.singletonList(builder.toString());
2681
        }
2682
        
2683
        protected List<String> alter_table_alter_column_set_default_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2684
            StringBuilder builder = new StringBuilder();
2685
            builder.append("ALTER TABLE ");
2686
            builder.append(this.table.toString(formatter));
2687
            builder.append(" ALTER COLUMN ");
2688
            builder.append(as_identifier(column.getName()));
2689
            if (column.getDefaultValue() == null) {
2690
                if (column.allowNulls()) {
2691
                    builder.append(" SET DEFAULT NULL");
2692
                } else {
2693
                    builder.append(" DROP DEFAULT");
2694
                }
2695
            } else {
2696
                builder.append(" SET DEFAULT '");
2697
                builder.append(column.getDefaultValue().toString());
2698
                builder.append("'");
2699
            }
2700
            return Collections.singletonList(builder.toString());
2701
        }
2702

    
2703
        protected List<String> alter_table_alter_column_set_null_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2704
            StringBuilder builder = new StringBuilder();
2705
            builder.append("ALTER TABLE ");
2706
            builder.append(this.table.toString(formatter));
2707
            builder.append(" ALTER COLUMN ");
2708
            builder.append(as_identifier(column.getName()));
2709
            if (column.allowNulls()) {
2710
                builder.append(" SET NULL");
2711
            } else {
2712
                builder.append(" SET NOT NULL");
2713
            }
2714
            return Collections.singletonList(builder.toString());
2715
        }
2716

    
2717
        protected List<String> alter_table_drop_column_sqls(Formatter<Value> formatter, String columnName) {
2718
            StringBuilder builder = new StringBuilder();
2719
            builder.append("ALTER TABLE ");
2720
            builder.append(this.table.toString(formatter));
2721
            builder.append(" DROP COLUMN ");
2722
            builder.append(" IF EXISTS ");
2723
            builder.append(as_identifier(columnName));
2724
            return Collections.singletonList(builder.toString());
2725
        }
2726

    
2727
        protected List<String> alter_table_add_column_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2728
            List<String> sqls = new ArrayList<>();
2729
            StringBuilder builder = new StringBuilder();
2730
            builder.append("ALTER TABLE ");
2731
            builder.append(this.table.toString(formatter));
2732
            builder.append(" ADD COLUMN ");
2733
            builder.append(as_identifier(column.getName()));
2734
            builder.append(" ");
2735
            if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2736
                builder.append(" SERIAL");
2737
            } else {
2738
                builder.append(
2739
                        sqltype(
2740
                                column.getType(),
2741
                                column.getSize(),
2742
                                column.getPrecision(),
2743
                                column.getScale(),
2744
                                column.getGeometryType(),
2745
                                column.getGeometrySubtype()
2746
                        )
2747
                );
2748
            }
2749
            if (column.getDefaultValue() == null) {
2750
                if (column.allowNulls()) {
2751
                    builder.append(" DEFAULT NULL");
2752
                }
2753
            } else {
2754
                builder.append(" DEFAULT '");
2755
                builder.append(Objects.toString(column.getDefaultValue(),""));
2756
                builder.append("'");
2757
            }
2758
            if (column.allowNulls()) {
2759
                builder.append(" NULL");
2760
            } else {
2761
                builder.append(" NOT NULL");
2762
            }
2763
            if (column.isPrimaryKey()) {
2764
                builder.append(" PRIMARY KEY");
2765
            }
2766
            sqls.add(builder.toString());
2767
            
2768
            if( column.isGeometry() ) {
2769
                sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2770
            }
2771
            if( column.isIndexed() ) {
2772
                sqls.addAll(create_index_sqls(formatter, column));
2773
            }
2774
            return sqls;
2775
        }
2776

    
2777
        protected List<String> alter_table_alter_column_rename_sqls(Formatter<Value> formatter, String oldName, String newName) {
2778
            StringBuilder builder = new StringBuilder();
2779
            builder.append("ALTER TABLE ");
2780
            builder.append(this.table.toString(formatter));
2781
            builder.append(" ALTER COLUMN ");
2782
            builder.append(as_identifier(oldName));
2783
            builder.append(" RENAME TO ");
2784
            builder.append(as_identifier(newName));
2785
            return Collections.singletonList(builder.toString());
2786
        }
2787

    
2788
        protected List<String> alter_column_add_geometry_constraint_sqls(Formatter<ExpressionBuilder.Value> formatter, ColumnDescriptor column) {
2789
            return Collections.EMPTY_LIST;
2790
        }
2791
        
2792
        @Override
2793
        public String toString() {
2794
            return this.toString(formatter());
2795
        }
2796

    
2797
        @Override
2798
        public String toString(Formatter<Value> formatter) {
2799
            if (formatter!=null && formatter.canApply(this)) {
2800
                return formatter.format(this);
2801
            }
2802
            StringBuilder builder = new StringBuilder();
2803
            boolean first = true;
2804
            for (String sql : toStrings(formatter)) {
2805
                if (StringUtils.isEmpty(sql)) {
2806
                    continue;
2807
                }
2808
                if (first) {
2809
                    first = false;
2810
                } else {
2811
                    builder.append("; ");
2812
                }
2813
                builder.append(sql);
2814
            }
2815
            return builder.toString();
2816
        }
2817

    
2818
        @Override
2819
        public List<String> toStrings() {
2820
            return this.toStrings(formatter());
2821
        }
2822

    
2823
        @Override
2824
        public List<String> toStrings(Formatter formatter) {
2825
            List<String> sqls = new ArrayList<>();
2826
            if (this.isEmpty()) {
2827
                return sqls;
2828
            }
2829
            for (String column : drops) {
2830
                sqls.addAll(alter_table_drop_column_sqls(formatter, column));
2831
            }
2832
            for (ColumnDescriptor column : adds) {
2833
                sqls.addAll(alter_table_add_column_sqls(formatter, column));
2834
            }
2835
            for (Pair<Bitmask,ColumnDescriptor> operationAndColumn : this.getOperations()) {
2836
                Bitmask operation = operationAndColumn.getLeft();
2837
                ColumnDescriptor column = operationAndColumn.getRight();
2838
                if( operation.isSetBit(ALTER_COLUMN_ALL) ) {
2839
                    if( column.isPrimaryKey() ) {
2840
                        sqls.addAll(alter_table_add_primarykey_sqls(formatter, column));
2841
                    } else {
2842
                        sqls.addAll(alter_table_drop_primarykey_sqls(formatter, column));
2843
                        if( column.isIndexed() ) {
2844
                            sqls.addAll(create_index_sqls(formatter, column));
2845
                        }
2846
                    }
2847
                    sqls.addAll(alter_table_alter_column_set_data_type_sqls(formatter, column));
2848
                    sqls.addAll(alter_table_alter_column_set_default_sqls(formatter, column));
2849
                    sqls.addAll(alter_table_alter_column_set_null_sqls(formatter, column));
2850
                    if( column.isGeometry() ) {
2851
                        sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2852
                    }
2853
                } else {
2854
                    if( operation.isSetBit(ALTER_COLUMN_SET_NULL) ) { // Debe ir antes del "add primary key"
2855
                        sqls.addAll(alter_table_alter_column_set_null_sqls(formatter, column));
2856
                    }
2857
                    
2858
                    if( operation.isSetBit(ALTER_COLUMN_SET_DATA_TYPE) ) {
2859
                        sqls.addAll(alter_table_alter_column_set_data_type_sqls(formatter, column));
2860
                    }
2861
                    
2862
                    if( operation.isSetBit(ALTER_COLUMN_ADD_PRIMARY_KEY) ) {
2863
                        sqls.addAll(alter_table_add_primarykey_sqls(formatter, column));
2864
                    }
2865
                    
2866
                    if( operation.isSetBit(ALTER_COLUMN_DROP_PRIMARY_KEY) ) {
2867
                        sqls.addAll(alter_table_drop_primarykey_sqls(formatter, column));
2868
                    }
2869
                    
2870
                    if( operation.isSetBit(ALTER_COLUMN_SET_DEFAULT) ) {
2871
                        sqls.addAll(alter_table_alter_column_set_default_sqls(formatter, column));
2872
                    }
2873
                    
2874
                    if( operation.isSetBit(ALTER_COLUMN_CREATE_INDEX) ) {
2875
                        sqls.addAll(create_index_sqls(formatter, column));
2876
                    }
2877
                    
2878
                    if( operation.isSetBit(ALTER_COLUMN_DROP_INDEX) ) {
2879
                        sqls.addAll(drop_index_sqls(formatter, column));
2880
                    }
2881
                    
2882
                    if( operation.isSetBit(ALTER_COLUMN_GEOMETRY) ) {
2883
                        if( column.isGeometry() ) {
2884
                            sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2885
                        }
2886
                    }
2887
                        
2888
                }
2889
            }
2890
            
2891
            for (Pair<String, String> pair : renames) {
2892
                sqls.addAll(alter_table_alter_column_rename_sqls(formatter, pair.getLeft(), pair.getRight()));
2893
            }
2894
            return sqls;
2895
        }
2896

    
2897
    }
2898

    
2899
    public class CreateTableBuilderBase
2900
            extends AbstractStatement
2901
            implements CreateTableBuilder {
2902

    
2903
        protected TableNameBuilder table;
2904
        protected List<ColumnDescriptor> columns;
2905

    
2906
        public CreateTableBuilderBase() {
2907
            this.columns = new ArrayList<>();
2908
        }
2909

    
2910
        @Override
2911
        public void accept(Visitor visitor, VisitorFilter filter) {
2912
            boolean visitChildren = true;
2913
            if (filter==null || filter.accept(this)) {
2914
                visitor.visit(this);
2915
            } else {
2916
                visitChildren = !filter.skipChildren();
2917
            }
2918
            if(visitChildren){
2919
                if (this.table != null) {
2920
                    this.table.accept(visitor, filter);
2921
                }
2922
            }
2923
        }
2924

    
2925
        @Override
2926
        public TableNameBuilder table() {
2927
            if (table == null) {
2928
                table = createTableNameBuilder();
2929
            }
2930
            return table;
2931
        }
2932

    
2933
        @Override
2934
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2935
            this.columns.add(new ColumnDescriptorBase(fad));
2936
            return this;
2937
        }
2938

    
2939
        @Override
2940
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2941
            if (StringUtils.isEmpty(columnName)) {
2942
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2943
            }
2944
            if (isPk || isAutomatic) {
2945
                allowNulls = false;
2946
            }
2947
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2948
            return this;
2949
        }
2950

    
2951
        @Override
2952
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2953
            if (StringUtils.isEmpty(columnName)) {
2954
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2955
            }
2956
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2957
            return this;
2958
        }
2959

    
2960
        @Override
2961
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2962
            if (StringUtils.isEmpty(columnName)) {
2963
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2964
            }
2965
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2966
            return this;
2967
        }
2968

    
2969
        @Override
2970
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2971
            if (StringUtils.isEmpty(columnName)) {
2972
                return null;
2973
            }
2974
            for (ColumnDescriptor column : columns) {
2975
                if (columnName.equals(column.getName())) {
2976
                    return column;
2977
                }
2978
            }
2979
            return null;
2980
        }
2981

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

    
2987
        @Override
2988
        public String toString(Formatter<Value> formatter) {
2989
            if (formatter!=null && formatter.canApply(this)) {
2990
                return formatter.format(this);
2991
            }
2992
            StringBuilder builder = new StringBuilder();
2993
            boolean first = true;
2994
            for (String sql : toStrings(formatter)) {
2995
                if (StringUtils.isEmpty(sql)) {
2996
                    continue;
2997
                }
2998
                if (first) {
2999
                    first = false;
3000
                } else {
3001
                    builder.append("; ");
3002
                }
3003
                builder.append(sql);
3004
            }
3005
            return builder.toString();
3006
        }
3007

    
3008
        @Override
3009
        public List<String> toStrings() {
3010
            return this.toStrings(formatter());
3011
        }
3012

    
3013
        @Override
3014
        /*
3015
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
3016
        */
3017
        public List<String> toStrings(Formatter formatter) {
3018
            List<String> sqls = new ArrayList<>();
3019
            /**
3020
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
3021
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
3022
             * column_constraint [ ... ] ] | table_constraint | LIKE
3023
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
3024
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
3025
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
3026
             *
3027
             * where column_constraint is:
3028
             *
3029
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
3030
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
3031
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
3032
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
3033
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
3034
             *
3035
             * and table_constraint is:
3036
             *
3037
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
3038
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
3039
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
3040
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
3041
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
3042
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
3043
             */
3044
            
3045
            StringBuilder builder = new StringBuilder();
3046

    
3047
            builder.append("CREATE TABLE ");
3048
            builder.append(this.table.toString(formatter));
3049
            builder.append(" (");
3050
            boolean first = true;
3051
            for (ColumnDescriptor column : columns) {
3052
                if (first) {
3053
                    first = false;
3054
                } else {
3055
                    builder.append(", ");
3056
                }
3057
                builder.append(as_identifier(column.getName()));
3058
                builder.append(" ");
3059
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
3060
                    builder.append("SERIAL");
3061
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
3062
                    builder.append("BIGSERIAL");
3063
                } else {
3064
                    builder.append(sqltype(
3065
                            column.getType(),
3066
                            column.getSize(),
3067
                            column.getPrecision(),
3068
                            column.getScale(),
3069
                            column.getGeometryType(),
3070
                            column.getGeometrySubtype()
3071
                    )
3072
                    );
3073
                }
3074
                if (column.getDefaultValue() == null) {
3075
                    if (column.allowNulls()) {
3076
                        builder.append(" DEFAULT NULL");
3077
                    }
3078
                } else {
3079
                    builder.append(" DEFAULT '");
3080
                    builder.append(Objects.toString(column.getDefaultValue(),""));
3081
                    builder.append("'");
3082
                }
3083
                if (column.isPrimaryKey()) {
3084
                    builder.append(" NOT NULL");
3085
                    builder.append(" PRIMARY KEY");
3086
                } else {
3087
                    if (column.allowNulls()) {
3088
                        builder.append(" NULL");
3089
                    } else {
3090
                        builder.append(" NOT NULL");
3091
                    }
3092
                }
3093
            }
3094
            builder.append(" )");
3095
            sqls.add(builder.toString());
3096
            return sqls;
3097
        }
3098
    }
3099

    
3100
    public class InsertColumnBuilderBase
3101
            extends AbstractStatement
3102
            implements InsertColumnBuilder {
3103

    
3104
        protected Variable name;
3105
        protected Value value;
3106

    
3107
        public InsertColumnBuilderBase() {
3108
        }
3109

    
3110
        @Override
3111
        public void accept(Visitor visitor, VisitorFilter filter) {
3112
            boolean visitChildren = true;
3113
            if (filter==null || filter.accept(this)) {
3114
                visitor.visit(this);
3115
            } else {
3116
                visitChildren = !filter.skipChildren();
3117
            }
3118
            if(visitChildren){
3119
                if (this.name != null) {
3120
                    this.name.accept(visitor, filter);
3121
                }
3122
                if (this.value != null) {
3123
                    this.value.accept(visitor, filter);
3124
                }
3125
            }
3126
        }
3127

    
3128
        @Override
3129
        public InsertColumnBuilder name(String name) {
3130
            this.name = expression().variable(name);
3131
            return this;
3132
        }
3133

    
3134
        @Override
3135
        public InsertColumnBuilder with_value(Value value) {
3136
            this.value = value;
3137
            return this;
3138
        }
3139

    
3140
        @Override
3141
        public String getName() {
3142
            return this.name.name();
3143
        }
3144

    
3145
        @Override
3146
        public Value getValue() {
3147
            return this.value;
3148
        }
3149

    
3150
        @Override
3151
        public String toString() {
3152
            return this.toString(formatter());
3153
        }
3154

    
3155
        @Override
3156
        public String toString(Formatter<Value> formatter) {
3157
            if (formatter!=null && formatter.canApply(this)) {
3158
                return formatter.format(this);
3159
            }
3160
            return this.value.toString(formatter);
3161
        }
3162
    }
3163

    
3164
    public class MergeBuilderBase
3165
            extends InsertBuilderBase
3166
            implements MergeBuilder {
3167
        
3168
        protected List<String> keycolumns;
3169
        
3170
        public MergeBuilderBase() {
3171
            super();
3172
            this.keycolumns = new ArrayList<>();
3173
        }
3174

    
3175
        @Override
3176
        public MergeBuilder key(String id) {
3177
            this.keycolumns.add(id);
3178
            return this;
3179
        }
3180
        
3181
        @Override
3182
        public String toString(Formatter<Value> formatter) {
3183
            if (formatter!=null && formatter.canApply(this)) {
3184
                return formatter.format(this);
3185
            }
3186
            /*
3187
             * MERGE INTO table [ ( column [, ...] ) ] KEY (columnName [,...] ) { DEFAULT VALUES | VALUES (
3188
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3189
             * output_expression [ AS output_name ] [, ...] ]
3190
             */
3191
            StringBuilder builderKeyColumns = new StringBuilder();
3192
            StringBuilder builderColumns = new StringBuilder();
3193
            StringBuilder builderValues = new StringBuilder();
3194

    
3195
            boolean first = true;
3196
            for (InsertColumnBuilder column : columns) {
3197
                if (first) {
3198
                    first = false;
3199
                } else {
3200
                    builderColumns.append(", ");
3201
                }
3202
                builderColumns.append(as_identifier(column.getName()));
3203
            }
3204
            first = true;
3205
            for (String column : keycolumns) {
3206
                if (first) {
3207
                    first = false;
3208
                } else {
3209
                    builderKeyColumns.append(", ");
3210
                }
3211
                builderKeyColumns.append(as_identifier(column));
3212
            }
3213
            first = true;
3214
            for (InsertColumnBuilder column : columns) {
3215
                if (first) {
3216
                    first = false;
3217
                } else {
3218
                    builderValues.append(", ");
3219
                }
3220
                builderValues.append(column.toString(formatter));
3221
            }
3222

    
3223
            String sql = MessageFormat.format(
3224
                    STMT_MERGE_INTO_table_KEY_column_columns_VALUES_values,
3225
                    this.table.toString(formatter),
3226
                    builderColumns.toString(),
3227
                    builderKeyColumns.toString(),
3228
                    builderValues.toString()
3229
            );
3230
            return sql;
3231

    
3232
        }
3233
    }
3234

    
3235
    
3236
    public class InsertBuilderBase
3237
            extends AbstractStatement
3238
            implements InsertBuilder {
3239

    
3240
        protected List<InsertColumnBuilder> columns;
3241
        protected TableNameBuilder table;
3242

    
3243
        public InsertBuilderBase() {
3244
            this.columns = new ArrayList<>();
3245
        }
3246

    
3247
        @Override
3248
        public void accept(Visitor visitor, VisitorFilter filter) {
3249
            boolean visitChildren = true;
3250
            if (filter==null || filter.accept(this)) {
3251
                visitor.visit(this);
3252
            } else {
3253
                visitChildren = !filter.skipChildren();
3254
            }
3255
            if(visitChildren){
3256
                if (this.table != null) {
3257
                    this.table.accept(visitor, filter);
3258
                }
3259
                for (InsertColumnBuilder column : columns) {
3260
                    column.accept(visitor, filter);
3261
                }
3262
            }
3263
        }
3264

    
3265
        @Override
3266
        public TableNameBuilder table() {
3267
            if (table == null) {
3268
                table = createTableNameBuilder();
3269
            }
3270
            return table;
3271
        }
3272

    
3273
        @Override
3274
        public InsertColumnBuilder column() {
3275
            InsertColumnBuilder column = createInsertColumnBuilder();
3276
            this.columns.add(column);
3277
            return column;
3278
        }
3279

    
3280
        @Override
3281
        public String toString() {
3282
            return this.toString(formatter());
3283
        }
3284

    
3285
        @Override
3286
        public String toString(Formatter<Value> formatter) {
3287
            if (formatter!=null && formatter.canApply(this)) {
3288
                return formatter.format(this);
3289
            }
3290
            /*
3291
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
3292
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3293
             * output_expression [ AS output_name ] [, ...] ]
3294
             */
3295
            StringBuilder builderColumns = new StringBuilder();
3296
            StringBuilder builderValues = new StringBuilder();
3297

    
3298
            boolean first = true;
3299
            for (InsertColumnBuilder column : columns) {
3300
                if (first) {
3301
                    first = false;
3302
                } else {
3303
                    builderColumns.append(", ");
3304
                }
3305
                builderColumns.append(as_identifier(column.getName()));
3306
            }
3307
            first = true;
3308
            for (InsertColumnBuilder column : columns) {
3309
                if (first) {
3310
                    first = false;
3311
                } else {
3312
                    builderValues.append(", ");
3313
                }
3314
                builderValues.append(column.toString(formatter));
3315
            }
3316

    
3317
            String sql = MessageFormat.format(
3318
                    STMT_INSERT_INTO_table_columns_VALUES_values,
3319
                    this.table.toString(formatter),
3320
                    builderColumns.toString(),
3321
                    builderValues.toString()
3322
            );
3323
            return sql;
3324

    
3325
        }
3326
    }
3327

    
3328
    public class UpdateTableStatisticsBuilderBase
3329
            extends AbstractStatement
3330
            implements UpdateTableStatisticsBuilder {
3331

    
3332
        protected TableNameBuilder table;
3333

    
3334
        @Override
3335
        public void accept(Visitor visitor, VisitorFilter filter) {
3336
            boolean visitChildren = true;
3337
            if (filter==null || filter.accept(this)) {
3338
                visitor.visit(this);
3339
            } else {
3340
                visitChildren = !filter.skipChildren();
3341
            }
3342
            if(visitChildren){
3343
                if (this.table != null) {
3344
                    this.table.accept(visitor, filter);
3345
                }
3346
            }
3347
        }
3348

    
3349
        @Override
3350
        public TableNameBuilder table() {
3351
            if (table == null) {
3352
                table = createTableNameBuilder();
3353
            }
3354
            return table;
3355
        }
3356

    
3357
        @Override
3358
        public String toString() {
3359
            return this.toString(formatter());
3360
        }
3361

    
3362
        @Override
3363
        public String toString(Formatter<Value> formatter) {
3364
            if (formatter!=null && formatter.canApply(this)) {
3365
                return formatter.format(this);
3366
            }
3367
            StringBuilder builder = new StringBuilder();
3368
            boolean first = true;
3369
            for (String sql : toStrings(formatter)) {
3370
                if (StringUtils.isEmpty(sql)) {
3371
                    continue;
3372
                }
3373
                if (first) {
3374
                    first = false;
3375
                } else {
3376
                    builder.append("; ");
3377
                }
3378
                builder.append(sql);
3379
            }
3380
            return builder.toString();
3381
        }
3382

    
3383
        @Override
3384
        public List<String> toStrings() {
3385
            return this.toStrings(formatter());
3386
        }
3387

    
3388
        @Override
3389
        public List<String> toStrings(Formatter formatter) {
3390
            List<String> sqls = new ArrayList<>();
3391

    
3392
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
3393
                String sql = MessageFormat.format(
3394
                        STMT_UPDATE_TABLE_STATISTICS_table,
3395
                        table.toString(formatter)
3396
                );
3397
                if (!StringUtils.isEmpty(sql)) {
3398
                    sqls.add(sql);
3399
                }
3400
            }
3401
            return sqls;
3402
        }
3403
    }
3404

    
3405
    protected GeometryExpressionBuilder expressionBuilder;
3406

    
3407
    protected String defaultSchema;
3408
    protected boolean supportSchemas;
3409
    protected boolean hasSpatialFunctions;
3410
    protected GeometrySupportType geometrySupportType;
3411
    protected boolean allowAutomaticValues;
3412

    
3413
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
3414

    
3415
    protected String constant_true = "(1=1)";
3416
    protected String constant_false = "(1<>1)";
3417

    
3418
    protected String type_boolean = "BOOLEAN";
3419
    protected String type_byte = "TINYINT";
3420
    protected String type_bytearray = "BYTEA";
3421
    protected String type_geometry = "TEXT";
3422
    protected String type_char = "CHARACTER(1)";
3423
    protected String type_date = "DATE";
3424
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
3425
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
3426
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
3427
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
3428
    protected String type_int = "INT";
3429
    protected String type_long = "BIGINT";
3430
    protected String type_string = "TEXT";
3431
    protected String type_string_p = "VARCHAR({0,Number,#######})";
3432
    protected String type_time = "TIME";
3433
    protected String type_timestamp = "TIMESTAMP";
3434
    protected String type_version = "VARCHAR(30)";
3435
    protected String type_URI = "TEXT";
3436
    protected String type_URL = "TEXT";
3437
    protected String type_FILE = "TEXT";
3438
    protected String type_FOLDER = "TEXT";
3439

    
3440
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
3441
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
3442
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
3443
    protected String STMT_MERGE_INTO_table_KEY_column_columns_VALUES_values = "MERGE INTO {0} ( {1} )  KEY( {2} ) VALUES ( {3} )";
3444
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
3445
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
3446
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
3447
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
3448
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
3449
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
3450
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3451

    
3452
    public SQLBuilderBase() {
3453
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3454
        this.expressionBuilder.setProperty(PROP_SQLBUILDER, this);
3455

    
3456
        this.hasSpatialFunctions = false;
3457
        this.supportSchemas = true;
3458
        this.geometrySupportType = GeometrySupportType.WKT;
3459

    
3460
        this.defaultSchema = "public";
3461
        this.allowAutomaticValues = true;
3462

    
3463
    }
3464
    
3465
    @Override
3466
    public void setProperties(Class filter, final Object... values) {
3467
        this.expressionBuilder.setProperties(filter, values);
3468
        setProperties(this, filter, values);
3469
    }
3470
    
3471
    @Override
3472
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3473
        if(visitable == null){
3474
            return;
3475
        }
3476
        if(visitable instanceof PropertiesSupport){
3477
            for (int i = 0; i < values.length; i+=2) {
3478
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3479
                    }
3480
                }
3481
        visitable.accept((Visitable v) -> {
3482
            if(v instanceof PropertiesSupport){
3483
                for (int i = 0; i < values.length; i+=2) {
3484
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3485
                        }
3486
                    }
3487
        }, new ClassVisitorFilter(filter) );
3488
    }
3489

    
3490
    public String quote_for_identifiers() {
3491
        return "\"";
3492
    }
3493

    
3494
    public String quote_for_strings() {
3495
        return "'";
3496
    }
3497

    
3498
    @Override
3499
    public String as_identifier(String id) {
3500
        String quote = this.quote_for_identifiers();
3501
//        No se porque no esta disponible wrapIfMissing
3502
//        return StringUtils.wrapIfMissing(id,quote);
3503
        if (id.startsWith(quote)) {
3504
            return id;
3505
        }
3506
        return quote + id + quote;
3507

    
3508
    }
3509
    
3510
    @Override
3511
    public String as_clob(String s) {
3512
        int chunkSize = 1024;
3513
        StringBuilder builder = new StringBuilder();
3514
        builder.append("(CAST('");
3515
        for (int i = 0; i < s.length(); i += chunkSize) {
3516
            String chunk = s.substring(i, Math.min(s.length(), i + chunkSize));
3517
            if( i>0 ) {
3518
                builder.append("' AS NCLOB) || CAST('");
3519
            }            
3520
            builder.append(StringUtils.replace(chunk, "'", "''"));
3521
        }
3522
        builder.append("' AS NCLOB))");
3523
        return builder.toString();
3524
    }
3525

    
3526
    @Override
3527
    public String as_string(String s) {
3528
        String quote = this.quote_for_strings();
3529
//        No se porque no esta disponible wrapIfMissing
3530
//        return StringUtils.wrapIfMissing(id,quote);
3531
        if (s.startsWith(quote)) {
3532
            return s;
3533
        }
3534
        return quote + s + quote;
3535

    
3536
    }
3537

    
3538
    @Override
3539
    public String as_string(byte[] data) {
3540
        return this.expressionBuilder.bytearray_0x(data);
3541
//        return this.expressionBuilder.bytearray_hex(data);
3542
//        return this.expressionBuilder.bytearray_x(data);
3543
    }
3544
    
3545
    @Override
3546
    public String as_string(boolean value) {
3547
        return value? "TRUE" : "FALSE";
3548
    }
3549

    
3550
    @Override
3551
    public String as_string(Number value) {
3552
        return Objects.toString(value);
3553
    }
3554
    
3555
    @Override
3556
    public String as_string(Object value) {
3557
        if( value == null ) {
3558
            return "NULL";
3559
        }
3560
        if( value instanceof CharSequence ) {
3561
            return as_string(value.toString());
3562
        }
3563
        if( value instanceof Number ) {
3564
            return as_string((Number)value);
3565
        }
3566
        if( value instanceof Boolean ) {
3567
            return as_string((boolean)value);
3568
        }
3569
        if( value instanceof byte[] ) {
3570
            return as_string((byte[])value);
3571
        }
3572
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3573
    }
3574
    
3575
    @Override
3576
    public GeometryExpressionBuilder expression() {
3577
        return this.expressionBuilder;
3578
    }
3579

    
3580
    @Override
3581
    public boolean has_spatial_functions() {
3582
        return this.hasSpatialFunctions;
3583
    }
3584

    
3585
    @Override
3586
    public GeometrySupportType geometry_support_type() {
3587
        return this.geometrySupportType;
3588
    }
3589

    
3590
    protected GeometryExpressionBuilder createExpressionBuilder() {
3591
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3592
    }
3593

    
3594
    @Override
3595
    public Object srs_id(IProjection projection) {
3596
        String abrev = projection.getAbrev();
3597
        return abrev.split(":")[1].trim();
3598
    }
3599

    
3600
    @Override
3601
    public String default_schema() {
3602
        return this.defaultSchema;
3603
    }
3604

    
3605
    @Override
3606
    public boolean support_schemas() {
3607
        return this.supportSchemas;
3608
    }
3609

    
3610
    @Override
3611
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3612
        switch (type) {
3613
            case DataTypes.BOOLEAN:
3614
                return type_boolean;
3615
            case DataTypes.CHAR:
3616
                return type_char;
3617

    
3618

    
3619
            case DataTypes.BYTE:
3620
                return type_byte;
3621
            case DataTypes.INT:
3622
                return type_int;
3623
            case DataTypes.LONG:
3624
                return type_long;
3625

    
3626
            case DataTypes.FLOAT:
3627
                return type_float;
3628
            case DataTypes.DOUBLE:
3629
                return type_double;
3630
            case DataTypes.DECIMAL:
3631
                if (precision < 1) {
3632
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3633
                }
3634
                if (scale < 1) {
3635
                  return MessageFormat.format(type_decimal_p, precision);
3636
                }
3637
                return MessageFormat.format(type_decimal_ps, precision, scale);
3638

    
3639
                
3640
            case DataTypes.STRING:
3641
                if (size < 0) {
3642
                    return type_string;
3643
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3644
                    return MessageFormat.format(type_string_p, size);
3645
                }
3646
                return type_string;
3647

    
3648
                
3649
            case DataTypes.DATE:
3650
                return type_date;
3651
            case DataTypes.TIME:
3652
                return type_time;
3653
            case DataTypes.TIMESTAMP:
3654
                return type_timestamp;
3655

    
3656
            case DataTypes.BYTEARRAY:
3657
                return type_bytearray;
3658

    
3659
            case DataTypes.GEOMETRY:
3660
                return type_geometry;
3661

    
3662
            case DataTypes.VERSION:
3663
                return type_version;
3664
            case DataTypes.URI:
3665
                return type_URI;
3666
            case DataTypes.URL:
3667
                return type_URL;
3668
            case DataTypes.FILE:
3669
                return type_FILE;
3670
            case DataTypes.FOLDER:
3671
                return type_FOLDER;
3672
            default:
3673
                return null;
3674
        }
3675
    }
3676

    
3677
    @Override
3678
    public Object sqlgeometrytype(int type, int subtype) {
3679
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3680
        // identificadores numericos para el tipo y otros strings.
3681
        // Por defecto vamos a devolver strings.
3682
        if (sqlgeometrytypes == null) {
3683
            sqlgeometrytypes = new HashMap<>();
3684
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3685
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3686
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3687
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3688

    
3689
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3690
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3691
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3692
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3693

    
3694
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3695
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3696
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3697
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3698

    
3699
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3700
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3701
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3702
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3703

    
3704
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3705
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3706
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3707
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3708

    
3709
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3710
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3711
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3712
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3713

    
3714
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3715
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3716
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3717
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3718

    
3719
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3720
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3721
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3722
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3723

    
3724
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3725
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3726
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3727
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3728
        }
3729
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3730
    }
3731

    
3732
    @Override
3733
    public Object sqlgeometrydimension(int type, int subtype) {
3734
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3735
        // identificadores numericos para las dimensiones y otros strings.
3736
        // Por defecto vamos a devolver enteros.
3737
        switch (subtype) {
3738
            case Geometry.SUBTYPES.GEOM3D:
3739
                return 3;
3740
            case Geometry.SUBTYPES.GEOM2DM:
3741
                return 3;
3742
            case Geometry.SUBTYPES.GEOM3DM:
3743
                return 4;
3744
            case Geometry.SUBTYPES.GEOM2D:
3745
            default:
3746
                return 2;
3747
        }
3748
    }
3749

    
3750
    @Override
3751
    public SelectColumnBuilder column() {
3752
        return createSelectColumnBuilder();
3753
    }
3754

    
3755
    @Override
3756
    public TableNameBuilder createTableNameBuilder() {
3757
        return new TableNameBuilderBase();
3758
    }
3759

    
3760
    protected SelectColumnBuilder createSelectColumnBuilder() {
3761
        return new SelectColumnBuilderBase(this);
3762
    }
3763

    
3764
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3765
        return new UpdateColumnBuilderBase();
3766
    }
3767

    
3768
    protected InsertColumnBuilder createInsertColumnBuilder() {
3769
        return new InsertColumnBuilderBase();
3770
    }
3771

    
3772
    protected OrderByBuilder createOrderByBuilder() {
3773
        return new OrderByBuilderBase();
3774
    }
3775

    
3776
    protected FromBuilder createFromBuilder() {
3777
        return new FromBuilderBase();
3778
    }
3779

    
3780
    public SelectBuilder createSelectBuilder() {
3781
        return new SelectBuilderBase();
3782
    }
3783

    
3784
    protected UpdateBuilder createUpdateBuilder() {
3785
        return new UpdateBuilderBase();
3786
    }
3787

    
3788
    protected DeleteBuilder createDeleteBuilder() {
3789
        return new DeleteBuilderBase();
3790
    }
3791

    
3792
    protected GrantBuilder createGrantBuilder() {
3793
        return new GrantBuilderBase();
3794
    }
3795

    
3796
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3797
        return new GrantRoleBuilderBase(table, role);
3798
    }
3799

    
3800
    protected DropTableBuilder createDropTableBuilder() {
3801
        return new DropTableBuilderBase();
3802
    }
3803

    
3804
    protected CreateTableBuilder createCreateTableBuilder() {
3805
        return new CreateTableBuilderBase();
3806
    }
3807

    
3808
    protected AlterTableBuilder createAlterTableBuilder() {
3809
        return new AlterTableBuilderBase(this);
3810
    }
3811

    
3812
    protected InsertBuilder createInsertBuilder() {
3813
        return new InsertBuilderBase();
3814
    }
3815

    
3816
    protected MergeBuilder createMergeBuilder() {
3817
        return new MergeBuilderBase();
3818
    }
3819

    
3820
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3821
        return new UpdateTableStatisticsBuilderBase();
3822
    }
3823

    
3824
    public CreateIndexBuilder createCreateIndexBuilder() {
3825
        return new CreateIndexBuilderBase();
3826
    }
3827

    
3828
    public DropIndexBuilder createDropIndexBuilder() {
3829
        return new DropIndexBuilderBase();
3830
    }
3831
    
3832
    @Override
3833
    public SelectBuilder select() {
3834
        if (this.select == null) {
3835
            this.select = this.createSelectBuilder();
3836
        }
3837
        return this.select;
3838
    }
3839

    
3840
    @Override
3841
    public UpdateBuilder update() {
3842
        if (this.update == null) {
3843
            this.update = this.createUpdateBuilder();
3844
        }
3845
        return this.update;
3846
    }
3847

    
3848
    @Override
3849
    public UpdateTableStatisticsBuilder update_table_statistics() {
3850
        if (this.update_table_statistics == null) {
3851
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3852
        }
3853
        return this.update_table_statistics;
3854
    }
3855

    
3856
    @Override
3857
    public DropTableBuilder drop_table() {
3858
        if (this.drop_table == null) {
3859
            this.drop_table = this.createDropTableBuilder();
3860
        }
3861
        return this.drop_table;
3862
    }
3863

    
3864
    @Override
3865
    public CreateIndexBuilder create_index() {
3866
        if (this.create_index == null) {
3867
            this.create_index = this.createCreateIndexBuilder();
3868
        }
3869
        return this.create_index;
3870
    }
3871

    
3872
    @Override
3873
    public DropIndexBuilder drop_index() {
3874
        if (this.drop_index == null) {
3875
            this.drop_index = this.createDropIndexBuilder();
3876
        }
3877
        return this.drop_index;
3878
    }
3879

    
3880
    @Override
3881
    public DeleteBuilder delete() {
3882
        if (this.delete == null) {
3883
            this.delete = this.createDeleteBuilder();
3884
        }
3885
        return this.delete;
3886
    }
3887

    
3888
    @Override
3889
    public InsertBuilder insert() {
3890
        if (this.insert == null) {
3891
            this.insert = this.createInsertBuilder();
3892
        }
3893
        return this.insert;
3894
    }
3895

    
3896
    @Override
3897
    public MergeBuilder merge() {
3898
        if (this.merge == null) {
3899
            this.merge = this.createMergeBuilder();
3900
        }
3901
        return this.merge;
3902
    }
3903

    
3904
    @Override
3905
    public TableNameBuilder table_name() {
3906
        if (this.table_name == null) {
3907
            this.table_name = this.createTableNameBuilder();
3908
        }
3909
        return this.table_name;
3910
    }
3911

    
3912
    
3913
    @Override
3914
    public AlterTableBuilder alter_table() {
3915
        if (this.alter_table == null) {
3916
            this.alter_table = this.createAlterTableBuilder();
3917
        }
3918
        return this.alter_table;
3919
    }
3920

    
3921
    @Override
3922
    public CreateTableBuilder create_table() {
3923
        if (this.create_table == null) {
3924
            this.create_table = this.createCreateTableBuilder();
3925
        }
3926
        return this.create_table;
3927
    }
3928

    
3929
    @Override
3930
    public GrantBuilder grant() {
3931
        if (this.grant == null) {
3932
            this.grant = this.createGrantBuilder();
3933
        }
3934
        return this.grant;
3935
    }
3936
    
3937
    
3938
    @Override
3939
    public Column column(String name) {
3940
        ColumnBase col = new ColumnBase(null, name);
3941
        return col;
3942
    }
3943

    
3944
    @Override
3945
    public Column column(TableNameBuilder table, String name) {
3946
        ColumnBase col = new ColumnBase(table, name);
3947
        return col;
3948
    }
3949
    
3950
    @Override
3951
    public Column column_from(Variable variable) {
3952
        Column c = null;
3953
        if (variable instanceof Column) {
3954
            c = this.column(((Column) variable).table(), variable.name());
3955
        } else {
3956
            c = this.column(variable.name());
3957
        }
3958
        c.copyPropertiesFrom(variable);
3959
        return c;
3960

    
3961
    }
3962

    
3963
    @Override
3964
    public Column column_from(TableNameBuilder table, Variable variable) {
3965
        Column c = this.column(table, variable.name());
3966
        c.copyPropertiesFrom(variable);
3967
        return c;
3968
    }
3969

    
3970
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3971
        return new JoinBase(type, table, expression);
3972
    }
3973

    
3974
    @Override
3975
    public void accept(Visitor visitor, VisitorFilter filter) {
3976
        if (this.select != null) {
3977
            this.select.accept(visitor, filter);
3978
        }
3979
        if (this.update != null) {
3980
            this.update.accept(visitor, filter);
3981
        }
3982
        if (this.insert != null) {
3983
            this.insert.accept(visitor, filter);
3984
        }
3985
        if (this.merge != null) {
3986
            this.merge.accept(visitor, filter);
3987
        }
3988
        if (this.delete != null) {
3989
            this.delete.accept(visitor, filter);
3990
        }
3991
        if (this.alter_table != null) {
3992
            this.alter_table.accept(visitor, filter);
3993
        }
3994
        if (this.create_table != null) {
3995
            this.create_table.accept(visitor, filter);
3996
        }
3997
        if (this.drop_table != null) {
3998
            this.drop_table.accept(visitor, filter);
3999
        }
4000
        if (this.table_name != null) {
4001
            this.table_name.accept(visitor, filter);
4002
        }
4003
    }
4004

    
4005
    @Override
4006
    public Formatter formatter() {
4007
        return expression().formatter();
4008
    }
4009

    
4010
    @Override
4011
    public String toString() {
4012
        return this.toString(formatter());
4013
    }
4014

    
4015
    @Override
4016
    public String toString(Formatter formatter) {
4017
        if (this.select != null) {
4018
            return this.select.toString(formatter);
4019
        }
4020
        if (this.update != null) {
4021
            return this.update.toString(formatter);
4022
        }
4023
        if (this.insert != null) {
4024
            return this.insert.toString(formatter);
4025
        }
4026
        if (this.merge != null) {
4027
            return this.merge.toString(formatter);
4028
        }
4029
        if (this.delete != null) {
4030
            return this.delete.toString(formatter);
4031
        }
4032
        if (this.alter_table != null) {
4033
            return this.alter_table.toString(formatter);
4034
        }
4035
        if (this.create_table != null) {
4036
            return this.create_table.toString(formatter);
4037
        }
4038
        if (this.drop_table != null) {
4039
            return this.drop_table.toString(formatter);
4040
        }
4041
        if (this.update_table_statistics != null) {
4042
            return this.update_table_statistics.toString(formatter);
4043
        }
4044
        if (this.create_index != null) {
4045
            return this.create_index.toString(formatter);
4046
        }
4047
        if (this.drop_index != null) {
4048
            return this.drop_index.toString(formatter);
4049
        }
4050
        if (this.table_name != null) {
4051
            return this.table_name.toString(formatter);
4052
        }
4053
        return "";
4054
    }
4055

    
4056
    @Override
4057
    public CountBuilder count() {
4058
        return new CountBuilderBase();
4059
    }
4060

    
4061
    @Override
4062
    public List<Parameter> parameters() {
4063
        final List<Parameter> params = new ArrayList<>();
4064
        this.accept((Visitable value) -> {
4065
            params.add((Parameter) value);
4066
        }, new ClassVisitorFilter(Parameter.class));
4067
        return params;
4068
    }
4069

    
4070
    @Override
4071
    public List<Variable> variables() {
4072
        final List<Variable> vars = new ArrayList<>();
4073
        this.accept(new Visitor() {
4074
            @Override
4075
            public void visit(Visitable value) {
4076
                if (!vars.contains((Variable) value)) {
4077
                    vars.add((Variable) value);
4078
                }
4079
            }
4080
        }, new ClassVisitorFilter(Variable.class));
4081
        return vars;
4082
    }
4083

    
4084
    @Override
4085
    public List<String> parameters_names() {
4086
        List<String> params = new ArrayList<>();
4087
        for (Parameter param : parameters()) {
4088
            String s;
4089
            switch (param.type()) {
4090
                case PARAMETER_TYPE_CONSTANT:
4091
                    Object theValue = param.value();
4092
                    if (theValue == null) {
4093
                        s = "null";
4094
                    } else if (theValue instanceof String) {
4095
                        s = "'" + (String) theValue + "'";
4096
                    } else {
4097
                        s = theValue.toString();
4098
                    }
4099
                    break;
4100
                case PARAMETER_TYPE_VARIABLE:
4101
                default:
4102
                    s = "\"" + param.name() + "\"";
4103
            }
4104
            params.add(s);
4105
        }
4106
        return params;
4107
    }
4108

    
4109
    @Override
4110
    public List<String> variables_names() {
4111
        List<String> vars = new ArrayList<>();
4112
        for (Variable var : this.variables()) {
4113
            vars.add(var.name());
4114
        }
4115
        Collections.sort(vars);
4116
        return vars;
4117
    }    
4118
    
4119
    protected String[] aggregateFunctionNames = new String[] {
4120
        "MAX",
4121
        "MIN",
4122
        "COUNT",
4123
        "SUM"
4124
    };
4125
    
4126
    @Override
4127
    public boolean isAggregateFunction(String funcname) {
4128
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
4129
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
4130
                return true;
4131
            }
4132
        }
4133
        return false;
4134
    }
4135

    
4136
    @Override
4137
    public int getMaxRecomendedSQLLength() {
4138
        return DEFAULT_RECOMENDED_SQL_LENGTH;
4139
    }
4140
    
4141
    public String getConstrainName(TableNameBuilder table, String columnName, String constrainType) {
4142
        // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
4143
        String constraint_name = table.getName() + "_" + constrainType + "_" + columnName;
4144
        return constraint_name;
4145
    }    
4146
}