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

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.geom.Geometry;
54
import org.gvsig.fmap.geom.GeometryUtils;
55
import org.gvsig.fmap.geom.primitive.Envelope;
56
import org.gvsig.tools.dataTypes.DataType;
57
import org.gvsig.tools.dynobject.Tags;
58
import org.gvsig.tools.lang.CloneableUtils;
59
import org.gvsig.tools.util.Bitmask;
60
import org.gvsig.tools.util.PropertiesSupport;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

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

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

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

    
82
    protected abstract class AbstractStatementPart extends AbstractValue {
83
        
84
    }
85

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

    
93
    protected class ColumnDescriptorBase implements ColumnDescriptor {
94

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

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

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

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

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

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

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

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

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

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

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

    
240
        @Override
241
        public int getPrecision() {
242
            return precision;
243
        }
244

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

    
250
        @Override
251
        public int getScale() {
252
            return scale;
253
        }
254

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

    
260
        @Override
261
        public int getSize() {
262
            return size;
263
        }
264

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

    
270
        @Override
271
        public boolean isPrimaryKey() {
272
            return isPk;
273
        }
274

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

    
280
        @Override
281
        public boolean allowNulls() {
282
            return _allowNulls;
283
        }
284

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

    
290
        @Override
291
        public boolean isAutomatic() {
292
            return _isAutomatic;
293
        }
294

    
295
        @Override
296
        public boolean isIndexed() {
297
            return _isIndexed;
298
        }
299

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

    
305
        @Override
306
        public Object getDefaultValue() {
307
            return defaultValue;
308
        }
309

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

    
315
        @Override
316
        public int getGeometryType() {
317
            return geom_type;
318
        }
319

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

    
325
        @Override
326
        public int getGeometrySubtype() {
327
            return geom_subtype;
328
        }
329

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

    
335
        @Override
336
        public Object getGeometrySRSId() {
337
            return geom_srsdbcode;
338
        }
339

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

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

    
350
        private void setStoreParameters(DataStoreParameters parameters) {
351
            this.parameters = parameters;
352
        }
353

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

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

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

    
379
    public class ColumnBase extends AbstractValue implements Column {
380

    
381
        private final String name;
382
        private TableNameBuilder table;
383

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

    
396

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

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

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

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

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

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

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

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

    
460
    public class TableNameBuilderBase
461
            extends AbstractStatementPart
462
            implements TableNameBuilder {
463

    
464
        public String tableName;
465
        public String schemaName;
466
        private String databaseName;
467

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

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

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

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

    
498
        @Override
499
        public String getDatabase() {
500
            return this.databaseName;
501
        }
502

    
503
        @Override
504
        public String getSchema() {
505
            return this.schemaName;
506
        }
507

    
508
        @Override
509
        public String getName() {
510
            return this.tableName;
511
        }
512

    
513
        @Override
514
        public boolean has_schema() {
515
            if (!support_schemas()) {
516
                return false;
517
            }
518
            return StringUtils.isNotBlank(this.schemaName);
519
        }
520

    
521
        @Override
522
        public boolean has_name() {
523
            return StringUtils.isNotBlank(this.tableName);
524
        }
525

    
526
        @Override
527
        public boolean has_database() {
528
            return StringUtils.isNotBlank(this.databaseName);
529
        }
530

    
531
        @Override
532
        public boolean isEmpty() {
533
            return !this.has_database() && !this.has_schema() && !this.has_name();
534
        }
535

    
536
        @Override
537
        public String toString() {
538
            return this.toString(formatter());
539
        }
540

    
541
        @Override
542
        public String toString(Formatter<Value> formatter) {
543
            if (formatter!=null && formatter.canApply(this)) {
544
                return formatter.format(this);
545
            }
546
            if (this.has_database()) {
547
                if (this.has_schema()) {
548
                    return as_identifier(this.databaseName) + "."
549
                            + as_identifier(this.schemaName) + "."
550
                            + as_identifier(this.tableName);
551
                }
552
//                return as_identifier(this.databaseName) + "."
553
//                        + as_identifier(this.tableName);
554
            } else {
555
                if (this.has_schema()) {
556
                    return as_identifier(this.schemaName) + "."
557
                            + as_identifier(this.tableName);
558
                }
559
            }
560
            return as_identifier(this.tableName);
561
        }
562

    
563
        @Override
564
        public boolean equals(Object obj) {
565
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
566
                return false;
567
            }
568
            TableNameBuilder other = (TableNameBuilder) obj;
569
            
570
            if (this.has_database() != other.has_database()) {
571
                return false;
572
            }
573
            String thisSchema = null;
574
            String otherSchema = null;
575
            if(support_schemas()) {
576
                thisSchema = this.schemaName;
577
                if (StringUtils.isBlank(thisSchema)) {
578
                    thisSchema = default_schema();
579
                }
580
                otherSchema = other.getSchema();
581
                if (StringUtils.isBlank(otherSchema)) {
582
                    otherSchema = default_schema();
583
                }
584
            }
585
            if (this.has_database()) {
586
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
587
                           StringUtils.equals(thisSchema, otherSchema) &&
588
                           StringUtils.equals(this.tableName,other.getName());
589
            } else {
590
                    return StringUtils.equals(thisSchema, otherSchema) &&
591
                           StringUtils.equals(this.tableName,other.getName());
592
            }
593
        }
594

    
595
        @Override
596
        public int hashCode() {
597
            int hash = 7;
598
            hash = 37 * hash + Objects.hashCode(this.toString());
599
            return hash;
600
        }
601

    
602
    }
603

    
604
    public class CountBuilderBase
605
            extends AbstractStatementPart
606
            implements CountBuilder {
607

    
608
        protected Value value;
609
        protected boolean distinct;
610
        protected boolean all;
611

    
612
        public CountBuilderBase() {
613
            this.value = null;
614
            this.distinct = false;
615
            this.all = false;
616
        }
617
        
618
        @Override
619
        public CountBuilderBase clone() throws CloneNotSupportedException {
620
            CountBuilderBase other = (CountBuilderBase) super.clone();
621
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
622
            return other;
623
        }
624
        
625
        @Override
626
        public CountBuilder all() {
627
            this.all = true;
628
            return this;
629
        }
630

    
631
        @Override
632
        public CountBuilder column(Value value) {
633
            this.value = value;
634
            return this;
635
        }
636

    
637
        @Override
638
        public CountBuilder distinct() {
639
            this.distinct = true;
640
            return this;
641
        }
642

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

    
648
        @Override
649
        public String toString(Formatter formatter) {
650
            if (formatter!=null && formatter.canApply(this)) {
651
                return formatter.format(this);
652
            }
653
            if (this.all) {
654
                return "COUNT(*)";
655
            }
656
            if (this.distinct) {
657
                return MessageFormat.format(
658
                        "COUNT(DISTINCT {0})",
659
                        value.toString(formatter)
660
                );
661
            }
662
            return MessageFormat.format(
663
                    "COUNT({0})",
664
                    value.toString(formatter)
665
            );
666
        }
667

    
668
    }
669

    
670
    protected class JoinBase 
671
            extends AbstractStatementPart
672
            implements JoinBuilder 
673
        {
674
        protected String type;
675
        protected TableNameBuilder table;
676
        protected Value expression;
677
        
678
        public JoinBase(String type, TableNameBuilder table, Value expression) {
679
            this.type = type;
680
            this.table = table;
681
            this.expression = expression;
682
        }
683
        
684
        @Override
685
        public JoinBase clone() throws CloneNotSupportedException {
686
            JoinBase other = (JoinBase) super.clone();
687
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
688
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
689
            return other;
690
        }
691

    
692
        @Override
693
        public String toString() {
694
            return this.toString(formatter());
695
        }
696

    
697
        @Override
698
        public String toString(Formatter<Value> formatter) {
699
            if (formatter!=null && formatter.canApply(this)) {
700
                return formatter.format(this);
701
            }
702
            StringBuilder builder = new StringBuilder();
703
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
704
            builder.append(this.type.toUpperCase());
705
            builder.append(" JOIN ");
706
            builder.append(this.table.toString(formatter));
707
            builder.append(" ON ");
708
            builder.append(this.expression.toString(formatter));
709
            return builder.toString();
710
        }
711
        
712
        @Override
713
        public TableNameBuilder getTable() {
714
            return this.table;
715
        }
716
        
717
        @Override
718
        public String getType() {
719
            return this.type;
720
        }
721

    
722
        @Override
723
        public Value getCondition() {
724
            return this.expression;
725
        }
726
        
727
        @Override
728
        public void accept(Visitor visitor, VisitorFilter filter) {
729
            boolean visitChildren = true;
730
            if (filter==null || filter.accept(this)) {
731
                visitor.visit(this);
732
            } else {
733
                visitChildren = !filter.skipChildren();
734
            }
735
            if(visitChildren){
736
                if (this.expression != null) {
737
                    this.expression.accept(visitor, filter);
738
                }
739
            }
740
        }
741

    
742
    }
743
    
744
    public class FromBuilderBase
745
            extends AbstractStatementPart
746
            implements FromBuilder {
747

    
748
        protected TableNameBuilder tableName;
749
        protected String subquery;
750
        protected String passthrough;
751
        protected List<JoinBuilder> joins;
752

    
753
        public FromBuilderBase() {
754
            this.tableName = null;
755
            this.subquery = null;
756
            this.passthrough = null;
757
            this.joins = null;
758
        }
759
        
760
        @Override
761
        public FromBuilderBase clone() throws CloneNotSupportedException {
762
            FromBuilderBase other = (FromBuilderBase) super.clone();
763
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
764
            if (joins!=null) {
765
                for (int i = 0; i < joins.size(); i++) {
766
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
767
                }
768
            }
769
            return other;
770
        }
771

    
772
        @Override
773
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
774
            JoinBase join = createJoin("LEFT", table, expression);
775
            if( this.joins==null ) {
776
                this.joins = new ArrayList<>();
777
            }
778
            this.joins.add(join);
779
            return this;
780
        }
781
        
782
        @Override
783
        public TableNameBuilder table() {
784
            if (tableName == null) {
785
                this.tableName = createTableNameBuilder();
786
            }
787
            return this.tableName;
788
        }
789

    
790
        @Override
791
        public void accept(Visitor visitor, VisitorFilter filter) {
792
            boolean visitChildren = true;
793
            if (filter==null || filter.accept(this)) {
794
                visitor.visit(this);
795
            } else {
796
                visitChildren = !filter.skipChildren();
797
            }
798
            if(visitChildren){
799
                if (this.tableName != null) {
800
                    this.tableName.accept(visitor, filter);
801
                }
802
                if(this.joins != null) {
803
                    for (JoinBuilder join : joins) {
804
                        join.accept(visitor, filter);
805
                    }
806
                }
807
            }
808
        }
809

    
810
        @Override
811
        public FromBuilder custom(String passthrough) {
812
            this.passthrough = passthrough;
813
            return this;
814
        }
815

    
816
        @Override
817
        public FromBuilder subquery(String subquery) {
818
            this.subquery = subquery;
819
            return this;
820
        }
821

    
822
        @Override
823
        public String toString() {
824
            return this.toString(formatter());
825
        }
826

    
827
        @Override
828
        public String toString(Formatter<Value> formatter) {
829
            if (formatter!=null && formatter.canApply(this)) {
830
                return formatter.format(this);
831
            }
832
            if (!StringUtils.isEmpty(passthrough)) {
833
                return passthrough;
834
            }
835
            if (!StringUtils.isEmpty(subquery)) {
836
                return "( " + this.subquery + ") AS _subquery_alias_ ";
837
            }
838
            if( this.joins==null || this.joins.isEmpty() ) {
839
                return this.tableName.toString(formatter);
840
            }
841
            StringBuilder builder = new StringBuilder();
842
            builder.append(this.tableName.toString(formatter));
843
            for (JoinBuilder join : this.joins) {
844
                builder.append(" ");
845
                builder.append(join.toString(formatter));
846
            }
847
            return builder.toString();
848
        }
849

    
850
        @Override
851
        public List<JoinBuilder> getJoins() {
852
            return this.joins;
853
        }
854

    
855
    }
856

    
857
    public class SelectColumnBuilderBase
858
            extends AbstractStatementPart
859
            implements SelectColumnBuilder {
860

    
861
        protected Column name = null;
862
        protected String alias = null;
863
        protected Value value = null;
864
        protected boolean asGeometry = false;
865
        protected TableNameBuilder table;
866
        protected SQLBuilder sqlbuilder;
867
        
868
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
869
            this.sqlbuilder = sqlbuilder;
870
        }
871
        
872
        @Override
873
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
874
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
875
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
876
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
877
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
878
            return other;
879
        }
880

    
881
        @Override
882
        public void accept(Visitor visitor, VisitorFilter filter) {
883
            boolean visitChildren = true;
884
            if (filter==null || filter.accept(this)) {
885
                visitor.visit(this);
886
            } else {
887
                visitChildren = !filter.skipChildren();
888
            }
889
            if(visitChildren){
890
                if (this.value != null) {
891
                    this.value.accept(visitor, filter);
892
                } else if (this.name != null) {
893
                    this.name.accept(visitor, filter);
894
                }
895
            }
896
        }
