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

History | View | Annotate | Download (138 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
616
    }
617

    
618
    public class CountBuilderBase
619
            extends AbstractStatementPart
620
            implements CountBuilder {
621

    
622
        protected Value value;
623
        protected boolean distinct;
624
        protected boolean all;
625

    
626
        public CountBuilderBase() {
627
            this.value = null;
628
            this.distinct = false;
629
            this.all = false;
630
        }
631
        
632
        @Override
633
        public CountBuilderBase clone() throws CloneNotSupportedException {
634
            CountBuilderBase other = (CountBuilderBase) super.clone();
635
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
636
            return other;
637
        }
638
        
639
        @Override
640
        public CountBuilder all() {
641
            this.all = true;
642
            return this;
643
        }
644

    
645
        @Override
646
        public CountBuilder column(Value value) {
647
            this.value = value;
648
            return this;
649
        }
650

    
651
        @Override
652
        public CountBuilder distinct() {
653
            this.distinct = true;
654
            return this;
655
        }
656

    
657
        @Override
658
        public String toString() {
659
            return this.toString(formatter());
660
        }
661

    
662
        @Override
663
        public String toString(Formatter formatter) {
664
            if (formatter!=null && formatter.canApply(this)) {
665
                return formatter.format(this);
666
            }
667
            if (this.all) {
668
                return "COUNT(*)";
669
            }
670
            if (this.distinct) {
671
                return MessageFormat.format(
672
                        "COUNT(DISTINCT {0})",
673
                        value.toString(formatter)
674
                );
675
            }
676
            return MessageFormat.format(
677
                    "COUNT({0})",
678
                    value.toString(formatter)
679
            );
680
        }
681

    
682
    }
683

    
684
    protected class JoinBase 
685
            extends AbstractStatementPart
686
            implements JoinBuilder 
687
        {
688
        protected String type;
689
        protected TableNameBuilder table;
690
        protected Value expression;
691
        
692
        public JoinBase(String type, TableNameBuilder table, Value expression) {
693
            this.type = type;
694
            this.table = table;
695
            this.expression = expression;
696
        }
697
        
698
        @Override
699
        public JoinBase clone() throws CloneNotSupportedException {
700
            JoinBase other = (JoinBase) super.clone();
701
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
702
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
703
            return other;
704
        }
705

    
706
        @Override
707
        public String toString() {
708
            return this.toString(formatter());
709
        }
710

    
711
        @Override
712
        public String toString(Formatter<Value> formatter) {
713
            if (formatter!=null && formatter.canApply(this)) {
714
                return formatter.format(this);
715
            }
716
            StringBuilder builder = new StringBuilder();
717
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
718
            builder.append(this.type.toUpperCase());
719
            builder.append(" JOIN ");
720
            builder.append(this.table.toString(formatter));
721
            builder.append(" ON ");
722
            builder.append(this.expression.toString(formatter));
723
            return builder.toString();
724
        }
725
        
726
        @Override
727
        public TableNameBuilder getTable() {
728
            return this.table;
729
        }
730
        
731
        @Override
732
        public String getType() {
733
            return this.type;
734
        }
735

    
736
        @Override
737
        public Value getCondition() {
738
            return this.expression;
739
        }
740
        
741
        @Override
742
        public void accept(Visitor visitor, VisitorFilter filter) {
743
            boolean visitChildren = true;
744
            if (filter==null || filter.accept(this)) {
745
                visitor.visit(this);
746
            } else {
747
                visitChildren = !filter.skipChildren();
748
            }
749
            if(visitChildren){
750
                if (this.expression != null) {
751
                    this.expression.accept(visitor, filter);
752
                }
753
            }
754
        }
755

    
756
    }
757
    
758
    public class FromBuilderBase
759
            extends AbstractStatementPart
760
            implements FromBuilder {
761

    
762
        protected TableNameBuilder tableName;
763
        protected String subquery;
764
        protected String passthrough;
765
        protected List<JoinBuilder> joins;
766

    
767
        public FromBuilderBase() {
768
            this.tableName = null;
769
            this.subquery = null;
770
            this.passthrough = null;
771
            this.joins = null;
772
        }
773
        
774
        @Override
775
        public FromBuilderBase clone() throws CloneNotSupportedException {
776
            FromBuilderBase other = (FromBuilderBase) super.clone();
777
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
778
            if (joins!=null) {
779
                for (int i = 0; i < joins.size(); i++) {
780
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
781
                }
782
            }
783
            return other;
784
        }
785

    
786
        @Override
787
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
788
            JoinBase join = createJoin("LEFT", table, expression);
789
            if( this.joins==null ) {
790
                this.joins = new ArrayList<>();
791
            }
792
            this.joins.add(join);
793
            return this;
794
        }
795
        
796
        @Override
797
        public TableNameBuilder table() {
798
            if (tableName == null) {
799
                this.tableName = createTableNameBuilder();
800
            }
801
            return this.tableName;
802
        }
803

    
804
        @Override
805
        public void accept(Visitor visitor, VisitorFilter filter) {
806
            boolean visitChildren = true;
807
            if (filter==null || filter.accept(this)) {
808
                visitor.visit(this);
809
            } else {
810
                visitChildren = !filter.skipChildren();
811
            }
812
            if(visitChildren){
813
                if (this.tableName != null) {
814
                    this.tableName.accept(visitor, filter);
815
                }
816
                if(this.joins != null) {
817
                    for (JoinBuilder join : joins) {
818
                        join.accept(visitor, filter);
819
                    }
820
                }
821
            }
822
        }
823

    
824
        @Override
825
        public FromBuilder custom(String passthrough) {
826
            this.passthrough = passthrough;
827
            return this;
828
        }
829

    
830
        @Override
831
        public FromBuilder subquery(String subquery) {
832
            this.subquery = subquery;
833
            return this;
834
        }
835

    
836
        @Override
837
        public String toString() {
838
            return this.toString(formatter());
839
        }
840

    
841
        @Override
842
        public String toString(Formatter<Value> formatter) {
843
            if (formatter!=null && formatter.canApply(this)) {
844
                return formatter.format(this);
845
            }
846
            if (!StringUtils.isEmpty(passthrough)) {
847
                return passthrough;
848
            }
849
            if (!StringUtils.isEmpty(subquery)) {
850
                return "( " + this.subquery + ") AS _subquery_alias_ ";
851
            }
852
            if( this.joins==null || this.joins.isEmpty() ) {
853
                return this.tableName.toString(formatter);
854
            }
855
            StringBuilder builder = new StringBuilder();
856
            builder.append(this.tableName.toString(formatter));
857
            for (JoinBuilder join : this.joins) {
858
                builder.append(" ");
859
                builder.append(join.toString(formatter));
860
            }
861
            return builder.toString();
862
        }
863

    
864
        @Override
865
        public List<JoinBuilder> getJoins() {
866
            return this.joins;
867
        }
868

    
869
    }
870

    
871
    public class SelectColumnBuilderBase
872
            extends AbstractStatementPart
873
            implements SelectColumnBuilder {
874

    
875
        protected Column name = null;
876
        protected String alias = null;
877
        protected Value value = null;
878
        protected boolean asGeometry = false;
879
        protected TableNameBuilder table;
880
        protected SQLBuilder sqlbuilder;
881
        
882
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
883
            this.sqlbuilder = sqlbuilder;
884
        }
885
        
886
        @Override
887
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
888
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
889
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
890
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
891
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
892
            return other;
893
        }
894

    
895
        @Override
896
        public void accept(Visitor visitor, VisitorFilter filter) {
897
            boolean visitChildren = true;
898
            if (filter==null || filter.accept(this)) {
899
                visitor.visit(this);
900
            } else {
901
                visitChildren = !filter.skipChildren();
902
            }
903
            if(visitChildren){
904
                if (this.value != null) {
905
                    this.value.accept(visitor, filter);
906
                } else if (this.name != null) {
907
                    this.name.accept(visitor, filter);
908
                }
909
            }
910
        }
911

    
912
        @Override
913
        public void replace(Value target, Value replacement) {
914
            if (this.name!=null ) {
915
                if( this.name == target) {
916
                    if(replacement == null){
917
                        this.name = null;
918
                    } else if(replacement instanceof Column){
919
                        this.name = (Column) replacement;
920
                    } else if(replacement instanceof Variable){
921
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
922
                    } else {
923
                        this.value = replacement;
924
                    }
925
                }
926
            }
927
            if( this.value!=null ) {
928
                if (this.value == target) {
929
                    this.value = replacement;
930
                } else {
931
                    this.value.replace(target, replacement);
932
                }
933
            }
934
        }
935

    
936
        @Override
937
        public SelectColumnBuilder name(String name) {
938
            return this.name(this.table, name);
939
        }
940

    
941
        @Override
942
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
943
            String quote = quote_for_identifiers();
944
            if (name.startsWith(quote)) {
945
                // Remove quotes
946
                name = name.substring(1, name.length() - 1);
947
            }
948
            this.table = table;
949
            this.name = new ColumnBase(this.table, name);
950
            this.value = null;
951
            this.asGeometry = false;
952
            return this;
953
        }
954
        
955
        public SelectColumnBuilder table(TableNameBuilder table) {
956
            this.table = table;
957
            if(this.name != null){
958
                this.name.table(table);
959
            }
960
            return this;
961
        }
962
        
963
        @Override
964
        public SelectColumnBuilder all() {
965
            this.name = null;
966
            this.value = expression().custom("*");
967
            this.asGeometry = false;
968
            return this;
969
        }
970

    
971
        @Override
972
        public SelectColumnBuilder as_geometry() {
973
            this.asGeometry = true;
974
            return this;
975
        }
976

    
977
        @Override
978
        public SelectColumnBuilder value(Value value) {
979
            this.value = value;
980
            return this;
981
        }
982

    
983
        @Override
984
        public SelectColumnBuilder as(String alias) {
985
            this.alias = alias;
986
            return this;
987
        }
988

    
989
        @Override
990
        public String getName() {
991
            if (this.name==null) {
992
                return null;
993
            }
994
            return this.name.name();
995
        }
996

    
997
        @Override
998
        public String getAlias() {
999
            return this.alias;
1000
        }
1001

    
1002
        @Override
1003
        public Value getValue() {
1004
            return this.value;
1005
        }
1006

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

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

    
1074
    public class OrderByBuilderBase
1075
            extends AbstractStatementPart
1076
            implements OrderByBuilder {
1077

    
1078
        protected Value value;
1079
        protected String custom;
1080
        protected boolean ascending;
1081
        protected int nullsMode;
1082

    
1083
        public OrderByBuilderBase() {
1084
            this.ascending = true;
1085
            this.nullsMode = MODE_NULLS_LAST;
1086
        }
1087
        
1088
        @Override
1089
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
1090
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
1091
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
1092
            return other;
1093
        }
1094
        
1095
        @Override
1096
        public void accept(Visitor visitor, VisitorFilter filter) {
1097
            boolean visitChildren = true;
1098
            if (filter==null || filter.accept(this)) {
1099
                visitor.visit(this);
1100
            } else {
1101
                visitChildren = !filter.skipChildren();
1102
            }
1103
            if(visitChildren){
1104
                if (this.value!=null) {
1105
                    this.value.accept(visitor, filter);
1106
                }
1107
            }
1108
        }
1109

    
1110
        @Override
1111
        public OrderByBuilder column(String name) {
1112
            this.value = expression().variable(name);
1113
            return this;
1114
        }
1115
        
1116
        @Override
1117
        public boolean isColumn(String name) {
1118
            if(this.value instanceof ExpressionBuilder.Variable){
1119
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1120
            }
1121
            return false;
1122
        }
1123
        
1124
        @Override
1125
        public boolean isColumn(Value value) {
1126
            if(value instanceof ExpressionBuilder.Variable){
1127
                return isColumn(((ExpressionBuilder.Variable)value).name());
1128
            }
1129
            return this.value == value;
1130
        }
1131
        
1132
        @Override
1133
        public OrderByBuilder value(Value expression) {
1134
            this.value = expression;
1135
            return this;
1136
        }
1137
        
1138
        @Override
1139
        public OrderByBuilder custom(String order) {
1140
            this.custom = order;
1141
            return this;
1142
        }
1143

    
1144
        @Override
1145
        public OrderByBuilder ascending() {
1146
            this.ascending = true;
1147
            return this;
1148
        }
1149

    
1150
        @Override
1151
        public OrderByBuilder ascending(boolean asc) {
1152
            this.ascending = asc;
1153
            return this;
1154
        }
1155

    
1156
        @Override
1157
        public OrderByBuilder descending() {
1158
            this.ascending = false;
1159
            return this;
1160
        }
1161

    
1162
        @Override
1163
        public OrderByBuilder nulls(int mode) {
1164
            this.nullsMode = mode;
1165
            return this;
1166
        }
1167

    
1168
        @Override
1169
        public int getNullsMode() {
1170
            return this.nullsMode;
1171
        }
1172

    
1173
        @Override
1174
        public String toString() {
1175
            return this.toString(formatter());
1176
        }
1177

    
1178
        @Override
1179
        public String toString(Formatter<Value> formatter) {
1180
            if (formatter!=null && formatter.canApply(this)) {
1181
                return formatter.format(this);
1182
            }
1183
            if (!StringUtils.isEmpty(this.custom)) {
1184
                return this.custom;
1185
            }
1186
            String order_s = this.value.toString(formatter);
1187
            if (this.ascending) {
1188
                order_s += " ASC";
1189
            } else {
1190
                order_s += " DESC";
1191
            }
1192
            switch(this.nullsMode) {
1193
                case MODE_NULLS_NOT_SPECIFIED:
1194
                    break;
1195
                case MODE_NULLS_FIRST:
1196
                    order_s += " NULLS FIRST";
1197
                    break;
1198
                case MODE_NULLS_LAST:
1199
                default:
1200
                    order_s += " NULLS LAST";
1201
                    break;
1202
            }
1203
            return order_s;
1204
        }
1205

    
1206
        @Override
1207
        public void replace(Value target, Value replacement) {
1208
            super.replace(target, replacement);
1209
            if(target == this.value){
1210
                this.value = replacement;
1211
                return;
1212
            }
1213
            if(this.value == null){
1214
                return;
1215
            }
1216
            this.value.replace(target, replacement);
1217
        }
1218
        
1219
        
1220
    }
1221

    
1222
    public class SelectBuilderBase
1223
            extends AbstractStatement
1224
            implements SelectBuilder {
1225

    
1226
        protected FromBuilder from;
1227
        protected GeometryExpressionBuilder where;
1228
        protected long limit = -1;
1229
        protected long offset = -1;
1230
        protected List<SelectColumnBuilder> columns;
1231
        protected List<OrderByBuilder> order_by;
1232
        protected boolean distinct;
1233
        protected List<Value> groupColumn;
1234
        protected boolean check_order_and_offset = true;
1235

    
1236
        public SelectBuilderBase() {
1237
            this.columns = new ArrayList<>();
1238
            this.distinct = false;
1239
        }
1240
        @Override
1241
        public List<Value> getGroups() {
1242
            return this.groupColumn;
1243
        }
1244
        
1245
        @Override
1246
        public List<SelectColumnBuilder> getColumns() {
1247
            return Collections.unmodifiableList(this.columns);
1248
    }
1249
        
1250
        @Override
1251
        public void remove_column(String columnName) {
1252
            SelectColumnBuilder found = null;
1253
            for (SelectColumnBuilder column : columns) {
1254
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1255
                    found = column;
1256
                    break;
1257
                }
1258
                    
1259
            }
1260
            if(found!=null) {
1261
                columns.remove(found);
1262
            }
1263
        }
1264

    
1265
        @Override
1266
        public SelectBuilder group_by(Value... columns) {
1267
            if( this.groupColumn==null ) {
1268
                this.groupColumn = new ArrayList<>();
1269
            }
1270
            for (Value column : columns) {
1271
                this.groupColumn.add(column);
1272
            }
1273
            return this;
1274
        }
1275

    
1276
        @Override
1277
        public void accept(Visitor visitor, VisitorFilter filter) {
1278
            boolean visitChildren = true;
1279
            if (filter==null || filter.accept(this)) {
1280
                visitor.visit(this);
1281
            } else {
1282
                visitChildren = !filter.skipChildren();
1283
            }
1284
            if(visitChildren){
1285
                for (SelectColumnBuilder column : columns) {
1286
                    column.accept(visitor, filter);
1287
                }
1288
                if (this.has_from()) {
1289
                    this.from.accept(visitor, filter);
1290
                }
1291
                if (this.has_where()) {
1292
                    this.where.accept(visitor, filter);
1293
                }
1294
                if (this.has_order_by()) {
1295
                    for (OrderByBuilder order : order_by) {
1296
                        order.accept(visitor, filter);
1297
                    }
1298
                }
1299
                if (this.has_group_by()) {
1300
                    for (Value group : groupColumn) {
1301
                        group.accept(visitor, filter);
1302
                    }
1303
                }
1304
            }
1305
        }
1306

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

    
1357
        @Override
1358
        public SelectBuilder distinct() {
1359
            this.distinct = true;
1360
            return this;
1361
        }
1362

    
1363
        @Override
1364
        public SelectColumnBuilder column() {
1365
            return column(createSelectColumnBuilder());
1366
        }
1367

    
1368
        @Override
1369
        public SelectColumnBuilder column(SelectColumnBuilder columnBuilder) {
1370
            this.columns.add(columnBuilder);
1371
            if( this.has_from() && !this.from().table().isEmpty() ) {
1372
                TableNameBuilder table = (TableNameBuilder) CloneableUtils.cloneQuietly(this.from().table());
1373
                columnBuilder.table(table);
1374
            }
1375
            return columnBuilder;
1376
        }
1377

    
1378
        @Override
1379
        public SelectColumnBuilder column(String name) {
1380
            for (SelectColumnBuilder column : columns) {
1381
                if (StringUtils.equals(name, column.getName())) {
1382
                    return column;
1383
                }
1384
            }
1385
            return column(createSelectColumnBuilder()).name(name);
1386
        }
1387

    
1388
        @Override
1389
        public SelectColumnBuilder getColumn(String name) {
1390
            for (SelectColumnBuilder column : columns) {
1391
                if (StringUtils.equals(name, column.getName())) {
1392
                    return column;
1393
                }
1394
            }
1395
            return null;
1396
        }
1397
        
1398
        @Override
1399
        public SelectBuilder remove_all_columns() {
1400
            this.columns = new ArrayList<>();
1401
            return this;
1402
        }
1403
        
1404
        @Override
1405
        public boolean has_column(String name) {
1406
            for (SelectColumnBuilder column : columns) {
1407
                if (StringUtils.equals(name, column.getName())) {
1408
                    return true;
1409
                }
1410
                if (StringUtils.equals(name, column.getAlias())) {
1411
                    return true;
1412
                }
1413
            }
1414
            return false;
1415
        }
1416

    
1417
        @Override
1418
        public FromBuilder from() {
1419
            if (this.from == null) {
1420
                this.from = createFromBuilder();
1421
            }
1422
            return this.from;
1423
        }
1424

    
1425
        @Override
1426
        public boolean has_from() {
1427
            return this.from != null;
1428
        }
1429

    
1430
        @Override
1431
        public GeometryExpressionBuilder where() {
1432
            if (this.where == null) {
1433
                this.where = createExpressionBuilder();
1434
            }
1435
            return this.where;
1436
        }
1437

    
1438
        @Override
1439
        public boolean has_where() {
1440
            if (this.where == null) {
1441
                return false;
1442
            }
1443
            return this.where.value() != null;
1444
        }
1445

    
1446
        @Override
1447
        public SelectBuilder limit(long limit) {
1448
            this.limit = limit;
1449
            return this;
1450
        }
1451

    
1452
        @Override
1453
        public SelectBuilder limit(Long limit) {
1454
            if (limit == null) {
1455
                this.limit = -1;
1456
            } else {
1457
                this.limit = limit;
1458
            }
1459
            return this;
1460
        }
1461

    
1462
        @Override
1463
        public boolean has_limit() {
1464
            return this.limit >= 0;
1465
        }
1466

    
1467
        @Override
1468
        public SelectBuilder offset(long offset) {
1469
            this.offset = offset;
1470
            return this;
1471
        }
1472

    
1473
        @Override
1474
        public boolean has_offset() {
1475
            return this.offset > 0;
1476
        }
1477

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

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

    
1580
        @Override
1581
        public String toString() {
1582
            return this.toString(formatter());
1583
        }
1584

    
1585
        @Override