897

    
898
        @Override
899
        public void replace(Value target, Value replacement) {
900
            if (this.name!=null ) {
901
                if( this.name == target) {
902
                    if(replacement == null){
903
                        this.name = null;
904
                    } else if(replacement instanceof Column){
905
                        this.name = (Column) replacement;
906
                    } else if(replacement instanceof Variable){
907
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
908
                    } else {
909
                        this.value = replacement;
910
                    }
911
                }
912
            }
913
            if( this.value!=null ) {
914
                if (this.value == target) {
915
                    this.value = replacement;
916
                } else {
917
                    this.value.replace(target, replacement);
918
                }
919
            }
920
        }
921

    
922
        @Override
923
        public SelectColumnBuilder name(String name) {
924
            return this.name(this.table, name);
925
        }
926

    
927
        @Override
928
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
929
            String quote = quote_for_identifiers();
930
            if (name.startsWith(quote)) {
931
                // Remove quotes
932
                name = name.substring(1, name.length() - 1);
933
            }
934
            this.table = table;
935
            this.name = new ColumnBase(this.table, name);
936
            this.value = null;
937
            this.asGeometry = false;
938
            return this;
939
        }
940
        
941
        public SelectColumnBuilder table(TableNameBuilder table) {
942
            this.table = table;
943
            if(this.name != null){
944
                this.name.table(table);
945
            }
946
            return this;
947
        }
948
        
949
        @Override
950
        public SelectColumnBuilder all() {
951
            this.name = null;
952
            this.value = expression().custom("*");
953
            this.asGeometry = false;
954
            return this;
955
        }
956

    
957
        @Override
958
        public SelectColumnBuilder as_geometry() {
959
            this.asGeometry = true;
960
            return this;
961
        }
962

    
963
        @Override
964
        public SelectColumnBuilder value(Value value) {
965
            this.value = value;
966
            return this;
967
        }
968

    
969
        @Override
970
        public SelectColumnBuilder as(String alias) {
971
            this.alias = alias;
972
            return this;
973
        }
974

    
975
        @Override
976
        public String getName() {
977
            if (this.name==null) {
978
                return null;
979
            }
980
            return this.name.name();
981
        }
982

    
983
        @Override
984
        public String getAlias() {
985
            return this.alias;
986
        }
987

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

    
993
        @Override
994
        public String toString() {
995
            return this.toString(formatter());
996
        }
997

    
998
        @Override
999
        public String toString(Formatter<Value> formatter) {
1000
            if (formatter!=null && formatter.canApply(this)) {
1001
                return formatter.format(this);
1002
            }
1003
            StringBuilder builder = new StringBuilder();
1004
            if (this.asGeometry) {
1005
                if(this.value == VALUE_NULL){
1006
                    builder.append(this.value.toString(formatter));
1007
                } else {
1008
                    switch(expression().geometry_support_type()) {
1009
                        case WKB:
1010
                            builder.append(expression().ST_AsBinary(this.name).toString(formatter));
1011
                            break;
1012
                        case EWKB:
1013
                            builder.append(expression().ST_AsEWKB(this.name).toString(formatter));
1014
                            break;
1015
                        case WKT:
1016
                            builder.append(expression().ST_AsText(this.name).toString(formatter));
1017
                            break;
1018
                        case NATIVE:
1019
                            builder.append(as_identifier(this.name.toString(formatter)));
1020
                            break;
1021
                    }
1022
                }
1023
            } else {
1024
                if (this.value == null) {
1025
                    builder.append(this.name.toString(formatter));
1026
                } else {
1027
                    builder.append(this.value.toString(formatter));
1028
                }
1029
            }
1030
            if (this.alias != null) {
1031
                builder.append(" AS ");
1032
                builder.append(as_identifier(this.alias));
1033
            }
1034
            return builder.toString();
1035
        }
1036
        
1037
        @Override
1038
        public boolean isGeometry() {
1039
            return this.asGeometry;
1040
        }
1041
        
1042
        @Override
1043
        public TableNameBuilder getTable() {
1044
            return this.table;
1045
        }
1046
        
1047
        @Override
1048
        public boolean isAggregateFunction() {
1049
            if( this.value == null ) {
1050
                return false;
1051
            }
1052
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
1053
                return false;
1054
            }
1055
            String funcname = ((ExpressionBuilder.Function)this.value).name();
1056
            return this.sqlbuilder.isAggregateFunction(funcname);
1057
        }
1058
    }
1059

    
1060
    public class OrderByBuilderBase
1061
            extends AbstractStatementPart
1062
            implements OrderByBuilder {
1063

    
1064
        protected Value value;
1065
        protected String custom;
1066
        protected boolean ascending;
1067
        protected int nullsMode;
1068

    
1069
        public OrderByBuilderBase() {
1070
            this.ascending = true;
1071
            this.nullsMode = MODE_NULLS_LAST;
1072
        }
1073
        
1074
        @Override
1075
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
1076
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
1077
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
1078
            return other;
1079
        }
1080
        
1081
        @Override
1082
        public void accept(Visitor visitor, VisitorFilter filter) {
1083
            boolean visitChildren = true;
1084
            if (filter==null || filter.accept(this)) {
1085
                visitor.visit(this);
1086
            } else {
1087
                visitChildren = !filter.skipChildren();
1088
            }
1089
            if(visitChildren){
1090
                if (this.value!=null) {
1091
                    this.value.accept(visitor, filter);
1092
                }
1093
            }
1094
        }
1095

    
1096
        @Override
1097
        public OrderByBuilder column(String name) {
1098
            this.value = expression().variable(name);
1099
            return this;
1100
        }
1101
        
1102
        @Override
1103
        public boolean isColumn(String name) {
1104
            if(this.value instanceof ExpressionBuilder.Variable){
1105
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1106
            }
1107
            return false;
1108
        }
1109
        
1110
        @Override
1111
        public boolean isColumn(Value value) {
1112
            if(value instanceof ExpressionBuilder.Variable){
1113
                return isColumn(((ExpressionBuilder.Variable)value).name());
1114
            }
1115
            return this.value == value;
1116
        }
1117
        
1118
        @Override
1119
        public OrderByBuilder value(Value expression) {
1120
            this.value = expression;
1121
            return this;
1122
        }
1123
        
1124
        @Override
1125
        public OrderByBuilder custom(String order) {
1126
            this.custom = order;
1127
            return this;
1128
        }
1129

    
1130
        @Override
1131
        public OrderByBuilder ascending() {
1132
            this.ascending = true;
1133
            return this;
1134
        }
1135

    
1136
        @Override
1137
        public OrderByBuilder ascending(boolean asc) {
1138
            this.ascending = asc;
1139
            return this;
1140
        }
1141

    
1142
        @Override
1143
        public OrderByBuilder descending() {
1144
            this.ascending = false;
1145
            return this;
1146
        }
1147

    
1148
        @Override
1149
        public OrderByBuilder nulls(int mode) {
1150
            this.nullsMode = mode;
1151
            return this;
1152
        }
1153

    
1154
        @Override
1155
        public int getNullsMode() {
1156
            return this.nullsMode;
1157
        }
1158

    
1159
        @Override
1160
        public String toString() {
1161
            return this.toString(formatter());
1162
        }
1163

    
1164
        @Override
1165
        public String toString(Formatter<Value> formatter) {
1166
            if (formatter!=null && formatter.canApply(this)) {
1167
                return formatter.format(this);
1168
            }
1169
            if (!StringUtils.isEmpty(this.custom)) {
1170
                return this.custom;
1171
            }
1172
            String order_s = this.value.toString(formatter);
1173
            if (this.ascending) {
1174
                order_s += " ASC";
1175
            } else {
1176
                order_s += " DESC";
1177
            }
1178
            switch(this.nullsMode) {
1179
                case MODE_NULLS_NOT_SPECIFIED:
1180
                    break;
1181
                case MODE_NULLS_FIRST:
1182
                    order_s += " NULLS FIRST";
1183
                    break;
1184
                case MODE_NULLS_LAST:
1185
                default:
1186
                    order_s += " NULLS LAST";
1187
                    break;
1188
            }
1189
            return order_s;
1190
        }
1191

    
1192
        @Override
1193
        public void replace(Value target, Value replacement) {
1194
            super.replace(target, replacement);
1195
            if(target == this.value){
1196
                this.value = replacement;
1197
                return;
1198
            }
1199
            if(this.value == null){
1200
                return;
1201
            }
1202
            this.value.replace(target, replacement);
1203
        }
1204
        
1205
        
1206
    }
1207

    
1208
    public class SelectBuilderBase
1209
            extends AbstractStatement
1210
            implements SelectBuilder {
1211

    
1212
        protected FromBuilder from;
1213
        protected GeometryExpressionBuilder where;
1214
        protected long limit = -1;
1215
        protected long offset = -1;
1216
        protected List<SelectColumnBuilder> columns;
1217
        protected List<OrderByBuilder> order_by;
1218
        protected boolean distinct;
1219
        protected List<Value> groupColumn;
1220
        protected boolean check_order_and_offset = true;
1221

    
1222
        public SelectBuilderBase() {
1223
            this.columns = new ArrayList<>();
1224
            this.distinct = false;
1225
        }
1226
        @Override
1227
        public List<Value> getGroups() {
1228
            return this.groupColumn;
1229
        }
1230
        
1231
        @Override
1232
        public List<SelectColumnBuilder> getColumns() {
1233
            return Collections.unmodifiableList(this.columns);
1234
    }
1235
        
1236
        @Override
1237
        public void remove_column(String columnName) {
1238
            SelectColumnBuilder found = null;
1239
            for (SelectColumnBuilder column : columns) {
1240
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1241
                    found = column;
1242
                    break;
1243
                }
1244
                    
1245
            }
1246
            if(found!=null) {
1247
                columns.remove(found);
1248
            }
1249
        }
1250

    
1251
        @Override
1252
        public SelectBuilder group_by(Value... columns) {
1253
            if( this.groupColumn==null ) {
1254
                this.groupColumn = new ArrayList<>();
1255
            }
1256
            for (Value column : columns) {
1257
                this.groupColumn.add(column);
1258
            }
1259
            return this;
1260
        }
1261

    
1262
        @Override
1263
        public void accept(Visitor visitor, VisitorFilter filter) {
1264
            boolean visitChildren = true;
1265
            if (filter==null || filter.accept(this)) {
1266
                visitor.visit(this);
1267
            } else {
1268
                visitChildren = !filter.skipChildren();
1269
            }
1270
            if(visitChildren){
1271
                for (SelectColumnBuilder column : columns) {
1272
                    column.accept(visitor, filter);
1273
                }
1274
                if (this.has_from()) {
1275
                    this.from.accept(visitor, filter);
1276
                }
1277
                if (this.has_where()) {
1278
                    this.where.accept(visitor, filter);
1279
                }
1280
                if (this.has_order_by()) {
1281
                    for (OrderByBuilder order : order_by) {
1282
                        order.accept(visitor, filter);
1283
                    }
1284
                }
1285
                if (this.has_group_by()) {
1286
                    for (Value group : groupColumn) {
1287
                        group.accept(visitor, filter);
1288
                    }
1289
                }
1290
            }
1291
        }
1292

    
1293
        @Override
1294
        public void replace(Value target, Value replacement) {
1295
            if( this.columns!=null ) {
1296
                for (int i = 0; i < columns.size(); i++) {
1297
                    SelectColumnBuilder column = columns.get(i);
1298
                    if( column == target ) {
1299
                        columns.set(i, (SelectColumnBuilder) replacement);
1300
                    } else {
1301
                        column.replace(target, replacement);
1302
                    }
1303
                }
1304
            }
1305
            if (this.has_from()) {
1306
                if( this.from == target ) {
1307
                    this.from = (FromBuilder) replacement;
1308
                } else {
1309
                    this.from.replace(target, replacement);
1310
                }
1311
            }
1312
            if (this.has_where()) {
1313
                if( this.where == target ) {
1314
                    this.where = (GeometryExpressionBuilder) replacement;
1315
                } else if( this.where.value() == target ) {
1316
                    this.where.value(replacement);
1317
                } else {
1318
                    this.where.value().replace(target, replacement);
1319
                }
1320
            }
1321
            if (this.has_order_by()) {
1322
                for (int i = 0; i < order_by.size(); i++) {
1323
                    OrderByBuilder order = order_by.get(i);
1324
                    if( order == target ) {
1325
                        order_by.set(i, (OrderByBuilder) replacement);
1326
                    } else {
1327
                        order.replace(target, replacement);
1328
                    }
1329
                }
1330
            }
1331
            if (this.has_group_by()) {
1332
                for (int i = 0; i < groupColumn.size(); i++) {
1333
                    Value group = groupColumn.get(i);
1334
                    if( group == target ) {
1335
                        groupColumn.set(i, replacement);
1336
                    } else {
1337
                        group.replace(target, replacement);
1338
                    }
1339
                }
1340
            }
1341
        }
1342

    
1343
        @Override
1344
        public SelectBuilder distinct() {
1345
            this.distinct = true;
1346
            return this;
1347
        }
1348

    
1349
        @Override
1350
        public SelectColumnBuilder column() {
1351
            return column(createSelectColumnBuilder());
1352
        }
1353

    
1354
        @Override
1355
        public SelectColumnBuilder column(SelectColumnBuilder columnBuilder) {
1356
            this.columns.add(columnBuilder);
1357
            if( this.has_from() && !this.from().table().isEmpty() ) {
1358
                TableNameBuilder table = (TableNameBuilder) CloneableUtils.cloneQuietly(this.from().table());
1359
                columnBuilder.table(table);
1360
            }
1361
            return columnBuilder;
1362
        }
1363

    
1364
        @Override
1365
        public SelectColumnBuilder column(String name) {
1366
            for (SelectColumnBuilder column : columns) {
1367
                if (StringUtils.equals(name, column.getName())) {
1368
                    return column;
1369
                }
1370
            }
1371
            return column(createSelectColumnBuilder()).name(name);
1372
        }
1373

    
1374
        @Override
1375
        public SelectColumnBuilder getColumn(String name) {
1376
            for (SelectColumnBuilder column : columns) {
1377
                if (StringUtils.equals(name, column.getName())) {
1378
                    return column;
1379
                }
1380
            }
1381
            return null;
1382
        }
1383
        
1384
        @Override
1385
        public SelectBuilder remove_all_columns() {
1386
            this.columns = new ArrayList<>();
1387
            return this;
1388
        }
1389
        
1390
        @Override
1391
        public boolean has_column(String name) {
1392
            for (SelectColumnBuilder column : columns) {
1393
                if (StringUtils.equals(name, column.getName())) {
1394
                    return true;
1395
                }
1396
                if (StringUtils.equals(name, column.getAlias())) {
1397
                    return true;
1398
                }
1399
            }
1400
            return false;
1401
        }
1402

    
1403
        @Override
1404
        public FromBuilder from() {
1405
            if (this.from == null) {
1406
                this.from = createFromBuilder();
1407
            }
1408
            return this.from;
1409
        }
1410

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

    
1416
        @Override
1417
        public GeometryExpressionBuilder where() {
1418
            if (this.where == null) {
1419
                this.where = createExpressionBuilder();
1420
            }
1421
            return this.where;
1422
        }
1423

    
1424
        @Override
1425
        public boolean has_where() {
1426
            if (this.where == null) {
1427
                return false;
1428
            }
1429
            return this.where.value() != null;
1430
        }
1431

    
1432
        @Override
1433
        public SelectBuilder limit(long limit) {
1434
            this.limit = limit;
1435
            return this;
1436
        }
1437

    
1438
        @Override
1439
        public SelectBuilder limit(Long limit) {
1440
            if (limit == null) {
1441
                this.limit = -1;
1442
            } else {
1443
                this.limit = limit;
1444
            }
1445
            return this;
1446
        }
1447

    
1448
        @Override
1449
        public boolean has_limit() {
1450
            return this.limit >= 0;
1451
        }
1452

    
1453
        @Override
1454
        public SelectBuilder offset(long offset) {
1455
            this.offset = offset;
1456
            return this;
1457
        }
1458

    
1459
        @Override
1460
        public boolean has_offset() {
1461
            return this.offset > 0;
1462
        }
1463

    
1464
        @Override
1465
        public OrderByBuilder order_by() {
1466
            if (this.order_by == null) {
1467
                this.order_by = new ArrayList<>();
1468
            }
1469
            OrderByBuilder order = createOrderByBuilder();
1470
            this.order_by.add(order);
1471
            return order;
1472
        }
1473
        
1474
        @Override
1475
        public OrderByBuilder getOrderBy(Value column) {
1476
            if(this.order_by == null){
1477
                return null;
1478
            }
1479
            for (OrderByBuilder orderByBuilder : this.order_by) {
1480
                if(orderByBuilder.isColumn(column)){
1481
                    return orderByBuilder;
1482
                }
1483
            }
1484
            return null;
1485
        }
1486
        
1487
        @Override
1488
        public OrderByBuilder getOrderBy(String column) {
1489
            if(this.order_by == null){
1490
                return null;
1491
            }
1492
            for (OrderByBuilder orderByBuilder : this.order_by) {
1493
                if(orderByBuilder.isColumn(column)){
1494
                    return orderByBuilder;
1495
                }
1496
            }
1497
            return null;
1498
        }
1499
        
1500
        @Override
1501
        public boolean isGroupBy(String column) {
1502
            if(this.groupColumn == null){
1503
                return false;
1504
            }
1505
            for (Value group : this.groupColumn) {
1506
                if(group instanceof Variable){
1507
                    if(StringUtils.equalsIgnoreCase(((Variable)group).name(), column)){
1508
                        return true;
1509
                    }
1510
                }
1511
            }
1512
            return false;
1513
        }
1514

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

    
1566
        @Override
1567
        public String toString() {
1568
            return this.toString(formatter());
1569
        }
1570

    
1571
        @Override
1572
        public String toString(Formatter<Value> formatter) {
1573
            if (formatter!=null && formatter.canApply(this)) {
1574
                return formatter.format(this);
1575
            }
1576
            StringBuilder builder = new StringBuilder();
1577
            if (!this.isValid(builder)) {
1578
                throw new IllegalStateException(builder.toString());
1579
            }
1580
            builder.append("SELECT ");
1581
            if (this.distinct) {
1582
                builder.append("DISTINCT ");
1583
            }
1584
            boolean first = true;
1585
            for (SelectColumnBuilder column : columns) {
1586
                if (first) {
1587
                    first = false;
1588
                } else {
1589
                    builder.append(", ");
1590
                }
1591
                builder.append(column.toString(formatter));
1592
            }
1593

    
1594
            if (this.has_from()) {
1595
                builder.append(" FROM ");
1596
                builder.append(this.from.toString(formatter));
1597
            }
1598
            if (this.has_where()) {
1599
                builder.append(" WHERE ");
1600
                builder.append(this.where.toString(formatter));
1601
            }
1602
            if( this.has_group_by() ) {
1603
                builder.append(" GROUP BY ");
1604
                builder.append(this.groupColumn.get(0).toString(formatter));
1605
                for (int i = 1; i < groupColumn.size(); i++) {
1606
                    builder.append(", ");
1607
                    builder.append(this.groupColumn.get(i).toString(formatter));
1608
                }
1609
            }
1610
            if (this.has_order_by()) {
1611
                builder.append(" ORDER BY ");
1612
                first = true;
1613
                for (OrderByBuilder item : this.order_by) {
1614
                    if (first) {
1615
                        first = false;
1616
                    } else {
1617
                        builder.append(", ");
1618
                    }
1619
                    builder.append(item.toString(formatter));
1620
                }
1621
            }
1622

    
1623
            if (this.has_limit()) {
1624
                builder.append(" LIMIT ");
1625
                builder.append(this.limit);
1626
            }
1627
            if (this.has_offset()) {
1628
                builder.append(" OFFSET ");
1629
                builder.append(this.offset);
1630
            }
1631
            return builder.toString();
1632

    
1633
        }
1634
    }
1635

    
1636
    public class DropTableBuilderBase
1637
            extends AbstractStatement
1638
            implements DropTableBuilder {
1639

    
1640
        protected TableNameBuilder table;
1641

    
1642
        @Override
1643
        public TableNameBuilder table() {
1644
            if (table == null) {
1645
                table = createTableNameBuilder();
1646
            }
1647
            return table;
1648
        }
1649

    
1650
        @Override
1651
        public void accept(Visitor visitor, VisitorFilter filter) {
1652
            boolean visitChildren = true;
1653
            if (filter==null || filter.accept(this)) {
1654
                visitor.visit(this);
1655
            } else {
1656
                visitChildren = !filter.skipChildren();
1657
            }
1658
            if(visitChildren){
1659
                this.table.accept(visitor, filter);
1660
            }
1661
        }
1662

    
1663
        @Override
1664
        public String toString() {
1665
            return this.toString(formatter());
1666
        }
1667

    
1668
        @Override
1669
        public String toString(Formatter<Value> formatter) {
1670
            if (formatter!=null && formatter.canApply(this)) {
1671
                return formatter.format(this);
1672
            }
1673
            StringBuilder builder = new StringBuilder();
1674
            boolean first = true;
1675
            for (String sql : toStrings(formatter)) {
1676
                if (StringUtils.isEmpty(sql)) {
1677
                    continue;
1678
                }
1679
                if (first) {
1680
                    first = false;
1681
                } else {
1682
                    builder.append("; ");
1683
                }
1684
                builder.append(sql);
1685
            }
1686
            return builder.toString();
1687
        }
1688

    
1689
        @Override
1690
        public List<String> toStrings() {
1691
            return this.toStrings(formatter());
1692
        }
1693

    
1694
        @Override
1695
        public List<String> toStrings(Formatter formatter) {
1696
            List<String> sqls = new ArrayList<>();
1697

    
1698
            sqls.add(
1699
                    MessageFormat.format(
1700
                            STMT_DROP_TABLE_table,
1701
                            this.table.toString(formatter)
1702
                    )
1703
            );
1704
            String sql;
1705
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1706
                if (this.table.has_schema()) {
1707
                    sql = MessageFormat.format(
1708
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1709
                            as_string(this.table.getSchema()),
1710
                            as_string(this.table.getName())
1711
                    );
1712
                } else {
1713
                    sql = MessageFormat.format(
1714
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1715
                            as_identifier(this.table.getName())
1716
                    );
1717
                }
1718
                if (!StringUtils.isEmpty(sql)) {
1719
                    sqls.add(sql);
1720
                }
1721
            }
1722
            return sqls;
1723
        }
1724
    }
1725

    
1726
    public class GrantRoleBuilderBase
1727
            extends AbstractStatementPart
1728
            implements GrantRoleBuilder {
1729

    
1730
        protected TableNameBuilder table;
1731
        protected String role;
1732
        protected Set<Privilege> privileges;
1733

    
1734
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1735
            this.table = table;
1736
            this.role = role;
1737
            this.privileges = new HashSet<>();
1738
        }
1739
        
1740
        @Override
1741
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1742
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1743
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1744
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1745
            
1746
            return other;
1747
        }
1748

    
1749
        @Override
1750
        public GrantRoleBuilder privilege(Privilege privilege) {
1751
            privileges.add(privilege);
1752
            return this;
1753
        }
1754

    
1755
        @Override
1756
        public GrantRoleBuilder select() {
1757
            privileges.add(Privilege.SELECT);
1758
            return this;
1759
        }
1760

    
1761
        @Override
1762
        public GrantRoleBuilder update() {
1763
            privileges.add(Privilege.UPDATE);
1764
            return this;
1765
        }
1766

    
1767
        @Override
1768
        public GrantRoleBuilder insert() {
1769
            privileges.add(Privilege.INSERT);
1770
            return this;
1771
        }
1772

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

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

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

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

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

    
1803
        protected String getPrivilegeName(Privilege privilege) {
1804
            switch (privilege) {
1805
                case DELETE:
1806
                    return "DELETE";
1807
                case INSERT:
1808
                    return "INSERT";
1809
                case REFERENCE:
1810
                    return "REFERENCE";
1811
                case SELECT:
1812
                    return "SELECT";
1813
                case TRIGGER:
1814
                    return "TRIGGER";
1815
                case TRUNCATE:
1816
                    return "TRUNCATE";
1817
                case UPDATE:
1818
                    return "UPDATE";
1819
                case ALL:
1820
                default:
1821
                    return "ALL";
1822
            }
1823
        }
1824

    
1825
        @Override
1826
        public String toString() {
1827
            return this.toString(formatter());
1828
        }
1829

    
1830
        @Override
1831
        public String toString(Formatter<Value> formatter) {
1832
            if (formatter!=null && formatter.canApply(this)) {
1833
                return formatter.format(this);
1834
            }
1835
            StringBuilder builder = new StringBuilder();
1836
            boolean first = true;
1837
            for (Privilege privilege : privileges) {
1838
                if (first) {
1839
                    first = false;
1840
                } else {
1841
                    builder.append(", ");
1842
                }
1843
                builder.append(this.getPrivilegeName(privilege));
1844
            }
1845
            String sql = MessageFormat.format(
1846
                    STMT_GRANT_privileges_ON_table_TO_role,
1847
                    builder.toString(),
1848
                    table.toString(formatter),
1849
                    role
1850
            );
1851
            return sql;
1852
        }
1853
    }
1854

    
1855
    public class GrantBuilderBase
1856
            extends AbstractStatement