1586
        public String toString(Formatter<Value> formatter) {
1587
            if (formatter!=null && formatter.canApply(this)) {
1588
                return formatter.format(this);
1589
            }
1590
            StringBuilder builder = new StringBuilder();
1591
            if (!this.isValid(builder)) {
1592
                throw new IllegalStateException(builder.toString());
1593
            }
1594
            builder.append("SELECT ");
1595
            if (this.distinct) {
1596
                builder.append("DISTINCT ");
1597
            }
1598
            boolean first = true;
1599
            for (SelectColumnBuilder column : columns) {
1600
                if (first) {
1601
                    first = false;
1602
                } else {
1603
                    builder.append(", ");
1604
                }
1605
                builder.append(column.toString(formatter));
1606
            }
1607

    
1608
            if (this.has_from()) {
1609
                builder.append(" FROM ");
1610
                builder.append(this.from.toString(formatter));
1611
            }
1612
            if (this.has_where()) {
1613
                builder.append(" WHERE ");
1614
                builder.append(this.where.toString(formatter));
1615
            }
1616
            if( this.has_group_by() ) {
1617
                builder.append(" GROUP BY ");
1618
                builder.append(this.groupColumn.get(0).toString(formatter));
1619
                for (int i = 1; i < groupColumn.size(); i++) {
1620
                    builder.append(", ");
1621
                    builder.append(this.groupColumn.get(i).toString(formatter));
1622
                }
1623
            }
1624
            if (this.has_order_by()) {
1625
                builder.append(" ORDER BY ");
1626
                first = true;
1627
                for (OrderByBuilder item : this.order_by) {
1628
                    if (first) {
1629
                        first = false;
1630
                    } else {
1631
                        builder.append(", ");
1632
                    }
1633
                    builder.append(item.toString(formatter));
1634
                }
1635
            }
1636

    
1637
            if (this.has_limit()) {
1638
                builder.append(" LIMIT ");
1639
                builder.append(this.limit);
1640
            }
1641
            if (this.has_offset()) {
1642
                builder.append(" OFFSET ");
1643
                builder.append(this.offset);
1644
            }
1645
            return builder.toString();
1646

    
1647
        }
1648
    }
1649

    
1650
    public class DropTableBuilderBase
1651
            extends AbstractStatement
1652
            implements DropTableBuilder {
1653

    
1654
        protected TableNameBuilder table;
1655

    
1656
        @Override
1657
        public TableNameBuilder table() {
1658
            if (table == null) {
1659
                table = createTableNameBuilder();
1660
            }
1661
            return table;
1662
        }
1663

    
1664
        @Override
1665
        public void accept(Visitor visitor, VisitorFilter filter) {
1666
            boolean visitChildren = true;
1667
            if (filter==null || filter.accept(this)) {
1668
                visitor.visit(this);
1669
            } else {
1670
                visitChildren = !filter.skipChildren();
1671
            }
1672
            if(visitChildren){
1673
                this.table.accept(visitor, filter);
1674
            }
1675
        }
1676

    
1677
        @Override
1678
        public String toString() {
1679
            return this.toString(formatter());
1680
        }
1681

    
1682
        @Override
1683
        public String toString(Formatter<Value> formatter) {
1684
            if (formatter!=null && formatter.canApply(this)) {
1685
                return formatter.format(this);
1686
            }
1687
            StringBuilder builder = new StringBuilder();
1688
            boolean first = true;
1689
            for (String sql : toStrings(formatter)) {
1690
                if (StringUtils.isEmpty(sql)) {
1691
                    continue;
1692
                }
1693
                if (first) {
1694
                    first = false;
1695
                } else {
1696
                    builder.append("; ");
1697
                }
1698
                builder.append(sql);
1699
            }
1700
            return builder.toString();
1701
        }
1702

    
1703
        @Override
1704
        public List<String> toStrings() {
1705
            return this.toStrings(formatter());
1706
        }
1707

    
1708
        @Override
1709
        public List<String> toStrings(Formatter formatter) {
1710
            List<String> sqls = new ArrayList<>();
1711

    
1712
            sqls.add(
1713
                    MessageFormat.format(
1714
                            STMT_DROP_TABLE_table,
1715
                            this.table.toString(formatter)
1716
                    )
1717
            );
1718
            String sql;
1719
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1720
                if (this.table.has_schema()) {
1721
                    sql = MessageFormat.format(
1722
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1723
                            as_string(this.table.getSchema()),
1724
                            as_string(this.table.getName())
1725
                    );
1726
                } else {
1727
                    sql = MessageFormat.format(
1728
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1729
                            as_identifier(this.table.getName())
1730
                    );
1731
                }
1732
                if (!StringUtils.isEmpty(sql)) {
1733
                    sqls.add(sql);
1734
                }
1735
            }
1736
            return sqls;
1737
        }
1738
    }
1739

    
1740
    public class GrantRoleBuilderBase
1741
            extends AbstractStatementPart
1742
            implements GrantRoleBuilder {
1743

    
1744
        protected TableNameBuilder table;
1745
        protected String role;
1746
        protected Set<Privilege> privileges;
1747

    
1748
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1749
            this.table = table;
1750
            this.role = role;
1751
            this.privileges = new HashSet<>();
1752
        }
1753
        
1754
        @Override
1755
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1756
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1757
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1758
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1759
            
1760
            return other;
1761
        }
1762

    
1763
        @Override
1764
        public GrantRoleBuilder privilege(Privilege privilege) {
1765
            privileges.add(privilege);
1766
            return this;
1767
        }
1768

    
1769
        @Override
1770
        public GrantRoleBuilder select() {
1771
            privileges.add(Privilege.SELECT);
1772
            return this;
1773
        }
1774

    
1775
        @Override
1776
        public GrantRoleBuilder update() {
1777
            privileges.add(Privilege.UPDATE);
1778
            return this;
1779
        }
1780

    
1781
        @Override
1782
        public GrantRoleBuilder insert() {
1783
            privileges.add(Privilege.INSERT);
1784
            return this;
1785
        }
1786

    
1787
        @Override
1788
        public GrantRoleBuilder delete() {
1789
            privileges.add(Privilege.DELETE);
1790
            return this;
1791
        }
1792

    
1793
        @Override
1794
        public GrantRoleBuilder truncate() {
1795
            privileges.add(Privilege.TRUNCATE);
1796
            return this;
1797
        }
1798

    
1799
        @Override
1800
        public GrantRoleBuilder reference() {
1801
            privileges.add(Privilege.REFERENCE);
1802
            return this;
1803
        }
1804

    
1805
        @Override
1806
        public GrantRoleBuilder trigger() {
1807
            privileges.add(Privilege.TRIGGER);
1808
            return this;
1809
        }
1810

    
1811
        @Override
1812
        public GrantRoleBuilder all() {
1813
            privileges.add(Privilege.ALL);
1814
            return this;
1815
        }
1816

    
1817
        protected String getPrivilegeName(Privilege privilege) {
1818
            switch (privilege) {
1819
                case DELETE:
1820
                    return "DELETE";
1821
                case INSERT:
1822
                    return "INSERT";
1823
                case REFERENCE:
1824
                    return "REFERENCE";
1825
                case SELECT:
1826
                    return "SELECT";
1827
                case TRIGGER:
1828
                    return "TRIGGER";
1829
                case TRUNCATE:
1830
                    return "TRUNCATE";
1831
                case UPDATE:
1832
                    return "UPDATE";
1833
                case ALL:
1834
                default:
1835
                    return "ALL";
1836
            }
1837
        }
1838

    
1839
        @Override
1840
        public String toString() {
1841
            return this.toString(formatter());
1842
        }
1843

    
1844
        @Override
1845
        public String toString(Formatter<Value> formatter) {
1846
            if (formatter!=null && formatter.canApply(this)) {
1847
                return formatter.format(this);
1848
            }
1849
            StringBuilder builder = new StringBuilder();
1850
            boolean first = true;
1851
            for (Privilege privilege : privileges) {
1852
                if (first) {
1853
                    first = false;
1854
                } else {
1855
                    builder.append(", ");
1856
                }
1857
                builder.append(this.getPrivilegeName(privilege));
1858
            }
1859
            String sql = MessageFormat.format(
1860
                    STMT_GRANT_privileges_ON_table_TO_role,
1861
                    builder.toString(),
1862
                    table.toString(formatter),
1863
                    role
1864
            );
1865
            return sql;
1866
        }
1867
    }
1868

    
1869
    public class GrantBuilderBase
1870
            extends AbstractStatement
1871
            implements GrantBuilder {
1872

    
1873
        protected TableNameBuilder table;
1874
        protected Map<String, GrantRoleBuilder> roles;
1875

    
1876
        public GrantBuilderBase() {
1877
            this.roles = new HashMap<>();
1878
        }
1879

    
1880
        @Override
1881
        public TableNameBuilder table() {
1882
            if (table == null) {
1883
                table = createTableNameBuilder();
1884
            }
1885
            return table;
1886
        }
1887

    
1888
        @Override
1889
        public void accept(Visitor visitor, VisitorFilter filter) {
1890
            boolean visitChildren = true;
1891
            if (filter==null || filter.accept(this)) {
1892
                visitor.visit(this);
1893
            } else {
1894
                visitChildren = !filter.skipChildren();
1895
            }
1896
            if(visitChildren){
1897
                if (this.table != null) {
1898
                    this.table.accept(visitor, filter);
1899
                }
1900
            }
1901
        }
1902

    
1903
        @Override
1904
        public GrantRoleBuilder role(String role) {
1905
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1906
            if (roleBuilder == null) {
1907
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1908
                this.roles.put(role, roleBuilder);
1909
            }
1910
            return roleBuilder;
1911
        }
1912

    
1913
        @Override
1914
        public String toString() {
1915
            return this.toString(formatter());
1916
        }
1917

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

    
1939
        @Override
1940
        public List<String> toStrings() {
1941
            return this.toStrings(formatter());
1942
        }
1943

    
1944
        @Override
1945
        public List<String> toStrings(Formatter formatter) {
1946
            List<String> sqls = new ArrayList<>();
1947
            for (GrantRoleBuilder role : roles.values()) {
1948
                sqls.add(role.toString(formatter));
1949
            }
1950
            return sqls;
1951
        }
1952
    }
1953

    
1954
    public class UpdateColumnBuilderBase
1955
            extends InsertColumnBuilderBase
1956
            implements UpdateColumnBuilder {
1957

    
1958
        public UpdateColumnBuilderBase() {
1959
            super();
1960
        }
1961

    
1962
        @Override
1963
        public UpdateColumnBuilder name(String name) {
1964
            return (UpdateColumnBuilder) super.name(name);
1965
        }
1966

    
1967
        @Override
1968
        public UpdateColumnBuilder with_value(Value value) {
1969
            return (UpdateColumnBuilder) super.with_value(value);
1970
        }
1971

    
1972
    }
1973

    
1974
    public class UpdateBuilderBase
1975
            extends AbstractStatement