1857
            implements GrantBuilder {
1858

    
1859
        protected TableNameBuilder table;
1860
        protected Map<String, GrantRoleBuilder> roles;
1861

    
1862
        public GrantBuilderBase() {
1863
            this.roles = new HashMap<>();
1864
        }
1865

    
1866
        @Override
1867
        public TableNameBuilder table() {
1868
            if (table == null) {
1869
                table = createTableNameBuilder();
1870
            }
1871
            return table;
1872
        }
1873

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

    
1889
        @Override
1890
        public GrantRoleBuilder role(String role) {
1891
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1892
            if (roleBuilder == null) {
1893
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1894
                this.roles.put(role, roleBuilder);
1895
            }
1896
            return roleBuilder;
1897
        }
1898

    
1899
        @Override
1900
        public String toString() {
1901
            return this.toString(formatter());
1902
        }
1903

    
1904
        @Override
1905
        public String toString(Formatter<Value> formatter) {
1906
            if (formatter!=null && formatter.canApply(this)) {
1907
                return formatter.format(this);
1908
            }
1909
            StringBuilder builder = new StringBuilder();
1910
            boolean first = true;
1911
            for (String sql : toStrings(formatter)) {
1912
                if (StringUtils.isEmpty(sql)) {
1913
                    continue;
1914
                }
1915
                if (first) {
1916
                    first = false;
1917
                } else {
1918
                    builder.append("; ");
1919
                }
1920
                builder.append(sql);
1921
            }
1922
            return builder.toString();
1923
        }
1924

    
1925
        @Override
1926
        public List<String> toStrings() {
1927
            return this.toStrings(formatter());
1928
        }
1929

    
1930
        @Override
1931
        public List<String> toStrings(Formatter formatter) {
1932
            List<String> sqls = new ArrayList<>();
1933
            for (GrantRoleBuilder role : roles.values()) {
1934
                sqls.add(role.toString(formatter));
1935
            }
1936
            return sqls;
1937
        }
1938
    }
1939

    
1940
    public class UpdateColumnBuilderBase
1941
            extends InsertColumnBuilderBase
1942
            implements UpdateColumnBuilder {
1943

    
1944
        public UpdateColumnBuilderBase() {
1945
            super();
1946
        }
1947

    
1948
        @Override
1949
        public UpdateColumnBuilder name(String name) {
1950
            return (UpdateColumnBuilder) super.name(name);
1951
        }
1952

    
1953
        @Override
1954
        public UpdateColumnBuilder with_value(Value value) {
1955
            return (UpdateColumnBuilder) super.with_value(value);
1956
        }
1957

    
1958
    }
1959

    
1960
    public class UpdateBuilderBase
1961
            extends AbstractStatement
1962
            implements UpdateBuilder {
1963

    
1964
        protected GeometryExpressionBuilder where;
1965
        protected List<UpdateColumnBuilder> columns;
1966
        protected TableNameBuilder table;
1967

    
1968
        public UpdateBuilderBase() {
1969
            this.columns = new ArrayList<>();
1970
        }
1971

    
1972
        @Override
1973
        public void accept(Visitor visitor, VisitorFilter filter) {
1974
            boolean visitChildren = true;
1975
            if (filter==null || filter.accept(this)) {
1976
                visitor.visit(this);
1977
            } else {
1978
                visitChildren = !filter.skipChildren();
1979
            }
1980
            if(visitChildren){
1981
                if (this.table != null) {
1982
                    this.table.accept(visitor, filter);
1983
                }
1984
                for (UpdateColumnBuilder column : columns) {
1985
                    column.accept(visitor, filter);
1986
                }
1987
                if (this.has_where()) {
1988
                    this.where.accept(visitor, filter);
1989
                }
1990
            }
1991
        }
1992

    
1993
        @Override
1994
        public GeometryExpressionBuilder where() {
1995
            if (this.where == null) {
1996
                this.where = createExpressionBuilder();
1997
            }
1998
            return this.where;
1999
        }
2000

    
2001
        @Override
2002
        public TableNameBuilder table() {
2003
            if (table == null) {
2004
                table = createTableNameBuilder();
2005
            }
2006
            return table;
2007
        }
2008

    
2009
        @Override
2010
        public UpdateColumnBuilder column() {
2011
            UpdateColumnBuilder column = createUpdateColumnBuilder();
2012
            this.columns.add(column);
2013
            return column;
2014
        }
2015

    
2016
        @Override
2017
        public boolean has_where() {
2018
            return this.where != null;
2019
        }
2020

    
2021
        @Override
2022
        public String toString() {
2023
            return this.toString(formatter());
2024
        }
2025

    
2026
        @Override
2027
        public String toString(Formatter<Value> formatter) {
2028
            if (formatter!=null && formatter.canApply(this)) {
2029
                return formatter.format(this);
2030
            }
2031
            /*
2032
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
2033
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
2034
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
2035
             * output_expression [ AS output_name ] [, ...] ]
2036
             */
2037
            StringBuilder columnsAndValues = new StringBuilder();
2038

    
2039
            boolean first = true;
2040
            for (UpdateColumnBuilder column : columns) {
2041
                if (first) {
2042
                    first = false;
2043
                } else {
2044
                    columnsAndValues.append(", ");
2045
                }
2046
                columnsAndValues.append(as_identifier(column.getName()));
2047
                columnsAndValues.append(" = ");
2048
                columnsAndValues.append(column.getValue().toString(formatter));
2049
            }
2050

    
2051
            String sql;
2052
            if (this.has_where()) {
2053
                sql = MessageFormat.format(
2054
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
2055
                        this.table.toString(formatter),
2056
                        columnsAndValues.toString(),
2057
                        this.where.toString(formatter)
2058
                );
2059
            } else {
2060
                sql = MessageFormat.format(
2061
                        STMT_UPDATE_table_SET_columnsAndValues,
2062
                        this.table.toString(formatter),
2063
                        columnsAndValues.toString()
2064
                );
2065
            }
2066
            return sql;
2067
        }
2068
    }
2069

    
2070
    public class DeleteBuilderBase
2071
            extends AbstractStatement
2072
            implements DeleteBuilder {
2073

    
2074
        protected GeometryExpressionBuilder where;
2075
        protected TableNameBuilder table;
2076

    
2077
        public DeleteBuilderBase() {
2078
        }
2079

    
2080
        @Override
2081
        public void accept(Visitor visitor, VisitorFilter filter) {
2082
            boolean visitChildren = true;
2083
            if (filter==null || filter.accept(this)) {
2084
                visitor.visit(this);
2085
            } else {
2086
                visitChildren = !filter.skipChildren();
2087
            }
2088
            if(visitChildren){
2089
                if (this.table != null) {
2090
                    this.table.accept(visitor, filter);
2091
                }
2092
                if (this.has_where()) {
2093
                    this.where.accept(visitor, filter);
2094
                }
2095
            }
2096
        }
2097

    
2098
        @Override
2099
        public GeometryExpressionBuilder where() {
2100
            if (this.where == null) {
2101
                this.where = createExpressionBuilder();
2102
            }
2103
            return this.where;
2104
        }
2105

    
2106
        @Override
2107
        public TableNameBuilder table() {
2108
            if (table == null) {
2109
                table = createTableNameBuilder();
2110
            }
2111
            return table;
2112
        }
2113

    
2114
        @Override
2115
        public boolean has_where() {
2116
            return this.where != null;
2117
        }
2118

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

    
2124
        @Override
2125
        public String toString(Formatter<Value> formatter) {
2126
            if (formatter!=null && formatter.canApply(this)) {
2127
                return formatter.format(this);
2128
            }
2129
            /*
2130
             * DELETE FROM table_name
2131
             * WHERE some_column=some_value; 
2132
             */
2133
            String sql;
2134
            if (this.has_where()) {
2135
                sql = MessageFormat.format(
2136
                        STMT_DELETE_FROM_table_WHERE_expresion,
2137
                        this.table.toString(formatter),
2138
                        this.where.toString(formatter)
2139
                );
2140
            } else {
2141
                sql = MessageFormat.format(
2142
                        STMT_DELETE_FROM_table,
2143
                        this.table.toString(formatter)
2144
                );
2145
            }
2146
            return sql;
2147
        }
2148
    }
2149

    
2150
    public class CreateIndexBuilderBase
2151
            extends AbstractStatement
2152
            implements CreateIndexBuilder {
2153

    
2154
        protected boolean ifNotExist = false;
2155
        protected boolean isUnique = false;
2156
        protected String indexName;
2157
        protected boolean isSpatial = false;
2158
        protected TableNameBuilder table;
2159
        protected final List<String> columns;
2160

    
2161
        public CreateIndexBuilderBase() {
2162
            this.columns = new ArrayList<>();
2163
        }
2164

    
2165
        @Override
2166
        public CreateIndexBuilder unique() {
2167
            this.isUnique = true;
2168
            return this;
2169
        }
2170

    
2171
        @Override
2172
        public CreateIndexBuilder if_not_exist() {
2173
            this.ifNotExist = true;
2174
            return this;
2175
        }
2176

    
2177
        @Override
2178
        public CreateIndexBuilder name(String name) {
2179
            this.indexName = name;
2180
            return this;
2181
        }
2182

    
2183
        @Override
2184
        public CreateIndexBuilder name(String tableName, String columnName) {
2185
            this.indexName = tableName + "_IDX_" + columnName;
2186
            return this;
2187
        }
2188

    
2189
        @Override
2190
        public CreateIndexBuilder spatial() {
2191
            this.isSpatial = true;
2192
            return this;
2193
        }
2194

    
2195
        @Override
2196
        public CreateIndexBuilder column(String name) {
2197
            this.columns.add(name);
2198
            return this;
2199
        }
2200

    
2201
        @Override
2202
        public TableNameBuilder table() {
2203
            if (table == null) {
2204
                table = createTableNameBuilder();
2205
            }
2206
            return table;
2207
        }
2208

    
2209
        @Override
2210
        public void accept(Visitor visitor, VisitorFilter filter) {
2211
            boolean visitChildren = true;
2212
            if (filter==null || filter.accept(this)) {
2213
                visitor.visit(this);
2214
            } else {
2215
                visitChildren = !filter.skipChildren();
2216
            }
2217
            if(visitChildren){
2218
                if (this.table != null) {
2219
                    this.table.accept(visitor, filter);
2220
                }
2221
            }
2222
        }
2223

    
2224
        @Override
2225
        public String toString() {
2226
            return this.toString(formatter());
2227
        }
2228

    
2229
        @Override
2230
        public String toString(Formatter<Value> formatter) {
2231
            if (formatter!=null && formatter.canApply(this)) {
2232
                return formatter.format(this);
2233
            }
2234
            StringBuilder builder = new StringBuilder();
2235
            boolean first = true;
2236
            for (String sql : toStrings(formatter)) {
2237
                if (StringUtils.isEmpty(sql)) {
2238
                    continue;
2239
                }
2240
                if (first) {
2241
                    first = false;
2242
                } else {
2243
                    builder.append("; ");
2244
                }
2245
                builder.append(sql);
2246
            }
2247
            return builder.toString();
2248
        }
2249

    
2250
        @Override
2251
        public List<String> toStrings() {
2252
            return this.toStrings(formatter());
2253
        }
2254

    
2255
        @Override
2256
        public List<String> toStrings(Formatter formatter) {
2257
            StringBuilder builder = new StringBuilder();
2258
            builder.append("CREATE ");
2259
            if (this.isUnique) {
2260
                builder.append("UNIQUE ");
2261
            }
2262
            builder.append("INDEX ");
2263
            if (this.ifNotExist) {
2264
                builder.append("IF NOT EXISTS ");
2265
            }
2266
            builder.append(as_identifier(this.indexName));
2267
            builder.append(" ON ");
2268
            builder.append(this.table.toString(formatter));
2269
            if (this.isSpatial) {
2270
                builder.append(" USING GIST ");
2271
            }
2272
            builder.append(" ( ");
2273
            boolean is_first_column = true;
2274
            for (String column : this.columns) {
2275
                if (is_first_column) {
2276
                    is_first_column = false;
2277
                } else {
2278
                    builder.append(", ");
2279
                }
2280
                builder.append(column);
2281
            }
2282
            builder.append(" )");
2283

    
2284
            List<String> sqls = new ArrayList<>();
2285
            sqls.add(builder.toString());
2286
            return sqls;
2287
        }
2288

    
2289
    }
2290

    
2291
    public class DropIndexBuilderBase
2292
            extends AbstractStatement
2293
            implements DropIndexBuilder {
2294

    
2295
        protected boolean ifExist = false;
2296
        protected String indexName;
2297

    
2298
        public DropIndexBuilderBase() {
2299
        }
2300

    
2301
        @Override
2302
        public DropIndexBuilder if_exist() {
2303
            this.ifExist = true;
2304
            return this;
2305
        }
2306

    
2307
        @Override
2308
        public DropIndexBuilder name(String name) {
2309
            this.indexName = name;
2310
            return this;
2311
        }
2312

    
2313
        @Override
2314
        public DropIndexBuilder name(String tableName, String columnName) {
2315
            this.indexName = tableName + "_IDX_" + columnName;
2316
            return this;
2317
        }
2318

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

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

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

    
2350
        @Override
2351
        public List<String> toStrings(Formatter formatter) {
2352
            StringBuilder builder = new StringBuilder();
2353
            builder.append("DROP INDEX ");
2354
            if (this.ifExist) {
2355
                builder.append("IF EXISTS ");
2356
            }
2357
            builder.append(as_identifier(this.indexName));
2358
            List<String> sqls = new ArrayList<>();
2359
            sqls.add(builder.toString());
2360
            return sqls;
2361
        }
2362

    
2363
    }