1976
            implements UpdateBuilder {
1977

    
1978
        protected GeometryExpressionBuilder where;
1979
        protected List<UpdateColumnBuilder> columns;
1980
        protected TableNameBuilder table;
1981

    
1982
        public UpdateBuilderBase() {
1983
            this.columns = new ArrayList<>();
1984
        }
1985

    
1986
        @Override
1987
        public void accept(Visitor visitor, VisitorFilter filter) {
1988
            boolean visitChildren = true;
1989
            if (filter==null || filter.accept(this)) {
1990
                visitor.visit(this);
1991
            } else {
1992
                visitChildren = !filter.skipChildren();
1993
            }
1994
            if(visitChildren){
1995
                if (this.table != null) {
1996
                    this.table.accept(visitor, filter);
1997
                }
1998
                for (UpdateColumnBuilder column : columns) {
1999
                    column.accept(visitor, filter);
2000
                }
2001
                if (this.has_where()) {
2002
                    this.where.accept(visitor, filter);
2003
                }
2004
            }
2005
        }
2006

    
2007
        @Override
2008
        public GeometryExpressionBuilder where() {
2009
            if (this.where == null) {
2010
                this.where = createExpressionBuilder();
2011
            }
2012
            return this.where;
2013
        }
2014

    
2015
        @Override
2016
        public TableNameBuilder table() {
2017
            if (table == null) {
2018
                table = createTableNameBuilder();
2019
            }
2020
            return table;
2021
        }
2022

    
2023
        @Override
2024
        public UpdateColumnBuilder column() {
2025
            UpdateColumnBuilder column = createUpdateColumnBuilder();
2026
            this.columns.add(column);
2027
            return column;
2028
        }
2029

    
2030
        @Override
2031
        public boolean has_where() {
2032
            return this.where != null;
2033
        }
2034

    
2035
        @Override
2036
        public String toString() {
2037
            return this.toString(formatter());
2038
        }
2039

    
2040
        @Override
2041
        public String toString(Formatter<Value> formatter) {
2042
            if (formatter!=null && formatter.canApply(this)) {
2043
                return formatter.format(this);
2044
            }
2045
            /*
2046
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
2047
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
2048
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
2049
             * output_expression [ AS output_name ] [, ...] ]
2050
             */
2051
            StringBuilder columnsAndValues = new StringBuilder();
2052

    
2053
            boolean first = true;
2054
            for (UpdateColumnBuilder column : columns) {
2055
                if (first) {
2056
                    first = false;
2057
                } else {
2058
                    columnsAndValues.append(", ");
2059
                }
2060
                columnsAndValues.append(as_identifier(column.getName()));
2061
                columnsAndValues.append(" = ");
2062
                columnsAndValues.append(column.getValue().toString(formatter));
2063
            }
2064

    
2065
            String sql;
2066
            if (this.has_where()) {
2067
                sql = MessageFormat.format(
2068
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
2069
                        this.table.toString(formatter),
2070
                        columnsAndValues.toString(),
2071
                        this.where.toString(formatter)
2072
                );
2073
            } else {
2074
                sql = MessageFormat.format(
2075
                        STMT_UPDATE_table_SET_columnsAndValues,
2076
                        this.table.toString(formatter),
2077
                        columnsAndValues.toString()
2078
                );
2079
            }
2080
            return sql;
2081
        }
2082
    }
2083

    
2084
    public class DeleteBuilderBase
2085
            extends AbstractStatement
2086
            implements DeleteBuilder {
2087

    
2088
        protected GeometryExpressionBuilder where;
2089
        protected TableNameBuilder table;
2090

    
2091
        public DeleteBuilderBase() {
2092
        }
2093

    
2094
        @Override
2095
        public void accept(Visitor visitor, VisitorFilter filter) {
2096
            boolean visitChildren = true;
2097
            if (filter==null || filter.accept(this)) {
2098
                visitor.visit(this);
2099
            } else {
2100
                visitChildren = !filter.skipChildren();
2101
            }
2102
            if(visitChildren){
2103
                if (this.table != null) {
2104
                    this.table.accept(visitor, filter);
2105
                }
2106
                if (this.has_where()) {
2107
                    this.where.accept(visitor, filter);
2108
                }
2109
            }
2110
        }
2111

    
2112
        @Override
2113
        public GeometryExpressionBuilder where() {
2114
            if (this.where == null) {
2115
                this.where = createExpressionBuilder();
2116
            }
2117
            return this.where;
2118
        }
2119

    
2120
        @Override
2121
        public TableNameBuilder table() {
2122
            if (table == null) {
2123
                table = createTableNameBuilder();
2124
            }
2125
            return table;
2126
        }
2127

    
2128
        @Override
2129
        public boolean has_where() {
2130
            return this.where != null;
2131
        }
2132

    
2133
        @Override
2134
        public String toString() {
2135
            return this.toString(formatter());
2136
        }
2137

    
2138
        @Override
2139
        public String toString(Formatter<Value> formatter) {
2140
            if (formatter!=null && formatter.canApply(this)) {
2141
                return formatter.format(this);
2142
            }
2143
            /*
2144
             * DELETE FROM table_name
2145
             * WHERE some_column=some_value; 
2146
             */
2147
            String sql;
2148
            if (this.has_where()) {
2149
                sql = MessageFormat.format(
2150
                        STMT_DELETE_FROM_table_WHERE_expresion,
2151
                        this.table.toString(formatter),
2152
                        this.where.toString(formatter)
2153
                );
2154
            } else {
2155
                sql = MessageFormat.format(
2156
                        STMT_DELETE_FROM_table,
2157
                        this.table.toString(formatter)
2158
                );
2159
            }
2160
            return sql;
2161
        }
2162
    }
2163

    
2164
    public class CreateIndexBuilderBase
2165
            extends AbstractStatement
2166
            implements CreateIndexBuilder {
2167

    
2168
        protected boolean ifNotExist = false;
2169
        protected boolean isUnique = false;
2170
        protected String indexName;
2171
        protected boolean isSpatial = false;
2172
        protected TableNameBuilder table;
2173
        protected final List<String> columns;
2174
        protected FeatureType type;
2175

    
2176
        public CreateIndexBuilderBase() {
2177
            this.columns = new ArrayList<>();
2178
        }
2179

    
2180
        @Override
2181
        public CreateIndexBuilder unique() {
2182
            this.isUnique = true;
2183
            return this;
2184
        }
2185

    
2186
        @Override
2187
        public CreateIndexBuilder if_not_exist() {
2188
            this.ifNotExist = true;
2189
            return this;
2190
        }
2191

    
2192
        @Override
2193
        public CreateIndexBuilder name(String name) {
2194
            this.indexName = name;
2195
            return this;
2196
        }
2197

    
2198
        @Override
2199
        public CreateIndexBuilder name(String tableName, String columnName) {
2200
            this.indexName = tableName + "_IDX_" + columnName;
2201
            return this;
2202
        }
2203

    
2204
        @Override
2205
        public CreateIndexBuilder spatial() {
2206
            this.isSpatial = true;
2207
            return this;
2208
        }
2209

    
2210
        @Override
2211
        public CreateIndexBuilder column(String name) {
2212
            this.columns.add(name);
2213
            return this;
2214
        }
2215

    
2216
        @Override
2217
        public TableNameBuilder table() {
2218
            if (table == null) {
2219
                table = createTableNameBuilder();
2220
            }
2221
            return table;
2222
        }
2223

    
2224
        @Override
2225
        public void setFeatureType(FeatureType type) {
2226
            this.type = type;
2227
        }
2228

    
2229
        @Override
2230
        public void accept(Visitor visitor, VisitorFilter filter) {
2231
            boolean visitChildren = true;
2232
            if (filter==null || filter.accept(this)) {
2233
                visitor.visit(this);
2234
            } else {
2235
                visitChildren = !filter.skipChildren();
2236
            }
2237
            if(visitChildren){
2238
                if (this.table != null) {
2239
                    this.table.accept(visitor, filter);
2240
                }
2241
            }
2242
        }
2243

    
2244
        @Override
2245
        public String toString() {
2246
            return this.toString(formatter());
2247
        }
2248

    
2249
        @Override
2250
        public String toString(Formatter<Value> formatter) {
2251
            if (formatter!=null && formatter.canApply(this)) {
2252
                return formatter.format(this);
2253
            }
2254
            StringBuilder builder = new StringBuilder();
2255
            boolean first = true;
2256
            for (String sql : toStrings(formatter)) {
2257
                if (StringUtils.isEmpty(sql)) {
2258
                    continue;
2259
                }
2260
                if (first) {
2261
                    first = false;
2262
                } else {
2263
                    builder.append("; ");
2264
                }
2265
                builder.append(sql);
2266
            }
2267
            return builder.toString();
2268
        }
2269

    
2270
        @Override
2271
        public List<String> toStrings() {
2272
            return this.toStrings(formatter());
2273
        }
2274

    
2275
        @Override
2276
        public List<String> toStrings(Formatter formatter) {
2277
            StringBuilder builder = new StringBuilder();
2278
            builder.append("CREATE ");
2279
            if (this.isUnique) {
2280
                builder.append("UNIQUE ");
2281
            }
2282
            builder.append("INDEX ");
2283
            if (this.ifNotExist) {
2284
                builder.append("IF NOT EXISTS ");
2285
            }
2286
            builder.append(as_identifier(this.indexName));
2287
            builder.append(" ON ");
2288
            builder.append(this.table.toString(formatter));
2289
            if (this.isSpatial) {
2290
                builder.append(" USING GIST ");
2291
            }
2292
            builder.append(" ( ");
2293
            boolean is_first_column = true;
2294
            for (String column : this.columns) {
2295
                if (is_first_column) {
2296
                    is_first_column = false;
2297
                } else {
2298
                    builder.append(", ");
2299
                }
2300
                builder.append(column);
2301
            }
2302
            builder.append(" )");
2303

    
2304
            List<String> sqls = new ArrayList<>();
2305
            sqls.add(builder.toString());
2306
            return sqls;
2307
        }
2308

    
2309
    }
2310

    
2311
    public class DropIndexBuilderBase
2312
            extends AbstractStatement
2313
            implements DropIndexBuilder {
2314

    
2315
        protected boolean ifExist = false;
2316
        protected String indexName;
2317

    
2318
        public DropIndexBuilderBase() {
2319
        }
2320

    
2321
        @Override
2322
        public DropIndexBuilder if_exist() {
2323
            this.ifExist = true;
2324
            return this;
2325
        }
2326

    
2327
        @Override
2328
        public DropIndexBuilder name(String name) {
2329
            this.indexName = name;
2330
            return this;
2331
        }
2332

    
2333
        @Override
2334
        public DropIndexBuilder name(String tableName, String columnName) {
2335
            this.indexName = tableName + "_IDX_" + columnName;
2336
            return this;
2337
        }
2338

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

    
2344
        @Override
2345
        public String toString(Formatter<Value> formatter) {
2346
            if (formatter!=null && formatter.canApply(this)) {
2347
                return formatter.format(this);
2348
            }
2349
            StringBuilder builder = new StringBuilder();
2350
            boolean first = true;
2351
            for (String sql : toStrings(formatter)) {
2352
                if (StringUtils.isEmpty(sql)) {
2353
                    continue;
2354
                }
2355
                if (first) {
2356
                    first = false;
2357
                } else {
2358
                    builder.append("; ");
2359
                }
2360
                builder.append(sql);
2361
            }
2362
            return builder.toString();
2363
        }
2364

    
2365
        @Override
2366
        public List<String> toStrings() {
2367
            return this.toStrings(formatter());
2368
        }
2369

    
2370
        @Override
2371
        public List<String> toStrings(Formatter formatter) {
2372
            StringBuilder builder = new StringBuilder();
2373
            builder.append("DROP INDEX ");
2374
            if (this.ifExist) {
2375
                builder.append("IF EXISTS ");
2376
            }
2377
            builder.append(as_identifier(this.indexName));
2378
            List<String> sqls = new ArrayList<>();
2379
            sqls.add(builder.toString());
2380
            return sqls;
2381
        }
2382

    
2383
    }