2364

    
2365
    public class AlterTableBuilderBase
2366
            extends AbstractStatement
2367
            implements AlterTableBuilder {
2368
             
2369
        protected TableNameBuilder table;
2370
        protected List<String> drops;
2371
        protected List<ColumnDescriptor> adds;
2372
        
2373
        // alters debera dejarse de usar en fabor de operation_alters
2374
        @Deprecated
2375
        protected List<ColumnDescriptor> alters;
2376
        protected List<Pair<Bitmask,ColumnDescriptor>> operations;
2377
        
2378
        protected List<Pair<String, String>> renames;
2379
        protected String drop_primary_key_column;
2380
        private final SQLBuilderBase sqlbuilder;
2381

    
2382
        public AlterTableBuilderBase(SQLBuilderBase sqlbuilder) {
2383
            this.sqlbuilder = sqlbuilder;
2384
            this.drops = new ArrayList<>();
2385
            this.adds = new ArrayList<>();
2386
            this.alters = new ArrayList<>();
2387
            this.operations = new ArrayList<>();
2388
            this.renames = new ArrayList<>();
2389
        }
2390

    
2391
        public List<Pair<Bitmask,ColumnDescriptor>> getOperations() {
2392
            return this.operations;
2393
        }
2394
        
2395
        @Override
2396
        public boolean isEmpty() {
2397
            return this.drops.isEmpty()
2398
                    && this.adds.isEmpty()
2399
                    && this.alters.isEmpty()
2400
                    && this.operations.isEmpty()
2401
                    && this.renames.isEmpty();
2402
        }
2403

    
2404
        @Override
2405
        public void accept(Visitor visitor, VisitorFilter filter) {
2406
            boolean visitChildren = true;
2407
            if (filter==null || filter.accept(this)) {
2408
                visitor.visit(this);
2409
            } else {
2410
                visitChildren = !filter.skipChildren();
2411
            }
2412
            if(visitChildren){
2413
                if (this.table != null) {
2414
                    this.table.accept(visitor, filter);
2415
                }
2416
            }
2417
        }
2418

    
2419
        @Override
2420
        public TableNameBuilder table() {
2421
            if (table == null) {
2422
                table = createTableNameBuilder();
2423
            }
2424
            return table;
2425
        }
2426

    
2427
        @Override
2428
        public AlterTableBuilder drop_column(String columnName) {
2429
            this.drops.add(columnName);
2430
            return this;
2431
        }
2432

    
2433
        @Override
2434
        public AlterTableBuilder drop_primary_key(String columnName) {
2435
            this.drop_primary_key_column = columnName;
2436
            return this;
2437
        }
2438

    
2439
        @Override
2440
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2441
            this.adds.add(new ColumnDescriptorBase(fad));
2442
            return this;
2443
        }
2444

    
2445
        @Override
2446
        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) {
2447
            if (isPk || isAutomatic) {
2448
                allowNulls = false;
2449
            }
2450
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds));
2451
            return this;
2452
        }
2453

    
2454
        @Override
2455
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2456
            if (StringUtils.isEmpty(columnName)) {
2457
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2458
            }
2459
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2460
            return this;
2461
        }
2462

    
2463
        @Override
2464
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2465
            if (StringUtils.isEmpty(columnName)) {
2466
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2467
            }
2468
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2469
            return this;
2470
        }
2471

    
2472
        private void update_or_add_alters(ColumnDescriptorBase column) {
2473
            int i = 0;
2474
            for (; i < alters.size(); i++) {
2475
                ColumnDescriptor prevColumn = alters.get(i);
2476
                if( prevColumn.getName().equalsIgnoreCase(column.getName()) ) {
2477
                    // Si ya existia la actualizamos
2478
                    alters.set(i, column);
2479
                    break;
2480
                }
2481
                
2482
            }
2483
            if( i >= alters.size() ) {
2484
                // Si no existis la a?adimos
2485
                this.alters.add(column);
2486
            }
2487
        }
2488
        
2489
        @Override
2490
        public AlterTableBuilder alter_column(Bitmask operation, FeatureAttributeDescriptor fad) {
2491
            ColumnDescriptorBase column = new ColumnDescriptorBase(fad);
2492
            update_or_add_alters(column);
2493
            if( operation==null ) {
2494
                operation = Bitmask.createBitmask(0);
2495
            }
2496
            if( operation.isEmpty() ) {
2497
                operation.setBit(ALTER_COLUMN_ALL);
2498
            }
2499
            this.operations.add(new ImmutablePair<>(operation,column));
2500
            return this;
2501
        }
2502

    
2503
        @Override
2504
        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) {
2505
            if ( (isPk || isAutomatic) && allowNulls) {
2506
                allowNulls = false;
2507
                operation.setBit(ALTER_COLUMN_SET_NULL);
2508
            }
2509
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue, allowIndexDuplicateds);
2510
            update_or_add_alters(column);
2511
            if( operation == null ) {
2512
                operation = Bitmask.createBitmask(0);
2513
            }
2514
            if( operation.isEmpty() ) {
2515
                operation.setBit(ALTER_COLUMN_ALL);
2516
            }
2517
            this.operations.add(new ImmutablePair<>(operation,column));
2518
            return this;
2519
        }
2520

    
2521
//        @Override
2522
//        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) {
2523
//            if ( (isPk || isAutomatic) && allowNulls) {
2524
//                allowNulls = false;
2525
//                operation.setBit(ALTER_COLUMN_SET_NULL);
2526
//            }
2527
//            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue);
2528
//            update_or_add_alters(column);
2529
//            this.operations.add(new ImmutablePair<>(operation,column));
2530
//            return this;
2531
//        }
2532

    
2533
        @Override
2534
        public AlterTableBuilder alter_geometry_column(Bitmask operation, String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2535
            if (StringUtils.isEmpty(columnName)) {
2536
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2537
            }
2538
            ColumnDescriptorBase column = new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls);
2539
            update_or_add_alters(column);
2540
            if( operation == null ) {
2541
                operation = Bitmask.createBitmask(0);
2542
            }
2543
            if( operation.isEmpty() ) {
2544
                operation.setBit(ALTER_COLUMN_ALL);
2545
            }
2546
            operation.setBit(ALTER_COLUMN_GEOMETRY);
2547
            this.operations.add(new ImmutablePair<>(operation,column));
2548
            return this;
2549
        }
2550

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

    
2566
        @Override
2567
        public AlterTableBuilder rename_column(String source, String target) {
2568
            this.renames.add(new ImmutablePair(source, target));
2569
            return this;
2570
        }
2571

    
2572
        protected String getConstrainName(String constrainType, String columnName) {
2573
            return this.sqlbuilder.getConstrainName(table, columnName, constrainType);
2574
        }
2575

    
2576
        protected List<String> alter_table_add_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2577
            // ALTER TABLE table_name ADD CONSTRAINT IF NOT EXISTS constraint_name PRIMARY KEY(column_name)
2578
            List<String> sqls = new ArrayList<>();
2579
            StringBuilder builder = new StringBuilder();
2580
            builder.append("ALTER TABLE ");
2581
            builder.append(this.table.toString(formatter));
2582
            builder.append(" ADD CONSTRAINT ");
2583
            builder.append("IF NOT EXISTS ");
2584
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2585
            builder.append(" PRIMARY KEY( ");
2586
            builder.append(as_identifier(column.getName()));
2587
            builder.append(" )");
2588
            sqls.add(builder.toString());
2589
            return sqls;
2590
        }
2591

    
2592
        protected List<String> alter_table_drop_primarykey_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2593
            // ALTER TABLE table_name DROP CONSTRAINT constraint_name
2594
            StringBuilder builder = new StringBuilder();
2595
            builder.append("ALTER TABLE ");
2596
            builder.append(this.table.toString(formatter));
2597
            builder.append(" DROP CONSTRAINT ");
2598
            builder.append("IF EXISTS ");
2599
            builder.append(as_identifier(getConstrainName("PK",column.getName())));
2600
            return Collections.singletonList(builder.toString());
2601
        }
2602
        
2603
        protected List<String> create_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2604
            CreateIndexBuilder createIndex = this.sqlbuilder.createCreateIndexBuilder();
2605
            if( column.isGeometry() ) {
2606
                createIndex.spatial();
2607
            }
2608
            createIndex.if_not_exist();
2609
            createIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2610
            createIndex.column(column.getName());
2611
            createIndex.table()
2612
                    .database(this.table.getDatabase())
2613
                    .schema(this.table.getSchema())
2614
                    .name(this.table.getName()
2615
            );
2616
            if(!column.allowIndexDuplicateds()){
2617
                createIndex.unique();
2618
            }
2619
            return createIndex.toStrings();
2620
        }
2621

    
2622
        protected List<String> drop_index_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2623
            DropIndexBuilder dropIndex = this.sqlbuilder.createDropIndexBuilder();
2624
            dropIndex.if_exist();
2625
            dropIndex.name(as_identifier(getConstrainName("IDX",column.getName())));
2626
            return dropIndex.toStrings();
2627
        }
2628

    
2629
        protected List<String> alter_table_alter_column_set_data_type_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2630
            StringBuilder builder = new StringBuilder();
2631
            builder.append("ALTER TABLE ");
2632
            builder.append(this.table.toString(formatter));
2633
            builder.append(" ALTER COLUMN ");
2634
            builder.append(as_identifier(column.getName()));
2635
            builder.append(" SET DATA TYPE ");
2636
            if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2637
                builder.append(" SERIAL");
2638
            } else {
2639
                builder.append(
2640
                        sqltype(
2641
                                column.getType(),
2642
                                column.getSize(),
2643
                                column.getPrecision(),
2644
                                column.getScale(),
2645
                                column.getGeometryType(),
2646
                                column.getGeometrySubtype()
2647
                        )
2648
                );
2649
            }
2650
            return Collections.singletonList(builder.toString());
2651
        }
2652
        
2653
        protected List<String> alter_table_alter_column_set_default_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2654
            StringBuilder builder = new StringBuilder();
2655
            builder.append("ALTER TABLE ");
2656
            builder.append(this.table.toString(formatter));
2657
            builder.append(" ALTER COLUMN ");
2658
            builder.append(as_identifier(column.getName()));
2659
            if (column.getDefaultValue() == null) {
2660
                if (column.allowNulls()) {
2661
                    builder.append(" SET DEFAULT NULL");
2662
                } else {
2663
                    builder.append(" DROP DEFAULT");
2664
                }
2665
            } else {
2666
                builder.append(" SET DEFAULT '");
2667
                builder.append(column.getDefaultValue().toString());
2668
                builder.append("'");
2669
            }
2670
            return Collections.singletonList(builder.toString());
2671
        }
2672

    
2673
        protected List<String> alter_table_alter_column_set_null_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.allowNulls()) {
2680
                builder.append(" SET NULL");
2681
            } else {
2682
                builder.append(" SET NOT NULL");
2683
            }
2684
            return Collections.singletonList(builder.toString());
2685
        }
2686

    
2687
        protected List<String> alter_table_drop_column_sqls(Formatter<Value> formatter, String columnName) {
2688
            StringBuilder builder = new StringBuilder();
2689
            builder.append("ALTER TABLE ");
2690
            builder.append(this.table.toString(formatter));
2691
            builder.append(" DROP COLUMN ");
2692
            builder.append(" IF EXISTS ");
2693
            builder.append(as_identifier(columnName));
2694
            return Collections.singletonList(builder.toString());
2695
        }
2696

    
2697
        protected List<String> alter_table_add_column_sqls(Formatter<Value> formatter, ColumnDescriptor column) {
2698
            List<String> sqls = new ArrayList<>();
2699
            StringBuilder builder = new StringBuilder();
2700
            builder.append("ALTER TABLE ");
2701
            builder.append(this.table.toString(formatter));
2702
            builder.append(" ADD COLUMN ");
2703
            builder.append(as_identifier(column.getName()));
2704
            builder.append(" ");
2705
            if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2706
                builder.append(" SERIAL");
2707
            } else {
2708
                builder.append(
2709
                        sqltype(
2710
                                column.getType(),
2711
                                column.getSize(),
2712
                                column.getPrecision(),
2713
                                column.getScale(),
2714
                                column.getGeometryType(),
2715
                                column.getGeometrySubtype()
2716
                        )
2717
                );
2718
            }
2719
            if (column.getDefaultValue() == null) {
2720
                if (column.allowNulls()) {
2721
                    builder.append(" DEFAULT NULL");
2722
                }
2723
            } else {
2724
                builder.append(" DEFAULT '");
2725
                builder.append(Objects.toString(column.getDefaultValue(),""));
2726
                builder.append("'");
2727
            }
2728
            if (column.allowNulls()) {
2729
                builder.append(" NULL");
2730
            } else {
2731
                builder.append(" NOT NULL");
2732
            }
2733
            if (column.isPrimaryKey()) {
2734
                builder.append(" PRIMARY KEY");
2735
            }
2736
            sqls.add(builder.toString());
2737
            
2738
            if( column.isGeometry() ) {
2739
                sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2740
            }
2741
            if( column.isIndexed() ) {
2742
                sqls.addAll(create_index_sqls(formatter, column));
2743
            }
2744
            return sqls;
2745
        }
2746

    
2747
        protected List<String> alter_table_alter_column_rename_sqls(Formatter<Value> formatter, String oldName, String newName) {
2748
            StringBuilder builder = new StringBuilder();
2749
            builder.append("ALTER TABLE ");
2750
            builder.append(this.table.toString(formatter));
2751
            builder.append(" ALTER COLUMN ");
2752
            builder.append(as_identifier(oldName));
2753
            builder.append(" RENAME TO ");
2754
            builder.append(as_identifier(newName));
2755
            return Collections.singletonList(builder.toString());
2756
        }
2757

    
2758
        protected List<String> alter_column_add_geometry_constraint_sqls(Formatter<ExpressionBuilder.Value> formatter, ColumnDescriptor column) {
2759
            return Collections.EMPTY_LIST;
2760
        }
2761
        
2762
        @Override
2763
        public String toString() {
2764
            return this.toString(formatter());
2765
        }
2766

    
2767
        @Override
2768
        public String toString(Formatter<Value> formatter) {
2769
            if (formatter!=null && formatter.canApply(this)) {
2770
                return formatter.format(this);
2771
            }
2772
            StringBuilder builder = new StringBuilder();
2773
            boolean first = true;
2774
            for (String sql : toStrings(formatter)) {
2775
                if (StringUtils.isEmpty(sql)) {
2776
                    continue;
2777
                }
2778
                if (first) {
2779
                    first = false;
2780
                } else {
2781
                    builder.append("; ");
2782
                }
2783
                builder.append(sql);
2784
            }
2785
            return builder.toString();
2786
        }
2787

    
2788
        @Override
2789
        public List<String> toStrings() {
2790
            return this.toStrings(formatter());
2791
        }
2792

    
2793
        @Override
2794
        public List<String> toStrings(Formatter formatter) {
2795
            List<String> sqls = new ArrayList<>();
2796
            if (this.isEmpty()) {
2797
                return sqls;
2798
            }
2799
            for (String column : drops) {
2800
                sqls.addAll(alter_table_drop_column_sqls(formatter, column));
2801
            }
2802
            for (ColumnDescriptor column : adds) {
2803
                sqls.addAll(alter_table_add_column_sqls(formatter, column));
2804
            }
2805
            for (Pair<Bitmask,ColumnDescriptor> operationAndColumn : this.getOperations()) {
2806
                Bitmask operation = operationAndColumn.getLeft();
2807
                ColumnDescriptor column = operationAndColumn.getRight();
2808
                if( operation.isSetBit(ALTER_COLUMN_ALL) ) {
2809
                    if( column.isPrimaryKey() ) {
2810
                        sqls.addAll(alter_table_add_primarykey_sqls(formatter, column));
2811
                    } else {
2812
                        sqls.addAll(alter_table_drop_primarykey_sqls(formatter, column));
2813
                        if( column.isIndexed() ) {
2814
                            sqls.addAll(create_index_sqls(formatter, column));
2815
                        }
2816
                    }
2817
                    sqls.addAll(alter_table_alter_column_set_data_type_sqls(formatter, column));
2818
                    sqls.addAll(alter_table_alter_column_set_default_sqls(formatter, column));
2819
                    sqls.addAll(alter_table_alter_column_set_null_sqls(formatter, column));
2820
                    if( column.isGeometry() ) {
2821
                        sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2822
                    }
2823
                } else {
2824
                    if( operation.isSetBit(ALTER_COLUMN_SET_NULL) ) { // Debe ir antes del "add primary key"
2825
                        sqls.addAll(alter_table_alter_column_set_null_sqls(formatter, column));
2826
                    }
2827
                    
2828
                    if( operation.isSetBit(ALTER_COLUMN_SET_DATA_TYPE) ) {
2829
                        sqls.addAll(alter_table_alter_column_set_data_type_sqls(formatter, column));
2830
                    }
2831
                    
2832
                    if( operation.isSetBit(ALTER_COLUMN_ADD_PRIMARY_KEY) ) {
2833
                        sqls.addAll(alter_table_add_primarykey_sqls(formatter, column));
2834
                    }
2835
                    
2836
                    if( operation.isSetBit(ALTER_COLUMN_DROP_PRIMARY_KEY) ) {
2837
                        sqls.addAll(alter_table_drop_primarykey_sqls(formatter, column));
2838
                    }
2839
                    
2840
                    if( operation.isSetBit(ALTER_COLUMN_SET_DEFAULT) ) {
2841
                        sqls.addAll(alter_table_alter_column_set_default_sqls(formatter, column));
2842
                    }
2843
                    
2844
                    if( operation.isSetBit(ALTER_COLUMN_CREATE_INDEX) ) {
2845
                        sqls.addAll(create_index_sqls(formatter, column));
2846
                    }
2847
                    
2848
                    if( operation.isSetBit(ALTER_COLUMN_DROP_INDEX) ) {
2849
                        sqls.addAll(drop_index_sqls(formatter, column));
2850
                    }
2851
                    
2852
                    if( operation.isSetBit(ALTER_COLUMN_GEOMETRY) ) {
2853
                        if( column.isGeometry() ) {
2854
                            sqls.addAll(alter_column_add_geometry_constraint_sqls(formatter, column));
2855
                        }
2856
                    }
2857
                        
2858
                }
2859
            }
2860
            
2861
            for (Pair<String, String> pair : renames) {
2862
                sqls.addAll(alter_table_alter_column_rename_sqls(formatter, pair.getLeft(), pair.getRight()));
2863
            }
2864
            return sqls;
2865
        }
2866

    
2867
    }
2868

    
2869
    public class CreateTableBuilderBase
2870
            extends AbstractStatement
2871
            implements CreateTableBuilder {
2872

    
2873
        protected TableNameBuilder table;
2874
        protected List<ColumnDescriptor> columns;
2875

    
2876
        public CreateTableBuilderBase() {
2877
            this.columns = new ArrayList<>();
2878
        }
2879

    
2880
        @Override
2881
        public void accept(Visitor visitor, VisitorFilter filter) {
2882
            boolean visitChildren = true;
2883
            if (filter==null || filter.accept(this)) {
2884
                visitor.visit(this);
2885
            } else {
2886
                visitChildren = !filter.skipChildren();
2887
            }
2888
            if(visitChildren){
2889
                if (this.table != null) {
2890
                    this.table.accept(visitor, filter);
2891
                }
2892
            }
2893
        }
2894

    
2895
        @Override
2896
        public TableNameBuilder table() {
2897
            if (table == null) {
2898
                table = createTableNameBuilder();
2899
            }
2900
            return table;
2901
        }
2902

    
2903
        @Override
2904
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2905
            this.columns.add(new ColumnDescriptorBase(fad));
2906
            return this;
2907
        }
2908

    
2909
        @Override
2910
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2911
            if (StringUtils.isEmpty(columnName)) {
2912
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2913
            }
2914
            if (isPk || isAutomatic) {
2915
                allowNulls = false;
2916
            }
2917
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2918
            return this;
2919
        }
2920

    
2921
        @Override
2922
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2923
            if (StringUtils.isEmpty(columnName)) {
2924
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2925
            }
2926
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2927
            return this;
2928
        }
2929

    
2930
        @Override
2931
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2932
            if (StringUtils.isEmpty(columnName)) {
2933
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2934
            }
2935
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2936
            return this;
2937
        }
2938

    
2939
        @Override
2940
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2941
            if (StringUtils.isEmpty(columnName)) {
2942
                return null;
2943
            }
2944
            for (ColumnDescriptor column : columns) {
2945
                if (columnName.equals(column.getName())) {
2946
                    return column;
2947
                }
2948
            }
2949
            return null;
2950
        }
2951

    
2952
        @Override
2953
        public String toString() {
2954
            return this.toString(formatter());
2955
        }
2956

    
2957
        @Override
2958
        public String toString(Formatter<Value> formatter) {
2959
            if (formatter!=null && formatter.canApply(this)) {
2960
                return formatter.format(this);
2961
            }
2962
            StringBuilder builder = new StringBuilder();
2963
            boolean first = true;
2964
            for (String sql : toStrings(formatter)) {
2965
                if (StringUtils.isEmpty(sql)) {
2966
                    continue;
2967
                }
2968
                if (first) {
2969
                    first = false;
2970
                } else {
2971
                    builder.append("; ");
2972
                }
2973
                builder.append(sql);
2974
            }
2975
            return builder.toString();
2976
        }
2977

    
2978
        @Override
2979
        public List<String> toStrings() {
2980
            return this.toStrings(formatter());
2981
        }
2982

    
2983
        @Override
2984
        /*
2985
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
2986
        */
2987
        public List<String> toStrings(Formatter formatter) {
2988
            List<String> sqls = new ArrayList<>();
2989
            /**
2990
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2991
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2992
             * column_constraint [ ... ] ] | table_constraint | LIKE
2993
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2994
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2995
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2996
             *
2997
             * where column_constraint is:
2998
             *
2999
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
3000
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
3001
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
3002
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
3003
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
3004
             *
3005
             * and table_constraint is:
3006
             *
3007
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
3008
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
3009
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
3010
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
3011
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
3012
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
3013
             */
3014
            
3015
            StringBuilder builder = new StringBuilder();
3016

    
3017
            builder.append("CREATE TABLE ");
3018
            builder.append(this.table.toString(formatter));
3019
            builder.append(" (");
3020
            boolean first = true;
3021
            for (ColumnDescriptor column : columns) {
3022
                if (first) {
3023
                    first = false;
3024
                } else {
3025
                    builder.append(", ");
3026
                }
3027
                builder.append(as_identifier(column.getName()));
3028
                builder.append(" ");
3029
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
3030
                    builder.append("SERIAL");
3031
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
3032
                    builder.append("BIGSERIAL");
3033
                } else {
3034
                    builder.append(sqltype(
3035
                            column.getType(),
3036
                            column.getSize(),
3037
                            column.getPrecision(),
3038
                            column.getScale(),
3039
                            column.getGeometryType(),
3040
                            column.getGeometrySubtype()
3041
                    )
3042
                    );
3043
                }
3044
                if (column.getDefaultValue() == null) {
3045
                    if (column.allowNulls()) {
3046
                        builder.append(" DEFAULT NULL");
3047
                    }
3048
                } else {
3049
                    builder.append(" DEFAULT '");
3050
                    builder.append(Objects.toString(column.getDefaultValue(),""));
3051
                    builder.append("'");
3052
                }
3053
                if (column.isPrimaryKey()) {
3054
                    builder.append(" NOT NULL");
3055
                    builder.append(" PRIMARY KEY");
3056
                } else {
3057
                    if (column.allowNulls()) {
3058
                        builder.append(" NULL");
3059
                    } else {
3060
                        builder.append(" NOT NULL");
3061
                    }
3062
                }
3063
            }
3064
            builder.append(" )");
3065
            sqls.add(builder.toString());
3066
            return sqls;
3067
        }
3068
    }
3069

    
3070
    public class InsertColumnBuilderBase
3071
            extends AbstractStatement
3072
            implements InsertColumnBuilder {
3073

    
3074
        protected Variable name;
3075
        protected Value value;
3076

    
3077
        public InsertColumnBuilderBase() {
3078
        }
3079

    
3080
        @Override
3081
        public void accept(Visitor visitor, VisitorFilter filter) {
3082
            boolean visitChildren = true;
3083
            if (filter==null || filter.accept(this)) {
3084
                visitor.visit(this);
3085
            } else {
3086
                visitChildren = !filter.skipChildren();
3087
            }
3088
            if(visitChildren){
3089
                if (this.name != null) {
3090
                    this.name.accept(visitor, filter);
3091
                }
3092
                if (this.value != null) {
3093
                    this.value.accept(visitor, filter);
3094
                }
3095
            }
3096
        }
3097

    
3098
        @Override
3099
        public InsertColumnBuilder name(String name) {
3100
            this.name = expression().variable(name);
3101
            return this;
3102
        }
3103

    
3104
        @Override
3105
        public InsertColumnBuilder with_value(Value value) {
3106
            this.value = value;
3107
            return this;
3108
        }
3109

    
3110
        @Override
3111
        public String getName() {
3112
            return this.name.name();
3113
        }
3114

    
3115
        @Override
3116
        public Value getValue() {
3117
            return this.value;
3118
        }
3119

    
3120
        @Override
3121
        public String toString() {
3122
            return this.toString(formatter());
3123
        }
3124

    
3125
        @Override
3126
        public String toString(Formatter<Value> formatter) {
3127
            if (formatter!=null && formatter.canApply(this)) {
3128
                return formatter.format(this);
3129
            }
3130
            return this.value.toString(formatter);
3131
        }
3132
    }
3133

    
3134
    public class InsertBuilderBase
3135
            extends AbstractStatement