2384

    
2385
    public class AlterTableBuilderBase
2386
            extends AbstractStatement
2387
            implements AlterTableBuilder {
2388
             
2389
        protected TableNameBuilder table;
2390
        protected List<String> drops;
2391
        protected List<ColumnDescriptor> adds;
2392
        
2393
        // alters debera dejarse de usar en favor de operations
2394
        @Deprecated
2395
        protected List<ColumnDescriptor> alters;
2396
        protected List<Pair<Bitmask,ColumnDescriptor>> operations;
2397
        
2398
        protected List<Pair<String, String>> renames;
2399
        protected String drop_primary_key_column;
2400
        protected final SQLBuilderBase sqlbuilder;
2401

    
2402
        public AlterTableBuilderBase(SQLBuilderBase sqlbuilder) {
2403
            this.sqlbuilder = sqlbuilder;
2404
            this.drops = new ArrayList<>();
2405
            this.adds = new ArrayList<>();
2406
            this.alters = new ArrayList<>();
2407
            this.operations = new ArrayList<>();
2408
            this.renames = new ArrayList<>();
2409
        }
2410

    
2411
        public List<Pair<Bitmask,ColumnDescriptor>> getOperations() {
2412
            return this.operations;
2413
        }
2414
        
2415
        @Override
2416
        public boolean isEmpty() {
2417
            return this.drops.isEmpty()
2418
                    && this.adds.isEmpty()
2419
                    && this.alters.isEmpty()
2420
                    && this.operations.isEmpty()
2421
                    && this.renames.isEmpty();
2422
        }
2423

    
2424
        @Override
2425
        public void accept(Visitor visitor, VisitorFilter filter) {
2426
            boolean visitChildren = true;
2427
            if (filter==null || filter.accept(this)) {
2428
                visitor.visit(this);
2429
            } else {
2430
                visitChildren = !filter.skipChildren();
2431
            }
2432
            if(visitChildren){
2433
                if (this.table != null) {
2434
                    this.table.accept(visitor, filter);
2435
                }
2436
            }
2437
        }
2438

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

    
2447
        @Override
2448
        public AlterTableBuilder drop_column(String columnName) {
2449
            this.drops.add(columnName);
2450
            return this;
2451
        }
2452

    
2453
        @Override
2454
        public AlterTableBuilder drop_primary_key(String columnName) {
2455
            this.drop_primary_key_column = columnName;
2456
            return this;
2457
        }
2458

    
2459
        @Override
2460
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2461
            this.adds.add(new ColumnDescriptorBase(fad));
2462
            return this;
2463
        }
2464

    
2465
        @Override
2466
        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) {
2467
            if (isPk || isAutomatic) {
2468
                allowNulls = false;
2469
            }
2470
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds));
2471
            return this;
2472
        }
2473

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

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

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

    
2523
        @Override
2524
        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) {
2525
            if ( (isPk || isAutomatic) && allowNulls) {
2526
                allowNulls = false;
2527
                operation.setBit(ALTER_COLUMN_SET_NULL);
2528
            }
2529
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds);
2530
            update_or_add_alters(column);
2531
            if( operation == null ) {
2532
                operation = Bitmask.createBitmask(0);
2533
            }
2534
            if( operation.isEmpty() ) {
2535
                operation.setBit(ALTER_COLUMN_ALL);
2536
            }
2537
            this.operations.add(new ImmutablePair<>(operation,column));
2538
            return this;
2539
        }
2540

    
2541
//        @Override
2542
//        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) {
2543
//            if ( (isPk || isAutomatic) && allowNulls) {
2544
//                allowNulls = false;
2545
//                operation.setBit(ALTER_COLUMN_SET_NULL);
2546
//            }
2547
//            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue);
2548
//            update_or_add_alters(column);
2549
//            this.operations.add(new ImmutablePair<>(operation,column));
2550
//            return this;
2551
//        }
2552

    
2553
        @Override
2554
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2555
            if (StringUtils.isEmpty(columnName)) {
2556
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2557
            }
2558
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls);
2559
            update_or_add_alters(column);
2560
            if( operation == null ) {
2561
                operation = Bitmask.createBitmask(0);
2562
            }
2563
            if( operation.isEmpty() ) {
2564
                operation.setBit(ALTER_COLUMN_ALL);
2565
            }
2566
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2567
            this.operations.add(new ImmutablePair<>(operation,column));
2568
            return this;
2569
        }
2570

    
2571
        @Override
2572
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2573
            if (StringUtils.isEmpty(columnName)) {
2574
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2575
            }
2576
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls);
2577
            update_or_add_alters(column);
2578
            if( operation == null ) {
2579
                operation = Bitmask.createBitmask(0);
2580
            }
2581
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2582
            this.operations.add(new ImmutablePair<>(operation,column));
2583
            return this;
2584
        }
2585

    
2586
        @Override
2587
        public AlterTableBuilder rename_column(String source, String target) {
2588
            this.renames.add(new ImmutablePair(source, target));
2589
            return this;
2590
        }
2591

    
2592
        protected String getConstrainName(String constrainType, String columnName) {
2593
            return this.sqlbuilder.getConstrainName(table, columnName, constrainType);
2594
        }
2595

    
2596
        protected List<String> alter_table_add_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2597
            // ALTER TABLE table_name ADD CONSTRAINT IF NOT EXISTS constraint_name PRIMARY KEY(column_name)
2598
            List<String> sqls = new ArrayList<>();
2599
            StringBuilder builder = new StringBuilder();
2600
            builder.append("ALTER TABLE ");
2601
            builder.append(this.table.toString(formatter));
2602
            builder.append(" ADD CONSTRAINT ");
2603
            builder.append("IF NOT EXISTS ");
2604
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2605
            builder.append(" PRIMARY KEY( ");
2606
            builder.append(as_identifier(column.getName()));
2607
            builder.append(" )");
2608
            sqls.add(builder.toString());
2609
            return sqls;
2610
        }
2611

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

    
2642
        protected List<String> drop_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2643
            DropIndexBuilder dropIndex = this.sqlbuilder.createDropIndexBuilder();
2644
            dropIndex.if_exist();
2645
            dropIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2646
            return dropIndex.toStrings();
2647
        }
2648

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

    
2693
        protected List<String> alter_table_alter_column_set_null_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2694
            StringBuilder builder = new StringBuilder();
2695
            builder.append("ALTER TABLE ");
2696
            builder.append(this.table.toString(formatter));
2697
            builder.append(" ALTER COLUMN ");
2698
            builder.append(as_identifier(column.getName()));
2699
            if (column.allowNulls()) {
2700
                builder.append(" SET NULL");
2701
            } else {
2702
                builder.append(" SET NOT NULL");
2703
            }
2704
            return Collections.singletonList(builder.toString());
2705
        }
2706

    
2707
        protected List<String> alter_table_drop_column_sqls(Formatter<Value> formatter, String columnName) {
2708
            StringBuilder builder = new StringBuilder();
2709
            builder.append("ALTER TABLE ");
2710
            builder.append(this.table.toString(formatter));
2711
            builder.append(" DROP COLUMN ");
2712
            builder.append(" IF EXISTS ");
2713
            builder.append(as_identifier(columnName));
2714
            return Collections.singletonList(builder.toString());
2715
        }
2716

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

    
2767
        protected List<String> alter_table_alter_column_rename_sqls(Formatter<Value> formatter, String oldName, String newName) {
2768
            StringBuilder builder = new StringBuilder();
2769
            builder.append("ALTER TABLE ");
2770
            builder.append(this.table.toString(formatter));
2771
            builder.append(" ALTER COLUMN ");
2772
            builder.append(as_identifier(oldName));
2773
            builder.append(" RENAME TO ");
2774
            builder.append(as_identifier(newName));
2775
            return Collections.singletonList(builder.toString());
2776
        }
2777

    
2778
        protected List<String> alter_column_add_geometry_constraint_sqls(Formatter<ExpressionBuilder.Value> formatter, ColumnDescriptor column) {
2779
            return Collections.EMPTY_LIST;
2780
        }
2781
        
2782
        @Override
2783
        public String toString() {
2784
            return this.toString(formatter());
2785
        }
2786

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

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

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

    
2887
    }
2888

    
2889
    public class CreateTableBuilderBase
2890
            extends AbstractStatement
2891
            implements CreateTableBuilder {
2892

    
2893
        protected TableNameBuilder table;
2894
        protected List<ColumnDescriptor> columns;
2895

    
2896
        public CreateTableBuilderBase() {
2897
            this.columns = new ArrayList<>();
2898
        }
2899

    
2900
        @Override
2901
        public void accept(Visitor visitor, VisitorFilter filter) {
2902
            boolean visitChildren = true;
2903
            if (filter==null || filter.accept(this)) {
2904
                visitor.visit(this);
2905
            } else {
2906
                visitChildren = !filter.skipChildren();
2907
            }
2908
            if(visitChildren){
2909
                if (this.table != null) {
2910
                    this.table.accept(visitor, filter);
2911
                }
2912
            }
2913
        }
2914

    
2915
        @Override
2916
        public TableNameBuilder table() {
2917
            if (table == null) {
2918
                table = createTableNameBuilder();
2919
            }
2920
            return table;
2921
        }
2922

    
2923
        @Override
2924
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2925
            this.columns.add(new ColumnDescriptorBase(fad));
2926
            return this;
2927
        }
2928

    
2929
        @Override
2930
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2931
            if (StringUtils.isEmpty(columnName)) {
2932
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2933
            }
2934
            if (isPk || isAutomatic) {
2935
                allowNulls = false;
2936
            }
2937
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2938
            return this;
2939
        }
2940

    
2941
        @Override
2942
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2943
            if (StringUtils.isEmpty(columnName)) {
2944
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2945
            }
2946
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2947
            return this;
2948
        }
2949

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

    
2959
        @Override
2960
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2961
            if (StringUtils.isEmpty(columnName)) {
2962
                return null;
2963
            }
2964
            for (ColumnDescriptor column : columns) {
2965
                if (columnName.equals(column.getName())) {
2966
                    return column;
2967
                }
2968
            }