3136
            implements InsertBuilder {
3137

    
3138
        protected List<InsertColumnBuilder> columns;
3139
        protected TableNameBuilder table;
3140

    
3141
        public InsertBuilderBase() {
3142
            this.columns = new ArrayList<>();
3143
        }
3144

    
3145
        @Override
3146
        public void accept(Visitor visitor, VisitorFilter filter) {
3147
            boolean visitChildren = true;
3148
            if (filter==null || filter.accept(this)) {
3149
                visitor.visit(this);
3150
            } else {
3151
                visitChildren = !filter.skipChildren();
3152
            }
3153
            if(visitChildren){
3154
                if (this.table != null) {
3155
                    this.table.accept(visitor, filter);
3156
                }
3157
                for (InsertColumnBuilder column : columns) {
3158
                    column.accept(visitor, filter);
3159
                }
3160
            }
3161
        }
3162

    
3163
        @Override
3164
        public TableNameBuilder table() {
3165
            if (table == null) {
3166
                table = createTableNameBuilder();
3167
            }
3168
            return table;
3169
        }
3170

    
3171
        @Override
3172
        public InsertColumnBuilder column() {
3173
            InsertColumnBuilder column = createInsertColumnBuilder();
3174
            this.columns.add(column);
3175
            return column;
3176
        }
3177

    
3178
        @Override
3179
        public String toString() {
3180
            return this.toString(formatter());
3181
        }
3182

    
3183
        @Override
3184
        public String toString(Formatter<Value> formatter) {
3185
            if (formatter!=null && formatter.canApply(this)) {
3186
                return formatter.format(this);
3187
            }
3188
            /*
3189
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
3190
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
3191
             * output_expression [ AS output_name ] [, ...] ]
3192
             */
3193
            StringBuilder builderColumns = new StringBuilder();
3194
            StringBuilder builderValues = new StringBuilder();
3195

    
3196
            boolean first = true;
3197
            for (InsertColumnBuilder column : columns) {
3198
                if (first) {
3199
                    first = false;
3200
                } else {
3201
                    builderColumns.append(", ");
3202
                }
3203
                builderColumns.append(as_identifier(column.getName()));
3204
            }
3205
            first = true;
3206
            for (InsertColumnBuilder column : columns) {
3207
                if (first) {
3208
                    first = false;
3209
                } else {
3210
                    builderValues.append(", ");
3211
                }
3212
                builderValues.append(column.toString(formatter));
3213
            }
3214

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

    
3223
        }
3224
    }
3225

    
3226
    public class UpdateTableStatisticsBuilderBase
3227
            extends AbstractStatement
3228
            implements UpdateTableStatisticsBuilder {
3229

    
3230
        protected TableNameBuilder table;
3231

    
3232
        @Override
3233
        public void accept(Visitor visitor, VisitorFilter filter) {
3234
            boolean visitChildren = true;
3235
            if (filter==null || filter.accept(this)) {
3236
                visitor.visit(this);
3237
            } else {
3238
                visitChildren = !filter.skipChildren();
3239
            }
3240
            if(visitChildren){
3241
                if (this.table != null) {
3242
                    this.table.accept(visitor, filter);
3243
                }
3244
            }
3245
        }
3246

    
3247
        @Override
3248
        public TableNameBuilder table() {
3249
            if (table == null) {
3250
                table = createTableNameBuilder();
3251
            }
3252
            return table;
3253
        }
3254

    
3255
        @Override
3256
        public String toString() {
3257
            return this.toString(formatter());
3258
        }
3259

    
3260
        @Override
3261
        public String toString(Formatter<Value> formatter) {
3262
            if (formatter!=null && formatter.canApply(this)) {
3263
                return formatter.format(this);
3264
            }
3265
            StringBuilder builder = new StringBuilder();
3266
            boolean first = true;
3267
            for (String sql : toStrings(formatter)) {
3268
                if (StringUtils.isEmpty(sql)) {
3269
                    continue;
3270
                }
3271
                if (first) {
3272
                    first = false;
3273
                } else {
3274
                    builder.append("; ");
3275
                }
3276
                builder.append(sql);
3277
            }
3278
            return builder.toString();
3279
        }
3280

    
3281
        @Override
3282
        public List<String> toStrings() {
3283
            return this.toStrings(formatter());
3284
        }
3285

    
3286
        @Override
3287
        public List<String> toStrings(Formatter formatter) {
3288
            List<String> sqls = new ArrayList<>();
3289

    
3290
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
3291
                String sql = MessageFormat.format(
3292
                        STMT_UPDATE_TABLE_STATISTICS_table,
3293
                        table.toString(formatter)
3294
                );
3295
                if (!StringUtils.isEmpty(sql)) {
3296
                    sqls.add(sql);
3297
                }
3298
            }
3299
            return sqls;
3300
        }
3301
    }
3302

    
3303
    protected GeometryExpressionBuilder expressionBuilder;
3304

    
3305
    protected String defaultSchema;
3306
    protected boolean supportSchemas;
3307
    protected boolean hasSpatialFunctions;
3308
    protected GeometrySupportType geometrySupportType;
3309
    protected boolean allowAutomaticValues;
3310

    
3311
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
3312

    
3313
    protected String constant_true = "(1=1)";
3314
    protected String constant_false = "(1<>1)";
3315

    
3316
    protected String type_boolean = "BOOLEAN";
3317
    protected String type_byte = "TINYINT";
3318
    protected String type_bytearray = "BYTEA";
3319
    protected String type_geometry = "TEXT";
3320
    protected String type_char = "CHARACTER(1)";
3321
    protected String type_date = "DATE";
3322
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
3323
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
3324
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
3325
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
3326
    protected String type_int = "INT";
3327
    protected String type_long = "BIGINT";
3328
    protected String type_string = "TEXT";
3329
    protected String type_string_p = "VARCHAR({0,Number,#######})";
3330
    protected String type_time = "TIME";
3331
    protected String type_timestamp = "TIMESTAMP";
3332
    protected String type_version = "VARCHAR(30)";
3333
    protected String type_URI = "TEXT";
3334
    protected String type_URL = "TEXT";
3335
    protected String type_FILE = "TEXT";
3336
    protected String type_FOLDER = "TEXT";
3337

    
3338
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
3339
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
3340
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
3341
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
3342
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
3343
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
3344
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
3345
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
3346
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
3347
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3348

    
3349
    public SQLBuilderBase() {
3350
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3351
        this.expressionBuilder.setProperty(PROP_SQLBUILDER, this);
3352

    
3353
        this.hasSpatialFunctions = false;
3354
        this.supportSchemas = true;
3355
        this.geometrySupportType = GeometrySupportType.WKT;
3356

    
3357
        this.defaultSchema = "public";
3358
        this.allowAutomaticValues = true;
3359

    
3360
    }
3361
    
3362
    @Override
3363
    public void setProperties(Class filter, final Object... values) {
3364
        this.expressionBuilder.setProperties(filter, values);
3365
        setProperties(this, filter, values);
3366
    }
3367
    
3368
    @Override
3369
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3370
        if(visitable == null){
3371
            return;
3372
        }
3373
        if(visitable instanceof PropertiesSupport){
3374
            for (int i = 0; i < values.length; i+=2) {
3375
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3376
            }
3377
        }
3378
        visitable.accept((Visitable v) -> {
3379
            if(v instanceof PropertiesSupport){
3380
                for (int i = 0; i < values.length; i+=2) {
3381
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3382
                }
3383
            }
3384
        }, new ClassVisitorFilter(filter) );
3385
    }
3386

    
3387
    public String quote_for_identifiers() {
3388
        return "\"";
3389
    }
3390

    
3391
    public String quote_for_strings() {
3392
        return "'";
3393
    }
3394

    
3395
    @Override
3396
    public String as_identifier(String id) {
3397
        String quote = this.quote_for_identifiers();
3398
//        No se porque no esta disponible wrapIfMissing
3399
//        return StringUtils.wrapIfMissing(id,quote);
3400
        if (id.startsWith(quote)) {
3401
            return id;
3402
        }
3403
        return quote + id + quote;
3404

    
3405
    }
3406
    
3407
    @Override
3408
    public String as_clob(String s) {
3409
        int chunkSize = 1024;
3410
        StringBuilder builder = new StringBuilder();
3411
        builder.append("(CAST('");
3412
        for (int i = 0; i < s.length(); i += chunkSize) {
3413
            String chunk = s.substring(i, Math.min(s.length(), i + chunkSize));
3414
            if( i>0 ) {
3415
                builder.append("' AS NCLOB) || CAST('");
3416
            }            
3417
            builder.append(StringUtils.replace(chunk, "'", "''"));
3418
        }
3419
        builder.append("' AS NCLOB))");
3420
        return builder.toString();
3421
    }
3422

    
3423
    @Override
3424
    public String as_string(String s) {
3425
        String quote = this.quote_for_strings();
3426
//        No se porque no esta disponible wrapIfMissing
3427
//        return StringUtils.wrapIfMissing(id,quote);
3428
        if (s.startsWith(quote)) {
3429
            return s;
3430
        }
3431
        return quote + s + quote;
3432

    
3433
    }
3434

    
3435
    @Override
3436
    public String as_string(byte[] data) {
3437
        return this.expressionBuilder.bytearray_0x(data);
3438
//        return this.expressionBuilder.bytearray_hex(data);
3439
//        return this.expressionBuilder.bytearray_x(data);
3440
    }
3441
    
3442
    @Override
3443
    public String as_string(boolean value) {
3444
        return value? "TRUE" : "FALSE";
3445
    }
3446

    
3447
    @Override
3448
    public String as_string(Number value) {
3449
        return Objects.toString(value);
3450
    }
3451
    
3452
    @Override
3453
    public String as_string(Object value) {
3454
        if( value == null ) {
3455
            return "NULL";
3456
        }
3457
        if( value instanceof CharSequence ) {
3458
            return as_string(value.toString());
3459
        }
3460
        if( value instanceof Number ) {
3461
            return as_string((Number)value);
3462
        }
3463
        if( value instanceof Boolean ) {
3464
            return as_string((boolean)value);
3465
        }
3466
        if( value instanceof byte[] ) {
3467
            return as_string((byte[])value);
3468
        }
3469
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3470
    }
3471
    
3472
    @Override
3473
    public GeometryExpressionBuilder expression() {
3474
        return this.expressionBuilder;
3475
    }
3476

    
3477
    @Override
3478
    public boolean has_spatial_functions() {
3479
        return this.hasSpatialFunctions;
3480
    }
3481

    
3482
    @Override
3483
    public GeometrySupportType geometry_support_type() {
3484
        return this.geometrySupportType;
3485
    }
3486

    
3487
    protected GeometryExpressionBuilder createExpressionBuilder() {
3488
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3489
    }
3490

    
3491
    @Override
3492
    public Object srs_id(IProjection projection) {
3493
        String abrev = projection.getAbrev();
3494
        return abrev.split(":")[1].trim();
3495
    }
3496

    
3497
    @Override
3498
    public String default_schema() {
3499
        return this.defaultSchema;
3500
    }
3501

    
3502
    @Override
3503
    public boolean support_schemas() {
3504
        return this.supportSchemas;
3505
    }
3506

    
3507
    @Override
3508
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3509
        switch (type) {
3510
            case DataTypes.BOOLEAN:
3511
                return type_boolean;
3512
            case DataTypes.CHAR:
3513
                return type_char;
3514

    
3515

    
3516
            case DataTypes.BYTE:
3517
                return type_byte;
3518
            case DataTypes.INT:
3519
                return type_int;
3520
            case DataTypes.LONG:
3521
                return type_long;
3522

    
3523
            case DataTypes.FLOAT:
3524
                return type_float;
3525
            case DataTypes.DOUBLE:
3526
                return type_double;
3527
            case DataTypes.DECIMAL:
3528
                if (precision < 1) {
3529
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3530
                }
3531
                if (scale < 1) {
3532
                  return MessageFormat.format(type_decimal_p, precision);
3533
                }
3534
                return MessageFormat.format(type_decimal_ps, precision, scale);
3535

    
3536
                
3537
            case DataTypes.STRING:
3538
                if (size < 0) {
3539
                    return type_string;
3540
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3541
                    return MessageFormat.format(type_string_p, size);
3542
                }
3543
                return type_string;
3544

    
3545
                
3546
            case DataTypes.DATE:
3547
                return type_date;
3548
            case DataTypes.TIME:
3549
                return type_time;
3550
            case DataTypes.TIMESTAMP:
3551
                return type_timestamp;
3552

    
3553
            case DataTypes.BYTEARRAY:
3554
                return type_bytearray;
3555

    
3556
            case DataTypes.GEOMETRY:
3557
                return type_geometry;
3558

    
3559
            case DataTypes.VERSION:
3560
                return type_version;
3561
            case DataTypes.URI:
3562
                return type_URI;
3563
            case DataTypes.URL:
3564
                return type_URL;
3565
            case DataTypes.FILE:
3566
                return type_FILE;
3567
            case DataTypes.FOLDER:
3568
                return type_FOLDER;
3569
            default:
3570
                return null;
3571
        }