2969
            return null;
2970
        }
2971

    
2972
        @Override
2973
        public String toString() {
2974
            return this.toString(formatter());
2975
        }
2976

    
2977
        @Override
2978
        public String toString(Formatter<Value> formatter) {
2979
            if (formatter!=null && formatter.canApply(this)) {
2980
                return formatter.format(this);
2981
            }
2982
            StringBuilder builder = new StringBuilder();
2983
            boolean first = true;
2984
            for (String sql : toStrings(formatter)) {
2985
                if (StringUtils.isEmpty(sql)) {
2986
                    continue;
2987
                }
2988
                if (first) {
2989
                    first = false;
2990
                } else {
2991
                    builder.append("; ");
2992
                }
2993
                builder.append(sql);
2994
            }
2995
            return builder.toString();
2996
        }
2997

    
2998
        @Override
2999
        public List<String> toStrings() {
3000
            return this.toStrings(formatter());
3001
        }
3002

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

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

    
3090
    public class InsertColumnBuilderBase
3091
            extends AbstractStatement
3092
            implements InsertColumnBuilder {
3093

    
3094
        protected Variable name;
3095
        protected Value value;
3096

    
3097
        public InsertColumnBuilderBase() {
3098
        }
3099

    
3100
        @Override
3101
        public void accept(Visitor visitor, VisitorFilter filter) {
3102
            boolean visitChildren = true;
3103
            if (filter==null || filter.accept(this)) {
3104
                visitor.visit(this);
3105
            } else {
3106
                visitChildren = !filter.skipChildren();
3107
            }
3108
            if(visitChildren){
3109
                if (this.name != null) {
3110
                    this.name.accept(visitor, filter);
3111
                }
3112
                if (this.value != null) {
3113
                    this.value.accept(visitor, filter);
3114
                }
3115
            }
3116
        }
3117

    
3118
        @Override
3119
        public InsertColumnBuilder name(String name) {
3120
            this.name = expression().variable(name);
3121
            return this;
3122
        }
3123

    
3124
        @Override
3125
        public InsertColumnBuilder with_value(Value value) {
3126
            this.value = value;
3127
            return this;
3128
        }
3129

    
3130
        @Override
3131
        public String getName() {
3132
            return this.name.name();
3133
        }
3134

    
3135
        @Override
3136
        public Value getValue() {
3137
            return this.value;
3138
        }
3139

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

    
3145
        @Override
3146
        public String toString(Formatter<Value> formatter) {
3147
            if (formatter!=null && formatter.canApply(this)) {
3148
                return formatter.format(this);
3149
            }
3150
            return this.value.toString(formatter);
3151
        }
3152
    }
3153

    
3154
    public class MergeBuilderBase
3155
            extends InsertBuilderBase
3156
            implements MergeBuilder {
3157
        
3158
        protected List<String> keycolumns;
3159
        
3160
        public MergeBuilderBase() {
3161
            super();
3162
            this.keycolumns = new ArrayList<>();
3163
        }
3164

    
3165
        @Override
3166
        public MergeBuilder key(String id) {
3167
            this.keycolumns.add(id);
3168
            return this;
3169
        }
3170
        
3171
        @Override
3172
        public String toString(Formatter<Value> formatter) {
3173
            if (formatter!=null && formatter.canApply(this)) {
3174
                return formatter.format(this);
3175
            }
3176
            /*
3177
             * MERGE INTO table [ ( column [, ...] ) ] KEY (columnName [,...] ) { DEFAULT VALUES | VALUES (
3178
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3179
             * output_expression [ AS output_name ] [, ...] ]
3180
             */
3181
            StringBuilder builderKeyColumns = new StringBuilder();
3182
            StringBuilder builderColumns = new StringBuilder();
3183
            StringBuilder builderValues = new StringBuilder();
3184

    
3185
            boolean first = true;
3186
            for (InsertColumnBuilder column : columns) {
3187
                if (first) {
3188
                    first = false;
3189
                } else {
3190
                    builderColumns.append(", ");
3191
                }
3192
                builderColumns.append(as_identifier(column.getName()));
3193
            }
3194
            first = true;
3195
            for (String column : keycolumns) {
3196
                if (first) {
3197
                    first = false;
3198
                } else {
3199
                    builderKeyColumns.append(", ");
3200
                }
3201
                builderKeyColumns.append(as_identifier(column));
3202
            }
3203
            first = true;
3204
            for (InsertColumnBuilder column : columns) {
3205
                if (first) {
3206
                    first = false;
3207
                } else {
3208
                    builderValues.append(", ");
3209
                }
3210
                builderValues.append(column.toString(formatter));
3211
            }
3212

    
3213
            String sql = MessageFormat.format(
3214
                    STMT_MERGE_INTO_table_KEY_column_columns_VALUES_values,
3215
                    this.table.toString(formatter),
3216
                    builderColumns.toString(),
3217
                    builderKeyColumns.toString(),
3218
                    builderValues.toString()
3219
            );
3220
            return sql;
3221

    
3222
        }
3223
    }
3224

    
3225
    
3226
    public class InsertBuilderBase
3227
            extends AbstractStatement
3228
            implements InsertBuilder {
3229

    
3230
        protected List<InsertColumnBuilder> columns;
3231
        protected TableNameBuilder table;
3232

    
3233
        public InsertBuilderBase() {
3234
            this.columns = new ArrayList<>();
3235
        }
3236

    
3237
        @Override
3238
        public void accept(Visitor visitor, VisitorFilter filter) {
3239
            boolean visitChildren = true;
3240
            if (filter==null || filter.accept(this)) {
3241
                visitor.visit(this);
3242
            } else {
3243
                visitChildren = !filter.skipChildren();
3244
            }
3245
            if(visitChildren){
3246
                if (this.table != null) {
3247
                    this.table.accept(visitor, filter);
3248
                }
3249
                for (InsertColumnBuilder column : columns) {
3250
                    column.accept(visitor, filter);
3251
                }
3252
            }
3253
        }
3254

    
3255
        @Override
3256
        public TableNameBuilder table() {
3257
            if (table == null) {
3258
                table = createTableNameBuilder();
3259
            }
3260
            return table;
3261
        }
3262

    
3263
        @Override
3264
        public InsertColumnBuilder column() {
3265
            InsertColumnBuilder column = createInsertColumnBuilder();
3266
            this.columns.add(column);
3267
            return column;
3268
        }
3269

    
3270
        @Override
3271
        public String toString() {
3272
            return this.toString(formatter());
3273
        }
3274

    
3275
        @Override
3276
        public String toString(Formatter<Value> formatter) {
3277
            if (formatter!=null && formatter.canApply(this)) {
3278
                return formatter.format(this);
3279
            }
3280
            /*
3281
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
3282
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3283
             * output_expression [ AS output_name ] [, ...] ]
3284
             */
3285
            StringBuilder builderColumns = new StringBuilder();
3286
            StringBuilder builderValues = new StringBuilder();
3287

    
3288
            boolean first = true;
3289
            for (InsertColumnBuilder column : columns) {
3290
                if (first) {
3291
                    first = false;
3292
                } else {
3293
                    builderColumns.append(", ");
3294
                }
3295
                builderColumns.append(as_identifier(column.getName()));
3296
            }
3297
            first = true;
3298
            for (InsertColumnBuilder column : columns) {
3299
                if (first) {
3300
                    first = false;
3301
                } else {
3302
                    builderValues.append(", ");
3303
                }
3304
                builderValues.append(column.toString(formatter));
3305
            }
3306

    
3307
            String sql = MessageFormat.format(
3308
                    STMT_INSERT_INTO_table_columns_VALUES_values,
3309
                    this.table.toString(formatter),
3310
                    builderColumns.toString(),
3311
                    builderValues.toString()
3312
            );
3313
            return sql;
3314

    
3315
        }
3316
    }
3317

    
3318
    public class UpdateTableStatisticsBuilderBase
3319
            extends AbstractStatement
3320
            implements UpdateTableStatisticsBuilder {
3321

    
3322
        protected TableNameBuilder table;
3323

    
3324
        @Override
3325
        public void accept(Visitor visitor, VisitorFilter filter) {
3326
            boolean visitChildren = true;
3327
            if (filter==null || filter.accept(this)) {
3328
                visitor.visit(this);
3329
            } else {
3330
                visitChildren = !filter.skipChildren();
3331
            }
3332
            if(visitChildren){
3333
                if (this.table != null) {
3334
                    this.table.accept(visitor, filter);
3335
                }
3336
            }
3337
        }
3338

    
3339
        @Override
3340
        public TableNameBuilder table() {
3341
            if (table == null) {
3342
                table = createTableNameBuilder();
3343
            }
3344
            return table;
3345
        }
3346

    
3347
        @Override
3348
        public String toString() {
3349
            return this.toString(formatter());
3350
        }
3351

    
3352
        @Override
3353
        public String toString(Formatter<Value> formatter) {
3354
            if (formatter!=null && formatter.canApply(this)) {
3355
                return formatter.format(this);
3356
            }
3357
            StringBuilder builder = new StringBuilder();
3358
            boolean first = true;
3359
            for (String sql : toStrings(formatter)) {
3360
                if (StringUtils.isEmpty(sql)) {
3361
                    continue;
3362
                }
3363
                if (first) {
3364
                    first = false;
3365
                } else {
3366
                    builder.append("; ");
3367
                }
3368
                builder.append(sql);
3369
            }
3370
            return builder.toString();
3371
        }
3372

    
3373
        @Override
3374
        public List<String> toStrings() {
3375
            return this.toStrings(formatter());
3376
        }
3377

    
3378
        @Override
3379
        public List<String> toStrings(Formatter formatter) {
3380
            List<String> sqls = new ArrayList<>();
3381

    
3382
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
3383
                String sql = MessageFormat.format(
3384
                        STMT_UPDATE_TABLE_STATISTICS_table,
3385
                        table.toString(formatter)
3386
                );
3387
                if (!StringUtils.isEmpty(sql)) {
3388
                    sqls.add(sql);
3389
                }
3390
            }
3391
            return sqls;
3392
        }
3393
    }
3394

    
3395
    protected GeometryExpressionBuilder expressionBuilder;
3396

    
3397
    protected String defaultSchema;
3398
    protected boolean supportSchemas;
3399
    protected boolean hasSpatialFunctions;
3400
    protected GeometrySupportType geometrySupportType;
3401
    protected boolean allowAutomaticValues;
3402

    
3403
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
3404

    
3405
    protected String constant_true = "(1=1)";
3406
    protected String constant_false = "(1<>1)";
3407

    
3408
    protected String type_boolean = "BOOLEAN";
3409
    protected String type_byte = "TINYINT";
3410
    protected String type_bytearray = "BYTEA";
3411
    protected String type_geometry = "TEXT";
3412
    protected String type_char = "CHARACTER(1)";
3413
    protected String type_date = "DATE";
3414
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
3415
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
3416
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
3417
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
3418
    protected String type_int = "INT";
3419
    protected String type_long = "BIGINT";
3420
    protected String type_string = "TEXT";
3421
    protected String type_string_p = "VARCHAR({0,Number,#######})";
3422
    protected String type_time = "TIME";
3423
    protected String type_timestamp = "TIMESTAMP";
3424
    protected String type_version = "VARCHAR(30)";
3425
    protected String type_URI = "TEXT";
3426
    protected String type_URL = "TEXT";
3427
    protected String type_FILE = "TEXT";
3428
    protected String type_FOLDER = "TEXT";
3429

    
3430
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
3431
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
3432
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
3433
    protected String STMT_MERGE_INTO_table_KEY_column_columns_VALUES_values = "MERGE INTO {0} ( {1} )  KEY( {2} ) VALUES ( {3} )";
3434
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
3435
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
3436
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
3437
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
3438
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
3439
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
3440
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3441

    
3442
    public SQLBuilderBase() {
3443
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3444
        this.expressionBuilder.setProperty(PROP_SQLBUILDER, this);
3445

    
3446
        this.hasSpatialFunctions = false;
3447
        this.supportSchemas = true;
3448
        this.geometrySupportType = GeometrySupportType.WKT;
3449

    
3450
        this.defaultSchema = "public";
3451
        this.allowAutomaticValues = true;
3452

    
3453
    }
3454
    
3455
    @Override
3456
    public void setProperties(Class filter, final Object... values) {
3457
        this.expressionBuilder.setProperties(filter, values);
3458
        setProperties(this, filter, values);
3459
    }
3460
    
3461
    @Override
3462
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3463
        if(visitable == null){
3464
            return;
3465
        }
3466
        if(visitable instanceof PropertiesSupport){
3467
            for (int i = 0; i < values.length; i+=2) {
3468
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3469
            }
3470
        }
3471
        visitable.accept((Visitable v) -> {
3472
            if(v instanceof PropertiesSupport){
3473
                for (int i = 0; i < values.length; i+=2) {
3474
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3475
                }
3476
            }
3477
        }, new ClassVisitorFilter(filter) );
3478
    }
3479

    
3480
    public String quote_for_identifiers() {
3481
        return "\"";
3482
    }
3483

    
3484
    public String quote_for_strings() {
3485
        return "'";
3486
    }
3487

    
3488
    @Override
3489
    public String as_identifier(String id) {
3490
        String quote = this.quote_for_identifiers();
3491
//        No se porque no esta disponible wrapIfMissing
3492
//        return StringUtils.wrapIfMissing(id,quote);
3493
        if (id.startsWith(quote)) {
3494
            return id;
3495
        }
3496
        return quote + id + quote;
3497

    
3498
    }
3499
    
3500
    @Override
3501
    public String as_clob(String s) {
3502
        int chunkSize = 1024;
3503
        StringBuilder builder = new StringBuilder();
3504
        builder.append("(CAST('");
3505
        for (int i = 0; i < s.length(); i += chunkSize) {
3506
            String chunk = s.substring(i, Math.min(s.length(), i + chunkSize));
3507
            if( i>0 ) {
3508
                builder.append("' AS NCLOB) || CAST('");
3509
            }            
3510
            builder.append(StringUtils.replace(chunk, "'", "''"));
3511
        }
3512
        builder.append("' AS NCLOB))");
3513
        return builder.toString();
3514
    }
3515

    
3516
    @Override
3517
    public String as_string(String s) {
3518
        String quote = this.quote_for_strings();
3519
//        No se porque no esta disponible wrapIfMissing
3520
//        return StringUtils.wrapIfMissing(id,quote);
3521
        if (s.startsWith(quote)) {
3522
            return s;
3523
        }
3524
        return quote + s + quote;
3525

    
3526
    }
3527

    
3528
    @Override
3529
    public String as_string(byte[] data) {
3530
        return this.expressionBuilder.bytearray_0x(data);
3531
//        return this.expressionBuilder.bytearray_hex(data);
3532
//        return this.expressionBuilder.bytearray_x(data);
3533
    }
3534
    
3535
    @Override
3536
    public String as_string(boolean value) {
3537
        return value? "TRUE" : "FALSE";
3538
    }
3539

    
3540
    @Override
3541
    public String as_string(Number value) {
3542
        return Objects.toString(value);
3543
    }
3544
    
3545
    @Override
3546
    public String as_string(Object value) {
3547
        if( value == null ) {
3548
            return "NULL";
3549
        }
3550
        if( value instanceof CharSequence ) {
3551
            return as_string(value.toString());
3552
        }
3553
        if( value instanceof Number ) {
3554
            return as_string((Number)value);
3555
        }
3556
        if( value instanceof Boolean ) {
3557
            return as_string((boolean)value);
3558
        }
3559
        if( value instanceof byte[] ) {
3560
            return as_string((byte[])value);
3561
        }
3562
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3563
    }
3564
    
3565
    @Override
3566
    public GeometryExpressionBuilder expression() {
3567
        return this.expressionBuilder;
3568
    }
3569

    
3570
    @Override
3571
    public boolean has_spatial_functions() {
3572
        return this.hasSpatialFunctions;
3573
    }
3574

    
3575
    @Override
3576
    public GeometrySupportType geometry_support_type() {
3577
        return this.geometrySupportType;
3578
    }
3579

    
3580
    protected GeometryExpressionBuilder createExpressionBuilder() {
3581
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3582
    }
3583

    
3584
    @Override
3585
    public Object srs_id(IProjection projection) {
3586
        String abrev = projection.getAbrev();
3587
        return abrev.split(":")[1].trim();
3588
    }
3589

    
3590
    @Override
3591
    public String default_schema() {
3592
        return this.defaultSchema;
3593
    }
3594

    
3595
    @Override
3596
    public boolean support_schemas() {
3597
        return this.supportSchemas;
3598
    }
3599

    
3600
    @Override
3601
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3602
        switch (type) {
3603
            case DataTypes.BOOLEAN:
3604
                return type_boolean;
3605
            case DataTypes.CHAR:
3606
                return type_char;
3607

    
3608

    
3609
            case DataTypes.BYTE:
3610
                return type_byte;
3611
            case DataTypes.INT:
3612
                return type_int;
3613
            case DataTypes.LONG:
3614
                return type_long;
3615

    
3616
            case DataTypes.FLOAT:
3617
                return type_float;
3618
            case DataTypes.DOUBLE:
3619
                return type_double;
3620
            case DataTypes.DECIMAL:
3621
                if (precision < 1) {
3622
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3623
                }
3624
                if (scale < 1) {
3625
                  return MessageFormat.format(type_decimal_p, precision);
3626
                }
3627
                return MessageFormat.format(type_decimal_ps, precision, scale);
3628

    
3629
                
3630
            case DataTypes.STRING:
3631
                if (size < 0) {
3632
                    return type_string;
3633
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3634
                    return MessageFormat.format(type_string_p, size);
3635
                }
3636
                return type_string;
3637

    
3638
                
3639
            case DataTypes.DATE:
3640
                return type_date;
3641
            case DataTypes.TIME:
3642
                return type_time;
3643
            case DataTypes.TIMESTAMP:
3644
                return type_timestamp;
3645

    
3646
            case DataTypes.BYTEARRAY:
3647
                return type_bytearray;
3648

    
3649
            case DataTypes.GEOMETRY:
3650
                return type_geometry;
3651

    
3652
            case DataTypes.VERSION:
3653
                return type_version;
3654
            case DataTypes.URI:
3655
                return type_URI;
3656
            case DataTypes.URL:
3657
                return type_URL;
3658
            case DataTypes.FILE:
3659
                return type_FILE;
3660
            case DataTypes.FOLDER:
3661
                return type_FOLDER;
3662
            default:
3663
                return null;
3664
        }
3665
    }
3666

    
3667
    @Override
3668
    public Object sqlgeometrytype(int type, int subtype) {
3669
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3670
        // identificadores numericos para el tipo y otros strings.
3671
        // Por defecto vamos a devolver strings.
3672
        if (sqlgeometrytypes == null) {
3673
            sqlgeometrytypes = new HashMap<>();
3674
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3675
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3676
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3677
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3678

    
3679
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3680
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3681
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3682
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3683

    
3684
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3685
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3686
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3687
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3688

    
3689
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3690
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3691
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3692
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3693

    
3694
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3695
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3696
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3697
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3698

    
3699
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3700
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3701
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3702
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3703

    
3704
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3705
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3706
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3707
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3708

    
3709
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3710
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3711
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3712
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3713

    
3714
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3715
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3716
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3717
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3718
        }
3719
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3720
    }
3721

    
3722
    @Override
3723
    public Object sqlgeometrydimension(int type, int subtype) {
3724
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3725
        // identificadores numericos para las dimensiones y otros strings.
3726
        // Por defecto vamos a devolver enteros.
3727
        switch (subtype) {
3728
            case Geometry.SUBTYPES.GEOM3D:
3729
                return 3;
3730
            case Geometry.SUBTYPES.GEOM2DM:
3731
                return 3;
3732
            case Geometry.SUBTYPES.GEOM3DM:
3733
                return 4;
3734
            case Geometry.SUBTYPES.GEOM2D:
3735
            default:
3736
                return 2;
3737
        }
3738
    }
3739

    
3740
    @Override
3741
    public SelectColumnBuilder column() {
3742
        return createSelectColumnBuilder();
3743
    }
3744

    
3745
    @Override
3746
    public TableNameBuilder createTableNameBuilder() {
3747
        return new TableNameBuilderBase();
3748
    }
3749

    
3750
    protected SelectColumnBuilder createSelectColumnBuilder() {
3751
        return new SelectColumnBuilderBase(this);
3752
    }
3753

    
3754
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3755
        return new UpdateColumnBuilderBase();
3756
    }
3757

    
3758
    protected InsertColumnBuilder createInsertColumnBuilder() {
3759
        return new InsertColumnBuilderBase();
3760
    }
3761

    
3762
    protected OrderByBuilder createOrderByBuilder() {
3763
        return new OrderByBuilderBase();
3764
    }
3765

    
3766
    protected FromBuilder createFromBuilder() {
3767
        return new FromBuilderBase();
3768
    }
3769

    
3770
    public SelectBuilder createSelectBuilder() {
3771
        return new SelectBuilderBase();
3772
    }
3773

    
3774
    protected UpdateBuilder createUpdateBuilder() {
3775
        return new UpdateBuilderBase();
3776
    }
3777

    
3778
    protected DeleteBuilder createDeleteBuilder() {
3779
        return new DeleteBuilderBase();
3780
    }