3572
    }
3573

    
3574
    @Override
3575
    public Object sqlgeometrytype(int type, int subtype) {
3576
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3577
        // identificadores numericos para el tipo y otros strings.
3578
        // Por defecto vamos a devolver strings.
3579
        if (sqlgeometrytypes == null) {
3580
            sqlgeometrytypes = new HashMap<>();
3581
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3582
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3583
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3584
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3585

    
3586
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3587
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3588
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3589
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3590

    
3591
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3592
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3593
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3594
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3595

    
3596
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3597
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3598
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3599
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3600

    
3601
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3602
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3603
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3604
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3605

    
3606
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3607
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3608
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3609
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3610

    
3611
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3612
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3613
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3614
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3615

    
3616
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3617
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3618
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3619
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3620

    
3621
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3622
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3623
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3624
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3625
        }
3626
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3627
    }
3628

    
3629
    @Override
3630
    public Object sqlgeometrydimension(int type, int subtype) {
3631
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3632
        // identificadores numericos para las dimensiones y otros strings.
3633
        // Por defecto vamos a devolver enteros.
3634
        switch (subtype) {
3635
            case Geometry.SUBTYPES.GEOM3D:
3636
                return 3;
3637
            case Geometry.SUBTYPES.GEOM2DM:
3638
                return 3;
3639
            case Geometry.SUBTYPES.GEOM3DM:
3640
                return 4;
3641
            case Geometry.SUBTYPES.GEOM2D:
3642
            default:
3643
                return 2;
3644
        }
3645
    }
3646

    
3647
    @Override
3648
    public SelectColumnBuilder column() {
3649
        return createSelectColumnBuilder();
3650
    }
3651

    
3652
    @Override
3653
    public TableNameBuilder createTableNameBuilder() {
3654
        return new TableNameBuilderBase();
3655
    }
3656

    
3657
    protected SelectColumnBuilder createSelectColumnBuilder() {
3658
        return new SelectColumnBuilderBase(this);
3659
    }
3660

    
3661
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3662
        return new UpdateColumnBuilderBase();
3663
    }
3664

    
3665
    protected InsertColumnBuilder createInsertColumnBuilder() {
3666
        return new InsertColumnBuilderBase();
3667
    }
3668

    
3669
    protected OrderByBuilder createOrderByBuilder() {
3670
        return new OrderByBuilderBase();
3671
    }
3672

    
3673
    protected FromBuilder createFromBuilder() {
3674
        return new FromBuilderBase();
3675
    }
3676

    
3677
    public SelectBuilder createSelectBuilder() {
3678
        return new SelectBuilderBase();
3679
    }
3680

    
3681
    protected UpdateBuilder createUpdateBuilder() {
3682
        return new UpdateBuilderBase();
3683
    }
3684

    
3685
    protected DeleteBuilder createDeleteBuilder() {
3686
        return new DeleteBuilderBase();
3687
    }
3688

    
3689
    protected GrantBuilder createGrantBuilder() {
3690
        return new GrantBuilderBase();
3691
    }
3692

    
3693
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3694
        return new GrantRoleBuilderBase(table, role);
3695
    }
3696

    
3697
    protected DropTableBuilder createDropTableBuilder() {
3698
        return new DropTableBuilderBase();
3699
    }
3700

    
3701
    protected CreateTableBuilder createCreateTableBuilder() {
3702
        return new CreateTableBuilderBase();
3703
    }
3704

    
3705
    protected AlterTableBuilder createAlterTableBuilder() {
3706
        return new AlterTableBuilderBase(this);
3707
    }
3708

    
3709
    protected InsertBuilder createInsertBuilder() {
3710
        return new InsertBuilderBase();
3711
    }
3712

    
3713
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3714
        return new UpdateTableStatisticsBuilderBase();
3715
    }
3716

    
3717
    protected CreateIndexBuilder createCreateIndexBuilder() {
3718
        return new CreateIndexBuilderBase();
3719
    }
3720

    
3721
    protected DropIndexBuilder createDropIndexBuilder() {
3722
        return new DropIndexBuilderBase();
3723
    }
3724
    
3725
    @Override
3726
    public SelectBuilder select() {
3727
        if (this.select == null) {
3728
            this.select = this.createSelectBuilder();
3729
        }
3730
        return this.select;
3731
    }
3732

    
3733
    @Override
3734
    public UpdateBuilder update() {
3735
        if (this.update == null) {
3736
            this.update = this.createUpdateBuilder();
3737
        }
3738
        return this.update;
3739
    }
3740

    
3741
    @Override
3742
    public UpdateTableStatisticsBuilder update_table_statistics() {
3743
        if (this.update_table_statistics == null) {
3744
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3745
        }
3746
        return this.update_table_statistics;
3747
    }
3748

    
3749
    @Override
3750
    public DropTableBuilder drop_table() {
3751
        if (this.drop_table == null) {
3752
            this.drop_table = this.createDropTableBuilder();
3753
        }
3754
        return this.drop_table;
3755
    }
3756

    
3757
    @Override
3758
    public CreateIndexBuilder create_index() {
3759
        if (this.create_index == null) {
3760
            this.create_index = this.createCreateIndexBuilder();
3761
        }
3762
        return this.create_index;
3763
    }
3764

    
3765
    @Override
3766
    public DropIndexBuilder drop_index() {
3767
        if (this.drop_index == null) {
3768
            this.drop_index = this.createDropIndexBuilder();
3769
        }
3770
        return this.drop_index;
3771
    }
3772

    
3773
    @Override
3774
    public DeleteBuilder delete() {
3775
        if (this.delete == null) {
3776
            this.delete = this.createDeleteBuilder();
3777
        }
3778
        return this.delete;
3779
    }
3780

    
3781
    @Override
3782
    public InsertBuilder insert() {
3783
        if (this.insert == null) {
3784
            this.insert = this.createInsertBuilder();
3785
        }
3786
        return this.insert;
3787
    }
3788

    
3789
    @Override
3790
    public TableNameBuilder table_name() {
3791
        if (this.table_name == null) {
3792
            this.table_name = this.createTableNameBuilder();
3793
        }
3794
        return this.table_name;
3795
    }
3796

    
3797
    
3798
    @Override
3799
    public AlterTableBuilder alter_table() {
3800
        if (this.alter_table == null) {
3801
            this.alter_table = this.createAlterTableBuilder();
3802
        }
3803
        return this.alter_table;
3804
    }
3805

    
3806
    @Override
3807
    public CreateTableBuilder create_table() {
3808
        if (this.create_table == null) {
3809
            this.create_table = this.createCreateTableBuilder();
3810
        }
3811
        return this.create_table;
3812
    }
3813

    
3814
    @Override
3815
    public GrantBuilder grant() {
3816
        if (this.grant == null) {
3817
            this.grant = this.createGrantBuilder();
3818
        }
3819
        return this.grant;
3820
    }
3821
    
3822
    @Override
3823
    public Column column(String name) {
3824
        ColumnBase col = new ColumnBase(null, name);
3825
        return col;
3826
    }
3827

    
3828
    @Override
3829
    public Column column(TableNameBuilder table, String name) {
3830
        ColumnBase col = new ColumnBase(table, name);
3831
        return col;
3832
    }
3833
    
3834
    public Column column_from(Variable variable) {
3835
        Column c = null;
3836
        if (variable instanceof Column) {
3837
            c = this.column(((Column) variable).table(), variable.name());
3838
        } else {
3839
            c = this.column(variable.name());
3840
        }
3841
        c.copyPropertiesFrom(variable);
3842
        return c;
3843

    
3844
    }
3845

    
3846
    public Column column_from(TableNameBuilder table, Variable variable) {
3847
        Column c = this.column(table, variable.name());
3848
        c.copyPropertiesFrom(variable);
3849
        return c;
3850
    }
3851
        
3852

    
3853
    
3854
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3855
        return new JoinBase(type, table, expression);
3856
    }
3857

    
3858
    @Override
3859
    public void accept(Visitor visitor, VisitorFilter filter) {
3860
        if (this.select != null) {
3861
            this.select.accept(visitor, filter);
3862
        }
3863
        if (this.update != null) {
3864
            this.update.accept(visitor, filter);
3865
        }
3866
        if (this.insert != null) {
3867
            this.insert.accept(visitor, filter);
3868
        }
3869
        if (this.delete != null) {
3870
            this.delete.accept(visitor, filter);
3871
        }
3872
        if (this.alter_table != null) {
3873
            this.alter_table.accept(visitor, filter);
3874
        }
3875
        if (this.create_table != null) {
3876
            this.create_table.accept(visitor, filter);
3877
        }
3878
        if (this.drop_table != null) {
3879
            this.drop_table.accept(visitor, filter);
3880
        }
3881
        if (this.table_name != null) {
3882
            this.table_name.accept(visitor, filter);
3883
        }
3884
    }
3885

    
3886
    @Override
3887
    public Formatter formatter() {
3888
        return expression().formatter();
3889
    }
3890

    
3891
    @Override
3892
    public String toString() {
3893
        return this.toString(formatter());
3894
    }
3895

    
3896
    @Override
3897
    public String toString(Formatter formatter) {
3898
        if (this.select != null) {
3899
            return this.select.toString(formatter);
3900
        }
3901
        if (this.update != null) {
3902
            return this.update.toString(formatter);
3903
        }
3904
        if (this.insert != null) {
3905
            return this.insert.toString(formatter);
3906
        }
3907
        if (this.delete != null) {
3908
            return this.delete.toString(formatter);
3909
        }
3910
        if (this.alter_table != null) {
3911
            return this.alter_table.toString(formatter);
3912
        }
3913
        if (this.create_table != null) {
3914
            return this.create_table.toString(formatter);
3915
        }
3916
        if (this.drop_table != null) {
3917
            return this.drop_table.toString(formatter);
3918
        }
3919
        if (this.update_table_statistics != null) {
3920
            return this.update_table_statistics.toString(formatter);
3921
        }
3922
        if (this.create_index != null) {
3923
            return this.create_index.toString(formatter);
3924
        }
3925
        if (this.drop_index != null) {
3926
            return this.drop_index.toString(formatter);
3927
        }
3928
        if (this.table_name != null) {
3929
            return this.table_name.toString(formatter);
3930
        }
3931
        return "";
3932
    }
3933

    
3934
    @Override
3935
    public CountBuilder count() {
3936
        return new CountBuilderBase();
3937
    }
3938

    
3939
    @Override
3940
    public List<Parameter> parameters() {
3941
        final List<Parameter> params = new ArrayList<>();
3942
        this.accept((Visitable value) -> {
3943
            params.add((Parameter) value);
3944
        }, new ClassVisitorFilter(Parameter.class));
3945
        return params;
3946
    }
3947

    
3948
    @Override
3949
    public List<Variable> variables() {
3950
        final List<Variable> vars = new ArrayList<>();
3951
        this.accept(new Visitor() {
3952
            @Override
3953
            public void visit(Visitable value) {
3954
                if (!vars.contains((Variable) value)) {
3955
                    vars.add((Variable) value);
3956
                }
3957
            }
3958
        }, new ClassVisitorFilter(Variable.class));
3959
        return vars;
3960
    }
3961

    
3962
    @Override
3963
    public List<String> parameters_names() {
3964
        List<String> params = new ArrayList<>();
3965
        for (Parameter param : parameters()) {
3966
            String s;
3967
            switch (param.type()) {
3968
                case PARAMETER_TYPE_CONSTANT:
3969
                    Object theValue = param.value();
3970
                    if (theValue == null) {
3971
                        s = "null";
3972
                    } else if (theValue instanceof String) {
3973
                        s = "'" + (String) theValue + "'";
3974
                    } else {
3975
                        s = theValue.toString();
3976
                    }
3977
                    break;
3978
                case PARAMETER_TYPE_VARIABLE:
3979
                default:
3980
                    s = "\"" + param.name() + "\"";
3981
            }
3982
            params.add(s);
3983
        }
3984
        return params;
3985
    }
3986

    
3987
    @Override
3988
    public List<String> variables_names() {
3989
        List<String> vars = new ArrayList<>();
3990
        for (Variable var : this.variables()) {
3991
            vars.add(var.name());
3992
        }
3993
        Collections.sort(vars);
3994
        return vars;
3995
    }    
3996
    
3997
    protected String[] aggregateFunctionNames = new String[] {
3998
        "MAX",
3999
        "MIN",
4000
        "COUNT",
4001
        "SUM"
4002
    };
4003
    
4004
    @Override
4005
    public boolean isAggregateFunction(String funcname) {
4006
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
4007
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
4008
                return true;
4009
            }
4010
        }
4011
        return false;
4012
    }
4013

    
4014
    @Override
4015
    public int getMaxRecomendedSQLLength() {
4016
        return DEFAULT_RECOMENDED_SQL_LENGTH;
4017
    }
4018
    
4019
    public String getConstrainName(TableNameBuilder table, String columnName, String constrainType) {
4020
        // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
4021
        String constraint_name = table.getName() + "_" + constrainType + "_" + columnName;
4022
        return constraint_name;
4023
    }    
4024
}