3781

    
3782
    protected GrantBuilder createGrantBuilder() {
3783
        return new GrantBuilderBase();
3784
    }
3785

    
3786
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3787
        return new GrantRoleBuilderBase(table, role);
3788
    }
3789

    
3790
    protected DropTableBuilder createDropTableBuilder() {
3791
        return new DropTableBuilderBase();
3792
    }
3793

    
3794
    protected CreateTableBuilder createCreateTableBuilder() {
3795
        return new CreateTableBuilderBase();
3796
    }
3797

    
3798
    protected AlterTableBuilder createAlterTableBuilder() {
3799
        return new AlterTableBuilderBase(this);
3800
    }
3801

    
3802
    protected InsertBuilder createInsertBuilder() {
3803
        return new InsertBuilderBase();
3804
    }
3805

    
3806
    protected MergeBuilder createMergeBuilder() {
3807
        return new MergeBuilderBase();
3808
    }
3809

    
3810
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3811
        return new UpdateTableStatisticsBuilderBase();
3812
    }
3813

    
3814
    public CreateIndexBuilder createCreateIndexBuilder() {
3815
        return new CreateIndexBuilderBase();
3816
    }
3817

    
3818
    public DropIndexBuilder createDropIndexBuilder() {
3819
        return new DropIndexBuilderBase();
3820
    }
3821
    
3822
    @Override
3823
    public SelectBuilder select() {
3824
        if (this.select == null) {
3825
            this.select = this.createSelectBuilder();
3826
        }
3827
        return this.select;
3828
    }
3829

    
3830
    @Override
3831
    public UpdateBuilder update() {
3832
        if (this.update == null) {
3833
            this.update = this.createUpdateBuilder();
3834
        }
3835
        return this.update;
3836
    }
3837

    
3838
    @Override
3839
    public UpdateTableStatisticsBuilder update_table_statistics() {
3840
        if (this.update_table_statistics == null) {
3841
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3842
        }
3843
        return this.update_table_statistics;
3844
    }
3845

    
3846
    @Override
3847
    public DropTableBuilder drop_table() {
3848
        if (this.drop_table == null) {
3849
            this.drop_table = this.createDropTableBuilder();
3850
        }
3851
        return this.drop_table;
3852
    }
3853

    
3854
    @Override
3855
    public CreateIndexBuilder create_index() {
3856
        if (this.create_index == null) {
3857
            this.create_index = this.createCreateIndexBuilder();
3858
        }
3859
        return this.create_index;
3860
    }
3861

    
3862
    @Override
3863
    public DropIndexBuilder drop_index() {
3864
        if (this.drop_index == null) {
3865
            this.drop_index = this.createDropIndexBuilder();
3866
        }
3867
        return this.drop_index;
3868
    }
3869

    
3870
    @Override
3871
    public DeleteBuilder delete() {
3872
        if (this.delete == null) {
3873
            this.delete = this.createDeleteBuilder();
3874
        }
3875
        return this.delete;
3876
    }
3877

    
3878
    @Override
3879
    public InsertBuilder insert() {
3880
        if (this.insert == null) {
3881
            this.insert = this.createInsertBuilder();
3882
        }
3883
        return this.insert;
3884
    }
3885

    
3886
    @Override
3887
    public MergeBuilder merge() {
3888
        if (this.merge == null) {
3889
            this.merge = this.createMergeBuilder();
3890
        }
3891
        return this.merge;
3892
    }
3893

    
3894
    @Override
3895
    public TableNameBuilder table_name() {
3896
        if (this.table_name == null) {
3897
            this.table_name = this.createTableNameBuilder();
3898
        }
3899
        return this.table_name;
3900
    }
3901

    
3902
    
3903
    @Override
3904
    public AlterTableBuilder alter_table() {
3905
        if (this.alter_table == null) {
3906
            this.alter_table = this.createAlterTableBuilder();
3907
        }
3908
        return this.alter_table;
3909
    }
3910

    
3911
    @Override
3912
    public CreateTableBuilder create_table() {
3913
        if (this.create_table == null) {
3914
            this.create_table = this.createCreateTableBuilder();
3915
        }
3916
        return this.create_table;
3917
    }
3918

    
3919
    @Override
3920
    public GrantBuilder grant() {
3921
        if (this.grant == null) {
3922
            this.grant = this.createGrantBuilder();
3923
        }
3924
        return this.grant;
3925
    }
3926
    
3927
    @Override
3928
    public Column column(String name) {
3929
        ColumnBase col = new ColumnBase(null, name);
3930
        return col;
3931
    }
3932

    
3933
    @Override
3934
    public Column column(TableNameBuilder table, String name) {
3935
        ColumnBase col = new ColumnBase(table, name);
3936
        return col;
3937
    }
3938
    
3939
    public Column column_from(Variable variable) {
3940
        Column c = null;
3941
        if (variable instanceof Column) {
3942
            c = this.column(((Column) variable).table(), variable.name());
3943
        } else {
3944
            c = this.column(variable.name());
3945
        }
3946
        c.copyPropertiesFrom(variable);
3947
        return c;
3948

    
3949
    }
3950

    
3951
    public Column column_from(TableNameBuilder table, Variable variable) {
3952
        Column c = this.column(table, variable.name());
3953
        c.copyPropertiesFrom(variable);
3954
        return c;
3955
    }
3956
        
3957

    
3958
    
3959
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3960
        return new JoinBase(type, table, expression);
3961
    }
3962

    
3963
    @Override
3964
    public void accept(Visitor visitor, VisitorFilter filter) {
3965
        if (this.select != null) {
3966
            this.select.accept(visitor, filter);
3967
        }
3968
        if (this.update != null) {
3969
            this.update.accept(visitor, filter);
3970
        }
3971
        if (this.insert != null) {
3972
            this.insert.accept(visitor, filter);
3973
        }
3974
        if (this.merge != null) {
3975
            this.merge.accept(visitor, filter);
3976
        }
3977
        if (this.delete != null) {
3978
            this.delete.accept(visitor, filter);
3979
        }
3980
        if (this.alter_table != null) {
3981
            this.alter_table.accept(visitor, filter);
3982
        }
3983
        if (this.create_table != null) {
3984
            this.create_table.accept(visitor, filter);
3985
        }
3986
        if (this.drop_table != null) {
3987
            this.drop_table.accept(visitor, filter);
3988
        }
3989
        if (this.table_name != null) {
3990
            this.table_name.accept(visitor, filter);
3991
        }
3992
    }
3993

    
3994
    @Override
3995
    public Formatter formatter() {
3996
        return expression().formatter();
3997
    }
3998

    
3999
    @Override
4000
    public String toString() {
4001
        return this.toString(formatter());
4002
    }
4003

    
4004
    @Override
4005
    public String toString(Formatter formatter) {
4006
        if (this.select != null) {
4007
            return this.select.toString(formatter);
4008
        }
4009
        if (this.update != null) {
4010
            return this.update.toString(formatter);
4011
        }
4012
        if (this.insert != null) {
4013
            return this.insert.toString(formatter);
4014
        }
4015
        if (this.merge != null) {
4016
            return this.merge.toString(formatter);
4017
        }
4018
        if (this.delete != null) {
4019
            return this.delete.toString(formatter);
4020
        }
4021
        if (this.alter_table != null) {
4022
            return this.alter_table.toString(formatter);
4023
        }
4024
        if (this.create_table != null) {
4025
            return this.create_table.toString(formatter);
4026
        }
4027
        if (this.drop_table != null) {
4028
            return this.drop_table.toString(formatter);
4029
        }
4030
        if (this.update_table_statistics != null) {
4031
            return this.update_table_statistics.toString(formatter);
4032
        }
4033
        if (this.create_index != null) {
4034
            return this.create_index.toString(formatter);
4035
        }
4036
        if (this.drop_index != null) {
4037
            return this.drop_index.toString(formatter);
4038
        }
4039
        if (this.table_name != null) {
4040
            return this.table_name.toString(formatter);
4041
        }
4042
        return "";
4043
    }
4044

    
4045
    @Override
4046
    public CountBuilder count() {
4047
        return new CountBuilderBase();
4048
    }
4049

    
4050
    @Override
4051
    public List<Parameter> parameters() {
4052
        final List<Parameter> params = new ArrayList<>();
4053
        this.accept((Visitable value) -> {
4054
            params.add((Parameter) value);
4055
        }, new ClassVisitorFilter(Parameter.class));
4056
        return params;
4057
    }
4058

    
4059
    @Override
4060
    public List<Variable> variables() {
4061
        final List<Variable> vars = new ArrayList<>();
4062
        this.accept(new Visitor() {
4063
            @Override
4064
            public void visit(Visitable value) {
4065
                if (!vars.contains((Variable) value)) {
4066
                    vars.add((Variable) value);
4067
                }
4068
            }
4069
        }, new ClassVisitorFilter(Variable.class));
4070
        return vars;
4071
    }
4072

    
4073
    @Override
4074
    public List<String> parameters_names() {
4075
        List<String> params = new ArrayList<>();
4076
        for (Parameter param : parameters()) {
4077
            String s;
4078
            switch (param.type()) {
4079
                case PARAMETER_TYPE_CONSTANT:
4080
                    Object theValue = param.value();
4081
                    if (theValue == null) {
4082
                        s = "null";
4083
                    } else if (theValue instanceof String) {
4084
                        s = "'" + (String) theValue + "'";
4085
                    } else {
4086
                        s = theValue.toString();
4087
                    }
4088
                    break;
4089
                case PARAMETER_TYPE_VARIABLE:
4090
                default:
4091
                    s = "\"" + param.name() + "\"";
4092
            }
4093
            params.add(s);
4094
        }
4095
        return params;
4096
    }
4097

    
4098
    @Override
4099
    public List<String> variables_names() {
4100
        List<String> vars = new ArrayList<>();
4101
        for (Variable var : this.variables()) {
4102
            vars.add(var.name());
4103
        }
4104
        Collections.sort(vars);
4105
        return vars;
4106
    }    
4107
    
4108
    protected String[] aggregateFunctionNames = new String[] {
4109
        "MAX",
4110
        "MIN",
4111
        "COUNT",
4112
        "SUM"
4113
    };
4114
    
4115
    @Override
4116
    public boolean isAggregateFunction(String funcname) {
4117
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
4118
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
4119
                return true;
4120
            }
4121
        }
4122
        return false;
4123
    }
4124

    
4125
    @Override
4126
    public int getMaxRecomendedSQLLength() {
4127
        return DEFAULT_RECOMENDED_SQL_LENGTH;
4128
    }
4129
    
4130
    public String getConstrainName(TableNameBuilder table, String columnName, String constrainType) {
4131
        // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
4132
        String constraint_name = table.getName() + "_" + constrainType + "_" + columnName;
4133
        return constraint_name;
4134
    }    
4135
}