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

History | View | Annotate | Download (123 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.PropertiesSupport;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62

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

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

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

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

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

    
92
    protected class ColumnDescriptorBase implements ColumnDescriptor {
93

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

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

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

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

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

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

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

    
209
        @Override
210
        public String getName() {
211
            return this.name;
212
        }
213

    
214
        @Override
215
        public void setName(String name) {
216
            this.name = name;
217
        }
218

    
219
        @Override
220
        public int getType() {
221
            return this.type;
222
        }
223

    
224
        @Override
225
        public void setType(int type) {
226
            this.type = type;
227
        }
228

    
229
        @Override
230
        public int getPrecision() {
231
            return precision;
232
        }
233

    
234
        @Override
235
        public void setPrecision(int precision) {
236
            this.precision = precision;
237
        }
238

    
239
        @Override
240
        public int getScale() {
241
            return scale;
242
        }
243

    
244
        @Override
245
        public void setScale(int scale) {
246
            this.scale = scale;
247
        }
248

    
249
        @Override
250
        public int getSize() {
251
            return size;
252
        }
253

    
254
        @Override
255
        public void setSize(int size) {
256
            this.size = size;
257
        }
258

    
259
        @Override
260
        public boolean isPrimaryKey() {
261
            return isPk;
262
        }
263

    
264
        @Override
265
        public void setIsPrimaryKey(boolean isPk) {
266
            this.isPk = isPk;
267
        }
268

    
269
        @Override
270
        public boolean allowNulls() {
271
            return _allowNulls;
272
        }
273

    
274
        @Override
275
        public void setAllowNulls(boolean allowNulls) {
276
            this._allowNulls = allowNulls;
277
        }
278

    
279
        @Override
280
        public boolean isAutomatic() {
281
            return _isAutomatic;
282
        }
283

    
284
        @Override
285
        public boolean isIndexed() {
286
            return _isIndexed;
287
        }
288

    
289
        @Override
290
        public void setIsAutomatic(boolean isAutomatic) {
291
            this._isAutomatic = isAutomatic;
292
        }
293

    
294
        @Override
295
        public Object getDefaultValue() {
296
            return defaultValue;
297
        }
298

    
299
        @Override
300
        public void setDefaultValue(Object defaultValue) {
301
            this.defaultValue = defaultValue;
302
        }
303

    
304
        @Override
305
        public int getGeometryType() {
306
            return geom_type;
307
        }
308

    
309
        @Override
310
        public void setGeometryType(int geom_type) {
311
            this.geom_type = geom_type;
312
        }
313

    
314
        @Override
315
        public int getGeometrySubtype() {
316
            return geom_subtype;
317
        }
318

    
319
        @Override
320
        public void setGeometrySubtype(int geom_subtype) {
321
            this.geom_subtype = geom_subtype;
322
        }
323

    
324
        @Override
325
        public Object getGeometrySRSId() {
326
            return geom_srsdbcode;
327
        }
328

    
329
        @Override
330
        public void setGeometrySRSId(Object geom_srsid) {
331
            this.geom_srsdbcode = geom_srsid;
332
        }
333

    
334
        @Override
335
        public boolean isGeometry() {
336
            return this.type == DataTypes.GEOMETRY;
337
        }
338

    
339
        private void setStoreParameters(DataStoreParameters parameters) {
340
            this.parameters = parameters;
341
        }
342

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

    
357
    public class ColumnBase extends AbstractValue implements Column {
358

    
359
        private final String name;
360
        private TableNameBuilder table;
361

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

    
374

    
375
        @Override
376
        public String name() {
377
            return this.name;
378
        }
379

    
380
        @Override
381
        public TableNameBuilder table() {
382
            return this.table;
383
        }
384

    
385
        @Override
386
        public TableNameBuilder table(TableNameBuilder table) {
387
            this.table = table;
388
            return this.table;
389
        }
390

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

    
407
        @Override
408
        public int compareTo(Variable o) {
409
            return this.name.compareTo(o.name());
410
        }
411

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

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

    
428
    public class TableNameBuilderBase
429
            extends AbstractStatementPart
430
            implements TableNameBuilder {
431

    
432
        public String tableName;
433
        public String schemaName;
434
        private String databaseName;
435

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

    
446
        @Override
447
        public TableNameBuilder database(String name) {
448
            this.databaseName = name;
449
            return this;
450
        }
451

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

    
460
        @Override
461
        public TableNameBuilder name(String name) {
462
            this.tableName = name;
463
            return this;
464
        }
465

    
466
        @Override
467
        public String getDatabase() {
468
            return this.databaseName;
469
        }
470

    
471
        @Override
472
        public String getSchema() {
473
            return this.schemaName;
474
        }
475

    
476
        @Override
477
        public String getName() {
478
            return this.tableName;
479
        }
480

    
481
        @Override
482
        public boolean has_schema() {
483
            if (!support_schemas()) {
484
                return false;
485
            }
486
            return StringUtils.isNotBlank(this.schemaName);
487
        }
488

    
489
        @Override
490
        public boolean has_name() {
491
            return StringUtils.isNotBlank(this.tableName);
492
        }
493

    
494
        @Override
495
        public boolean has_database() {
496
            return StringUtils.isNotBlank(this.databaseName);
497
        }
498

    
499
        @Override
500
        public boolean isEmpty() {
501
            return !this.has_database() && !this.has_schema() && !this.has_name();
502
        }
503

    
504
        @Override
505
        public String toString() {
506
            return this.toString(formatter());
507
        }
508

    
509
        @Override
510
        public String toString(Formatter<Value> formatter) {
511
            if (formatter!=null && formatter.canApply(this)) {
512
                return formatter.format(this);
513
            }
514
            if (this.has_database()) {
515
                if (this.has_schema()) {
516
                    return as_identifier(this.databaseName) + "."
517
                            + as_identifier(this.schemaName) + "."
518
                            + as_identifier(this.tableName);
519
                }
520
//                return as_identifier(this.databaseName) + "."
521
//                        + as_identifier(this.tableName);
522
            } else {
523
                if (this.has_schema()) {
524
                    return as_identifier(this.schemaName) + "."
525
                            + as_identifier(this.tableName);
526
                }
527
            }
528
            return as_identifier(this.tableName);
529
        }
530

    
531
        @Override
532
        public boolean equals(Object obj) {
533
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
534
                return false;
535
            }
536
            TableNameBuilder other = (TableNameBuilder) obj;
537
            
538
            if (this.has_database() != other.has_database()) {
539
                return false;
540
            }
541
            String thisSchema = null;
542
            String otherSchema = null;
543
            if(support_schemas()) {
544
                thisSchema = this.schemaName;
545
                if (StringUtils.isBlank(thisSchema)) {
546
                    thisSchema = default_schema();
547
                }
548
                otherSchema = other.getSchema();
549
                if (StringUtils.isBlank(otherSchema)) {
550
                    otherSchema = default_schema();
551
                }
552
            }
553
            if (this.has_database()) {
554
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
555
                           StringUtils.equals(thisSchema, otherSchema) &&
556
                           StringUtils.equals(this.tableName,other.getName());
557
            } else {
558
                    return StringUtils.equals(thisSchema, otherSchema) &&
559
                           StringUtils.equals(this.tableName,other.getName());
560
            }
561
        }
562

    
563
        @Override
564
        public int hashCode() {
565
            int hash = 7;
566
            hash = 37 * hash + Objects.hashCode(this.toString());
567
            return hash;
568
        }
569

    
570
    }
571

    
572
    public class CountBuilderBase
573
            extends AbstractStatementPart
574
            implements CountBuilder {
575

    
576
        protected Value value;
577
        protected boolean distinct;
578
        protected boolean all;
579

    
580
        public CountBuilderBase() {
581
            this.value = null;
582
            this.distinct = false;
583
            this.all = false;
584
        }
585
        
586
        @Override
587
        public CountBuilderBase clone() throws CloneNotSupportedException {
588
            CountBuilderBase other = (CountBuilderBase) super.clone();
589
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
590
            return other;
591
        }
592
        
593
        @Override
594
        public CountBuilder all() {
595
            this.all = true;
596
            return this;
597
        }
598

    
599
        @Override
600
        public CountBuilder column(Value value) {
601
            this.value = value;
602
            return this;
603
        }
604

    
605
        @Override
606
        public CountBuilder distinct() {
607
            this.distinct = true;
608
            return this;
609
        }
610

    
611
        @Override
612
        public String toString() {
613
            return this.toString(formatter());
614
        }
615

    
616
        @Override
617
        public String toString(Formatter formatter) {
618
            if (formatter!=null && formatter.canApply(this)) {
619
                return formatter.format(this);
620
            }
621
            if (this.all) {
622
                return "COUNT(*)";
623
            }
624
            if (this.distinct) {
625
                return MessageFormat.format(
626
                        "COUNT(DISTINCT {0})",
627
                        value.toString(formatter)
628
                );
629
            }
630
            return MessageFormat.format(
631
                    "COUNT({0})",
632
                    value.toString(formatter)
633
            );
634
        }
635

    
636
    }
637

    
638
    protected class JoinBase 
639
            extends AbstractStatementPart
640
            implements JoinBuilder 
641
        {
642
        protected String type;
643
        protected TableNameBuilder table;
644
        protected Value expression;
645
        
646
        public JoinBase(String type, TableNameBuilder table, Value expression) {
647
            this.type = type;
648
            this.table = table;
649
            this.expression = expression;
650
        }
651
        
652
        @Override
653
        public JoinBase clone() throws CloneNotSupportedException {
654
            JoinBase other = (JoinBase) super.clone();
655
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
656
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
657
            return other;
658
        }
659

    
660
        @Override
661
        public String toString() {
662
            return this.toString(formatter());
663
        }
664

    
665
        @Override
666
        public String toString(Formatter<Value> formatter) {
667
            if (formatter!=null && formatter.canApply(this)) {
668
                return formatter.format(this);
669
            }
670
            StringBuilder builder = new StringBuilder();
671
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
672
            builder.append(this.type.toUpperCase());
673
            builder.append(" JOIN ");
674
            builder.append(this.table.toString(formatter));
675
            builder.append(" ON ");
676
            builder.append(this.expression.toString(formatter));
677
            return builder.toString();
678
        }
679
        
680
        @Override
681
        public TableNameBuilder getTable() {
682
            return this.table;
683
        }
684
        
685
        @Override
686
        public String getType() {
687
            return this.type;
688
        }
689

    
690
        @Override
691
        public Value getCondition() {
692
            return this.expression;
693
        }
694
    }
695
    
696
    public class FromBuilderBase
697
            extends AbstractStatementPart
698
            implements FromBuilder {
699

    
700
        protected TableNameBuilder tableName;
701
        protected String subquery;
702
        protected String passthrough;
703
        protected List<JoinBuilder> joins;
704

    
705
        public FromBuilderBase() {
706
            this.tableName = null;
707
            this.subquery = null;
708
            this.passthrough = null;
709
            this.joins = null;
710
        }
711
        
712
        @Override
713
        public FromBuilderBase clone() throws CloneNotSupportedException {
714
            FromBuilderBase other = (FromBuilderBase) super.clone();
715
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
716
            if (joins!=null) {
717
                for (int i = 0; i < joins.size(); i++) {
718
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
719
                }
720
            }
721
            return other;
722
        }
723

    
724
        @Override
725
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
726
            JoinBase join = createJoin("LEFT", table, expression);
727
            if( this.joins==null ) {
728
                this.joins = new ArrayList<>();
729
            }
730
            this.joins.add(join);
731
            return this;
732
        }
733
        
734
        @Override
735
        public TableNameBuilder table() {
736
            if (tableName == null) {
737
                this.tableName = createTableNameBuilder();
738
            }
739
            return this.tableName;
740
        }
741

    
742
        @Override
743
        public void accept(Visitor visitor, VisitorFilter filter) {
744
            boolean visitChildren = true;
745
            if (filter==null || filter.accept(this)) {
746
                visitor.visit(this);
747
            } else {
748
                visitChildren = !filter.skipChildren();
749
            }
750
            if(visitChildren){
751
                if (this.tableName != null) {
752
                    this.tableName.accept(visitor, filter);
753
                }
754
            }
755
        }
756

    
757
        @Override
758
        public FromBuilder custom(String passthrough) {
759
            this.passthrough = passthrough;
760
            return this;
761
        }
762

    
763
        @Override
764
        public FromBuilder subquery(String subquery) {
765
            this.subquery = subquery;
766
            return this;
767
        }
768

    
769
        @Override
770
        public String toString() {
771
            return this.toString(formatter());
772
        }
773

    
774
        @Override
775
        public String toString(Formatter<Value> formatter) {
776
            if (formatter!=null && formatter.canApply(this)) {
777
                return formatter.format(this);
778
            }
779
            if (!StringUtils.isEmpty(passthrough)) {
780
                return passthrough;
781
            }
782
            if (!StringUtils.isEmpty(subquery)) {
783
                return "( " + this.subquery + ") AS _subquery_alias_ ";
784
            }
785
            if( this.joins==null || this.joins.isEmpty() ) {
786
                return this.tableName.toString(formatter);
787
            }
788
            StringBuilder builder = new StringBuilder();
789
            builder.append(this.tableName.toString(formatter));
790
            for (JoinBuilder join : this.joins) {
791
                builder.append(" ");
792
                builder.append(join.toString(formatter));
793
            }
794
            return builder.toString();
795
        }
796

    
797
        @Override
798
        public List<JoinBuilder> getJoins() {
799
            return this.joins;
800
        }
801

    
802
    }
803

    
804
    public class SelectColumnBuilderBase
805
            extends AbstractStatementPart
806
            implements SelectColumnBuilder {
807

    
808
        protected Column name = null;
809
        protected String alias = null;
810
        protected Value value = null;
811
        protected boolean asGeometry = false;
812
        protected TableNameBuilder table;
813
        protected SQLBuilder sqlbuilder;
814
        
815
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
816
            this.sqlbuilder = sqlbuilder;
817
        }
818
        
819
        @Override
820
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
821
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
822
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
823
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
824
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
825
            return other;
826
        }
827

    
828
        @Override
829
        public void accept(Visitor visitor, VisitorFilter filter) {
830
            boolean visitChildren = true;
831
            if (filter==null || filter.accept(this)) {
832
                visitor.visit(this);
833
            } else {
834
                visitChildren = !filter.skipChildren();
835
            }
836
            if(visitChildren){
837
                if (this.value != null) {
838
                    this.value.accept(visitor, filter);
839
                } else if (this.name != null) {
840
                    this.name.accept(visitor, filter);
841
                }
842
            }
843
        }
844

    
845
        @Override
846
        public void replace(Value target, Value replacement) {
847
            if (this.name!=null ) {
848
                if( this.name == target) {
849
                    if(replacement == null){
850
                        this.name = null;
851
                    } else if(replacement instanceof Column){
852
                        this.name = (Column) replacement;
853
                    } else if(replacement instanceof Variable){
854
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
855
                    } else {
856
                        this.value = replacement;
857
                    }
858
                }
859
            }
860
            if( this.value!=null ) {
861
                if (this.value == target) {
862
                    this.value = replacement;
863
                } else {
864
                    this.value.replace(target, replacement);
865
                }
866
            }
867
        }
868

    
869
        @Override
870
        public SelectColumnBuilder name(String name) {
871
            return this.name(this.table, name);
872
        }
873

    
874
        @Override
875
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
876
            String quote = quote_for_identifiers();
877
            if (name.startsWith(quote)) {
878
                // Remove quotes
879
                name = name.substring(1, name.length() - 1);
880
            }
881
            this.table = table;
882
            this.name = new ColumnBase(this.table, name);
883
            this.value = null;
884
            this.asGeometry = false;
885
            return this;
886
        }
887
        
888
        public SelectColumnBuilder table(TableNameBuilder table) {
889
            this.table = table;
890
            if(this.name != null){
891
                this.name.table(table);
892
            }
893
            return this;
894
        }
895
        
896
        @Override
897
        public SelectColumnBuilder all() {
898
            this.name = null;
899
            this.value = expression().custom("*");
900
            this.asGeometry = false;
901
            return this;
902
        }
903

    
904
        @Override
905
        public SelectColumnBuilder as_geometry() {
906
            this.asGeometry = true;
907
            return this;
908
        }
909

    
910
        @Override
911
        public SelectColumnBuilder value(Value value) {
912
            this.value = value;
913
            return this;
914
        }
915

    
916
        @Override
917
        public SelectColumnBuilder as(String alias) {
918
            this.alias = alias;
919
            return this;
920
        }
921

    
922
        @Override
923
        public String getName() {
924
            if (this.name==null) {
925
                return null;
926
            }
927
            return this.name.name();
928
        }
929

    
930
        @Override
931
        public String getAlias() {
932
            return this.alias;
933
        }
934

    
935
        @Override
936
        public Value getValue() {
937
            return this.value;
938
        }
939

    
940
        @Override
941
        public String toString() {
942
            return this.toString(formatter());
943
        }
944

    
945
        @Override
946
        public String toString(Formatter<Value> formatter) {
947
            if (formatter!=null && formatter.canApply(this)) {
948
                return formatter.format(this);
949
            }
950
            StringBuilder builder = new StringBuilder();
951
            if (this.asGeometry) {
952
                if(this.value == VALUE_NULL){
953
                    builder.append(this.value.toString(formatter));
954
                } else {
955
                    builder.append(expression().ST_AsBinary(this.name).toString(formatter));
956
                }
957
            } else {
958
                if (this.value == null) {
959
                    builder.append(this.name.toString(formatter));
960
                } else {
961
                    builder.append(this.value.toString(formatter));
962
                }
963
            }
964
            if (this.alias != null) {
965
                builder.append(" AS ");
966
                builder.append(as_identifier(this.alias));
967
            }
968
            return builder.toString();
969
        }
970
        
971
        @Override
972
        public boolean isGeometry() {
973
            return this.asGeometry;
974
        }
975
        
976
        @Override
977
        public TableNameBuilder getTable() {
978
            return this.table;
979
        }
980
        
981
        @Override
982
        public boolean isAggregateFunction() {
983
            if( this.value == null ) {
984
                return false;
985
            }
986
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
987
                return false;
988
            }
989
            String funcname = ((ExpressionBuilder.Function)this.value).name();
990
            return this.sqlbuilder.isAggregateFunction(funcname);
991
        }
992
    }
993

    
994
    public class OrderByBuilderBase
995
            extends AbstractStatementPart
996
            implements OrderByBuilder {
997

    
998
        protected Value value;
999
        protected String custom;
1000
        protected boolean ascending;
1001
        protected int nullsMode;
1002

    
1003
        public OrderByBuilderBase() {
1004
            this.ascending = true;
1005
            this.nullsMode = MODE_NULLS_LAST;
1006
        }
1007
        
1008
        @Override
1009
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
1010
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
1011
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
1012
            return other;
1013
        }
1014
        
1015
        @Override
1016
        public void accept(Visitor visitor, VisitorFilter filter) {
1017
            boolean visitChildren = true;
1018
            if (filter==null || filter.accept(this)) {
1019
                visitor.visit(this);
1020
            } else {
1021
                visitChildren = !filter.skipChildren();
1022
            }
1023
            if(visitChildren){
1024
                if (this.value!=null) {
1025
                    this.value.accept(visitor, filter);
1026
                }
1027
            }
1028
        }
1029

    
1030
        @Override
1031
        public OrderByBuilder column(String name) {
1032
            this.value = expression().variable(name);
1033
            return this;
1034
        }
1035
        
1036
        @Override
1037
        public boolean isColumn(String name) {
1038
            if(this.value instanceof ExpressionBuilder.Variable){
1039
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1040
            }
1041
            return false;
1042
        }
1043
        
1044
        @Override
1045
        public boolean isColumn(Value value) {
1046
            if(value instanceof ExpressionBuilder.Variable){
1047
                return isColumn(((ExpressionBuilder.Variable)value).name());
1048
            }
1049
            return this.value == value;
1050
        }
1051
        
1052
        @Override
1053
        public OrderByBuilder value(Value expression) {
1054
            this.value = expression;
1055
            return this;
1056
        }
1057
        
1058
        @Override
1059
        public OrderByBuilder custom(String order) {
1060
            this.custom = order;
1061
            return this;
1062
        }
1063

    
1064
        @Override
1065
        public OrderByBuilder ascending() {
1066
            this.ascending = true;
1067
            return this;
1068
        }
1069

    
1070
        @Override
1071
        public OrderByBuilder ascending(boolean asc) {
1072
            this.ascending = asc;
1073
            return this;
1074
        }
1075

    
1076
        @Override
1077
        public OrderByBuilder descending() {
1078
            this.ascending = false;
1079
            return this;
1080
        }
1081

    
1082
        @Override
1083
        public OrderByBuilder nulls(int mode) {
1084
            this.nullsMode = mode;
1085
            return this;
1086
        }
1087

    
1088
        @Override
1089
        public int getNullsMode() {
1090
            return this.nullsMode;
1091
        }
1092

    
1093
        @Override
1094
        public String toString() {
1095
            return this.toString(formatter());
1096
        }
1097

    
1098
        @Override
1099
        public String toString(Formatter<Value> formatter) {
1100
            if (formatter!=null && formatter.canApply(this)) {
1101
                return formatter.format(this);
1102
            }
1103
            if (!StringUtils.isEmpty(this.custom)) {
1104
                return this.custom;
1105
            }
1106
            String order_s = this.value.toString(formatter);
1107
            if (this.ascending) {
1108
                order_s += " ASC";
1109
            } else {
1110
                order_s += " DESC";
1111
            }
1112
            switch(this.nullsMode) {
1113
                case MODE_NULLS_NOT_SPECIFIED:
1114
                    break;
1115
                case MODE_NULLS_FIRST:
1116
                    order_s += " NULLS FIRST";
1117
                    break;
1118
                case MODE_NULLS_LAST:
1119
                default:
1120
                    order_s += " NULLS LAST";
1121
                    break;
1122
            }
1123
            return order_s;
1124
        }
1125

    
1126
        @Override
1127
        public void replace(Value target, Value replacement) {
1128
            super.replace(target, replacement);
1129
            if(target == this.value){
1130
                this.value = replacement;
1131
                return;
1132
            }
1133
            if(this.value == null){
1134
                return;
1135
            }
1136
            this.value.replace(target, replacement);
1137
        }
1138
        
1139
        
1140
    }
1141

    
1142
    public class SelectBuilderBase
1143
            extends AbstractStatement
1144
            implements SelectBuilder {
1145

    
1146
        protected FromBuilder from;
1147
        protected GeometryExpressionBuilder where;
1148
        protected long limit = -1;
1149
        protected long offset = -1;
1150
        protected List<SelectColumnBuilder> columns;
1151
        protected List<OrderByBuilder> order_by;
1152
        protected boolean distinct;
1153
        protected List<Value> groupColumn;
1154
        protected boolean check_order_and_offset = true;
1155

    
1156
        public SelectBuilderBase() {
1157
            this.columns = new ArrayList<>();
1158
            this.distinct = false;
1159
        }
1160
        @Override
1161
        public List<Value> getGroups() {
1162
            return this.groupColumn;
1163
        }
1164
        
1165
        @Override
1166
        public List<SelectColumnBuilder> getColumns() {
1167
            return Collections.unmodifiableList(this.columns);
1168
    }
1169
        
1170
        @Override
1171
        public void remove_column(String columnName) {
1172
            SelectColumnBuilder found = null;
1173
            for (SelectColumnBuilder column : columns) {
1174
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1175
                    found = column;
1176
                    break;
1177
                }
1178
                    
1179
            }
1180
            if(found!=null) {
1181
                columns.remove(found);
1182
            }
1183
        }
1184

    
1185
        @Override
1186
        public SelectBuilder group_by(Value... columns) {
1187
            if( this.groupColumn==null ) {
1188
                this.groupColumn = new ArrayList<>();
1189
            }
1190
            for (Value column : columns) {
1191
                this.groupColumn.add(column);
1192
            }
1193
            return this;
1194
        }
1195

    
1196
        @Override
1197
        public void accept(Visitor visitor, VisitorFilter filter) {
1198
            boolean visitChildren = true;
1199
            if (filter==null || filter.accept(this)) {
1200
                visitor.visit(this);
1201
            } else {
1202
                visitChildren = !filter.skipChildren();
1203
            }
1204
            if(visitChildren){
1205
                for (SelectColumnBuilder column : columns) {
1206
                    column.accept(visitor, filter);
1207
                }
1208
                if (this.has_from()) {
1209
                    this.from.accept(visitor, filter);
1210
                }
1211
                if (this.has_where()) {
1212
                    this.where.accept(visitor, filter);
1213
                }
1214
                if (this.has_order_by()) {
1215
                    for (OrderByBuilder order : order_by) {
1216
                        order.accept(visitor, filter);
1217
                    }
1218
                }
1219
                if (this.has_group_by()) {
1220
                    for (Value group : groupColumn) {
1221
                        group.accept(visitor, filter);
1222
                    }
1223
                }
1224
            }
1225
        }
1226

    
1227
        @Override
1228
        public void replace(Value target, Value replacement) {
1229
            if( this.columns!=null ) {
1230
                for (int i = 0; i < columns.size(); i++) {
1231
                    SelectColumnBuilder column = columns.get(i);
1232
                    if( column == target ) {
1233
                        columns.set(i, (SelectColumnBuilder) replacement);
1234
                    } else {
1235
                        column.replace(target, replacement);
1236
                    }
1237
                }
1238
            }
1239
            if (this.has_from()) {
1240
                if( this.from == target ) {
1241
                    this.from = (FromBuilder) replacement;
1242
                } else {
1243
                    this.from.replace(target, replacement);
1244
                }
1245
            }
1246
            if (this.has_where()) {
1247
                if( this.where == target ) {
1248
                    this.where = (GeometryExpressionBuilder) replacement;
1249
                } else if( this.where.value() == target ) {
1250
                    this.where.value(replacement);
1251
                } else {
1252
                    this.where.value().replace(target, replacement);
1253
                }
1254
            }
1255
            if (this.has_order_by()) {
1256
                for (int i = 0; i < order_by.size(); i++) {
1257
                    OrderByBuilder order = order_by.get(i);
1258
                    if( order == target ) {
1259
                        order_by.set(i, (OrderByBuilder) replacement);
1260
                    } else {
1261
                        order.replace(target, replacement);
1262
                    }
1263
                }
1264
            }
1265
            if (this.has_group_by()) {
1266
                for (int i = 0; i < groupColumn.size(); i++) {
1267
                    Value group = groupColumn.get(i);
1268
                    if( group == target ) {
1269
                        groupColumn.set(i, replacement);
1270
                    } else {
1271
                        group.replace(target, replacement);
1272
                    }
1273
                }
1274
            }
1275
        }
1276

    
1277
        @Override
1278
        public SelectBuilder distinct() {
1279
            this.distinct = true;
1280
            return this;
1281
        }
1282

    
1283
        @Override
1284
        public SelectColumnBuilder column() {
1285
            return column(createSelectColumnBuilder());
1286
        }
1287

    
1288
        @Override
1289
        public SelectColumnBuilder column(SelectColumnBuilder columnBuilder) {
1290
            this.columns.add(columnBuilder);
1291
            if( this.has_from() && !this.from().table().isEmpty() ) {
1292
                TableNameBuilder table = (TableNameBuilder) CloneableUtils.cloneQuietly(this.from().table());
1293
                columnBuilder.table(table);
1294
            }
1295
            return columnBuilder;
1296
        }
1297

    
1298
        @Override
1299
        public SelectColumnBuilder column(String name) {
1300
            for (SelectColumnBuilder column : columns) {
1301
                if (StringUtils.equals(name, column.getName())) {
1302
                    return column;
1303
                }
1304
            }
1305
            return column(createSelectColumnBuilder()).name(name);
1306
        }
1307

    
1308
        @Override
1309
        public SelectColumnBuilder getColumn(String name) {
1310
            for (SelectColumnBuilder column : columns) {
1311
                if (StringUtils.equals(name, column.getName())) {
1312
                    return column;
1313
                }
1314
            }
1315
            return null;
1316
        }
1317
        
1318
        @Override
1319
        public SelectBuilder remove_all_columns() {
1320
            this.columns = new ArrayList<>();
1321
            return this;
1322
        }
1323
        
1324
        @Override
1325
        public boolean has_column(String name) {
1326
            for (SelectColumnBuilder column : columns) {
1327
                if (StringUtils.equals(name, column.getName())) {
1328
                    return true;
1329
                }
1330
                if (StringUtils.equals(name, column.getAlias())) {
1331
                    return true;
1332
                }
1333
            }
1334
            return false;
1335
        }
1336

    
1337
        @Override
1338
        public FromBuilder from() {
1339
            if (this.from == null) {
1340
                this.from = createFromBuilder();
1341
            }
1342
            return this.from;
1343
        }
1344

    
1345
        @Override
1346
        public boolean has_from() {
1347
            return this.from != null;
1348
        }
1349

    
1350
        @Override
1351
        public GeometryExpressionBuilder where() {
1352
            if (this.where == null) {
1353
                this.where = createExpressionBuilder();
1354
            }
1355
            return this.where;
1356
        }
1357

    
1358
        @Override
1359
        public boolean has_where() {
1360
            if (this.where == null) {
1361
                return false;
1362
            }
1363
            return this.where.value() != null;
1364
        }
1365

    
1366
        @Override
1367
        public SelectBuilder limit(long limit) {
1368
            this.limit = limit;
1369
            return this;
1370
        }
1371

    
1372
        @Override
1373
        public SelectBuilder limit(Long limit) {
1374
            if (limit == null) {
1375
                this.limit = -1;
1376
            } else {
1377
                this.limit = limit;
1378
            }
1379
            return this;
1380
        }
1381

    
1382
        @Override
1383
        public boolean has_limit() {
1384
            return this.limit >= 0;
1385
        }
1386

    
1387
        @Override
1388
        public SelectBuilder offset(long offset) {
1389
            this.offset = offset;
1390
            return this;
1391
        }
1392

    
1393
        @Override
1394
        public boolean has_offset() {
1395
            return this.offset > 0;
1396
        }
1397

    
1398
        @Override
1399
        public OrderByBuilder order_by() {
1400
            if (this.order_by == null) {
1401
                this.order_by = new ArrayList<>();
1402
            }
1403
            OrderByBuilder order = createOrderByBuilder();
1404
            this.order_by.add(order);
1405
            return order;
1406
        }
1407
        
1408
        @Override
1409
        public OrderByBuilder getOrderBy(Value column) {
1410
            if(this.order_by == null){
1411
                return null;
1412
            }
1413
            for (OrderByBuilder orderByBuilder : this.order_by) {
1414
                if(orderByBuilder.isColumn(column)){
1415
                    return orderByBuilder;
1416
                }
1417
            }
1418
            return null;
1419
        }
1420
        
1421
        @Override
1422
        public OrderByBuilder getOrderBy(String column) {
1423
            if(this.order_by == null){
1424
                return null;
1425
            }
1426
            for (OrderByBuilder orderByBuilder : this.order_by) {
1427
                if(orderByBuilder.isColumn(column)){
1428
                    return orderByBuilder;
1429
                }
1430
            }
1431
            return null;
1432
        }
1433
        
1434
        @Override
1435
        public boolean isGroupBy(String column) {
1436
            if(this.groupColumn == null){
1437
                return false;
1438
            }
1439
            for (Value group : this.groupColumn) {
1440
                if(group instanceof Variable){
1441
                    if(StringUtils.equalsIgnoreCase(((Variable)group).name(), column)){
1442
                        return true;
1443
                    }
1444
                }
1445
            }
1446
            return false;
1447
        }
1448

    
1449
        @Override
1450
        public boolean has_order_by() {
1451
            if (this.order_by == null) {
1452
                return false;
1453
            }
1454
            return !this.order_by.isEmpty();
1455
        }
1456
        
1457
        @Override
1458
        public boolean has_group_by() {
1459
            if (this.groupColumn == null) {
1460
                return false;
1461
            }
1462
            return !this.groupColumn.isEmpty();
1463
        }
1464
        
1465
        @Override
1466
        public boolean has_aggregate_functions() {
1467
            if (this.columns == null || this.columns.isEmpty() ) {
1468
                return false;
1469
            }
1470
            for (SelectColumnBuilder column : this.columns) {
1471
                if( column.isAggregateFunction() ) {
1472
                    return true;
1473
                }
1474
            }
1475
            return false;
1476
        }
1477
        
1478
        @Override
1479
        public void disable_check_order_and_offset() {
1480
          this.check_order_and_offset = false;
1481
        }
1482
        
1483
        protected boolean isValid(StringBuilder message) {
1484
            if (message == null) {
1485
                message = new StringBuilder();
1486
            }
1487
            if( this.check_order_and_offset ) {
1488
              if (this.has_offset() && !this.has_order_by()) {
1489
                  // Algunos gestores de BBDD requieren que se especifique un
1490
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1491
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1492
                  // siempre.
1493
                  message.append("Can't use OFFSET without an ORDER BY.");
1494
                  return false;
1495
              }
1496
            }
1497
            return true;
1498
        }
1499

    
1500
        @Override
1501
        public String toString() {
1502
            return this.toString(formatter());
1503
        }
1504

    
1505
        @Override
1506
        public String toString(Formatter<Value> formatter) {
1507
            if (formatter!=null && formatter.canApply(this)) {
1508
                return formatter.format(this);
1509
            }
1510
            StringBuilder builder = new StringBuilder();
1511
            if (!this.isValid(builder)) {
1512
                throw new IllegalStateException(builder.toString());
1513
            }
1514
            builder.append("SELECT ");
1515
            if (this.distinct) {
1516
                builder.append("DISTINCT ");
1517
            }
1518
            boolean first = true;
1519
            for (SelectColumnBuilder column : columns) {
1520
                if (first) {
1521
                    first = false;
1522
                } else {
1523
                    builder.append(", ");
1524
                }
1525
                builder.append(column.toString(formatter));
1526
            }
1527

    
1528
            if (this.has_from()) {
1529
                builder.append(" FROM ");
1530
                builder.append(this.from.toString(formatter));
1531
            }
1532
            if (this.has_where()) {
1533
                builder.append(" WHERE ");
1534
                builder.append(this.where.toString(formatter));
1535
            }
1536
            if( this.has_group_by() ) {
1537
                builder.append(" GROUP BY ");
1538
                builder.append(this.groupColumn.get(0).toString(formatter));
1539
                for (int i = 1; i < groupColumn.size(); i++) {
1540
                    builder.append(", ");
1541
                    builder.append(this.groupColumn.get(i).toString(formatter));
1542
                }
1543
            }
1544
            if (this.has_order_by()) {
1545
                builder.append(" ORDER BY ");
1546
                first = true;
1547
                for (OrderByBuilder item : this.order_by) {
1548
                    if (first) {
1549
                        first = false;
1550
                    } else {
1551
                        builder.append(", ");
1552
                    }
1553
                    builder.append(item.toString(formatter));
1554
                }
1555
            }
1556

    
1557
            if (this.has_limit()) {
1558
                builder.append(" LIMIT ");
1559
                builder.append(this.limit);
1560
            }
1561
            if (this.has_offset()) {
1562
                builder.append(" OFFSET ");
1563
                builder.append(this.offset);
1564
            }
1565
            return builder.toString();
1566

    
1567
        }
1568
    }
1569

    
1570
    public class DropTableBuilderBase
1571
            extends AbstractStatement
1572
            implements DropTableBuilder {
1573

    
1574
        protected TableNameBuilder table;
1575

    
1576
        @Override
1577
        public TableNameBuilder table() {
1578
            if (table == null) {
1579
                table = createTableNameBuilder();
1580
            }
1581
            return table;
1582
        }
1583

    
1584
        @Override
1585
        public void accept(Visitor visitor, VisitorFilter filter) {
1586
            boolean visitChildren = true;
1587
            if (filter==null || filter.accept(this)) {
1588
                visitor.visit(this);
1589
            } else {
1590
                visitChildren = !filter.skipChildren();
1591
            }
1592
            if(visitChildren){
1593
                this.table.accept(visitor, filter);
1594
            }
1595
        }
1596

    
1597
        @Override
1598
        public String toString() {
1599
            return this.toString(formatter());
1600
        }
1601

    
1602
        @Override
1603
        public String toString(Formatter<Value> formatter) {
1604
            if (formatter!=null && formatter.canApply(this)) {
1605
                return formatter.format(this);
1606
            }
1607
            StringBuilder builder = new StringBuilder();
1608
            boolean first = true;
1609
            for (String sql : toStrings(formatter)) {
1610
                if (StringUtils.isEmpty(sql)) {
1611
                    continue;
1612
                }
1613
                if (first) {
1614
                    first = false;
1615
                } else {
1616
                    builder.append("; ");
1617
                }
1618
                builder.append(sql);
1619
            }
1620
            return builder.toString();
1621
        }
1622

    
1623
        @Override
1624
        public List<String> toStrings() {
1625
            return this.toStrings(formatter());
1626
        }
1627

    
1628
        @Override
1629
        public List<String> toStrings(Formatter formatter) {
1630
            List<String> sqls = new ArrayList<>();
1631

    
1632
            sqls.add(
1633
                    MessageFormat.format(
1634
                            STMT_DROP_TABLE_table,
1635
                            this.table.toString(formatter)
1636
                    )
1637
            );
1638
            String sql;
1639
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1640
                if (this.table.has_schema()) {
1641
                    sql = MessageFormat.format(
1642
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1643
                            as_string(this.table.getSchema()),
1644
                            as_string(this.table.getName())
1645
                    );
1646
                } else {
1647
                    sql = MessageFormat.format(
1648
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1649
                            as_identifier(this.table.getName())
1650
                    );
1651
                }
1652
                if (!StringUtils.isEmpty(sql)) {
1653
                    sqls.add(sql);
1654
                }
1655
            }
1656
            return sqls;
1657
        }
1658
    }
1659

    
1660
    public class GrantRoleBuilderBase
1661
            extends AbstractStatementPart
1662
            implements GrantRoleBuilder {
1663

    
1664
        protected TableNameBuilder table;
1665
        protected String role;
1666
        protected Set<Privilege> privileges;
1667

    
1668
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1669
            this.table = table;
1670
            this.role = role;
1671
            this.privileges = new HashSet<>();
1672
        }
1673
        
1674
        @Override
1675
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1676
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1677
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1678
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1679
            
1680
            return other;
1681
        }
1682

    
1683
        @Override
1684
        public GrantRoleBuilder privilege(Privilege privilege) {
1685
            privileges.add(privilege);
1686
            return this;
1687
        }
1688

    
1689
        @Override
1690
        public GrantRoleBuilder select() {
1691
            privileges.add(Privilege.SELECT);
1692
            return this;
1693
        }
1694

    
1695
        @Override
1696
        public GrantRoleBuilder update() {
1697
            privileges.add(Privilege.UPDATE);
1698
            return this;
1699
        }
1700

    
1701
        @Override
1702
        public GrantRoleBuilder insert() {
1703
            privileges.add(Privilege.INSERT);
1704
            return this;
1705
        }
1706

    
1707
        @Override
1708
        public GrantRoleBuilder delete() {
1709
            privileges.add(Privilege.DELETE);
1710
            return this;
1711
        }
1712

    
1713
        @Override
1714
        public GrantRoleBuilder truncate() {
1715
            privileges.add(Privilege.TRUNCATE);
1716
            return this;
1717
        }
1718

    
1719
        @Override
1720
        public GrantRoleBuilder reference() {
1721
            privileges.add(Privilege.REFERENCE);
1722
            return this;
1723
        }
1724

    
1725
        @Override
1726
        public GrantRoleBuilder trigger() {
1727
            privileges.add(Privilege.TRIGGER);
1728
            return this;
1729
        }
1730

    
1731
        @Override
1732
        public GrantRoleBuilder all() {
1733
            privileges.add(Privilege.ALL);
1734
            return this;
1735
        }
1736

    
1737
        protected String getPrivilegeName(Privilege privilege) {
1738
            switch (privilege) {
1739
                case DELETE:
1740
                    return "DELETE";
1741
                case INSERT:
1742
                    return "INSERT";
1743
                case REFERENCE:
1744
                    return "REFERENCE";
1745
                case SELECT:
1746
                    return "SELECT";
1747
                case TRIGGER:
1748
                    return "TRIGGER";
1749
                case TRUNCATE:
1750
                    return "TRUNCATE";
1751
                case UPDATE:
1752
                    return "UPDATE";
1753
                case ALL:
1754
                default:
1755
                    return "ALL";
1756
            }
1757
        }
1758

    
1759
        @Override
1760
        public String toString() {
1761
            return this.toString(formatter());
1762
        }
1763

    
1764
        @Override
1765
        public String toString(Formatter<Value> formatter) {
1766
            if (formatter!=null && formatter.canApply(this)) {
1767
                return formatter.format(this);
1768
            }
1769
            StringBuilder builder = new StringBuilder();
1770
            boolean first = true;
1771
            for (Privilege privilege : privileges) {
1772
                if (first) {
1773
                    first = false;
1774
                } else {
1775
                    builder.append(", ");
1776
                }
1777
                builder.append(this.getPrivilegeName(privilege));
1778
            }
1779
            String sql = MessageFormat.format(
1780
                    STMT_GRANT_privileges_ON_table_TO_role,
1781
                    builder.toString(),
1782
                    table.toString(formatter),
1783
                    role
1784
            );
1785
            return sql;
1786
        }
1787
    }
1788

    
1789
    public class GrantBuilderBase
1790
            extends AbstractStatement
1791
            implements GrantBuilder {
1792

    
1793
        protected TableNameBuilder table;
1794
        protected Map<String, GrantRoleBuilder> roles;
1795

    
1796
        public GrantBuilderBase() {
1797
            this.roles = new HashMap<>();
1798
        }
1799

    
1800
        @Override
1801
        public TableNameBuilder table() {
1802
            if (table == null) {
1803
                table = createTableNameBuilder();
1804
            }
1805
            return table;
1806
        }
1807

    
1808
        @Override
1809
        public void accept(Visitor visitor, VisitorFilter filter) {
1810
            boolean visitChildren = true;
1811
            if (filter==null || filter.accept(this)) {
1812
                visitor.visit(this);
1813
            } else {
1814
                visitChildren = !filter.skipChildren();
1815
            }
1816
            if(visitChildren){
1817
                if (this.table != null) {
1818
                    this.table.accept(visitor, filter);
1819
                }
1820
            }
1821
        }
1822

    
1823
        @Override
1824
        public GrantRoleBuilder role(String role) {
1825
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1826
            if (roleBuilder == null) {
1827
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1828
                this.roles.put(role, roleBuilder);
1829
            }
1830
            return roleBuilder;
1831
        }
1832

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

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

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

    
1864
        @Override
1865
        public List<String> toStrings(Formatter formatter) {
1866
            List<String> sqls = new ArrayList<>();
1867
            for (GrantRoleBuilder role : roles.values()) {
1868
                sqls.add(role.toString(formatter));
1869
            }
1870
            return sqls;
1871
        }
1872
    }
1873

    
1874
    public class UpdateColumnBuilderBase
1875
            extends InsertColumnBuilderBase
1876
            implements UpdateColumnBuilder {
1877

    
1878
        public UpdateColumnBuilderBase() {
1879
            super();
1880
        }
1881

    
1882
        @Override
1883
        public UpdateColumnBuilder name(String name) {
1884
            return (UpdateColumnBuilder) super.name(name);
1885
        }
1886

    
1887
        @Override
1888
        public UpdateColumnBuilder with_value(Value value) {
1889
            return (UpdateColumnBuilder) super.with_value(value);
1890
        }
1891

    
1892
    }
1893

    
1894
    public class UpdateBuilderBase
1895
            extends AbstractStatement
1896
            implements UpdateBuilder {
1897

    
1898
        protected GeometryExpressionBuilder where;
1899
        protected List<UpdateColumnBuilder> columns;
1900
        protected TableNameBuilder table;
1901

    
1902
        public UpdateBuilderBase() {
1903
            this.columns = new ArrayList<>();
1904
        }
1905

    
1906
        @Override
1907
        public void accept(Visitor visitor, VisitorFilter filter) {
1908
            boolean visitChildren = true;
1909
            if (filter==null || filter.accept(this)) {
1910
                visitor.visit(this);
1911
            } else {
1912
                visitChildren = !filter.skipChildren();
1913
            }
1914
            if(visitChildren){
1915
                if (this.table != null) {
1916
                    this.table.accept(visitor, filter);
1917
                }
1918
                for (UpdateColumnBuilder column : columns) {
1919
                    column.accept(visitor, filter);
1920
                }
1921
                if (this.has_where()) {
1922
                    this.where.accept(visitor, filter);
1923
                }
1924
            }
1925
        }
1926

    
1927
        @Override
1928
        public GeometryExpressionBuilder where() {
1929
            if (this.where == null) {
1930
                this.where = createExpressionBuilder();
1931
            }
1932
            return this.where;
1933
        }
1934

    
1935
        @Override
1936
        public TableNameBuilder table() {
1937
            if (table == null) {
1938
                table = createTableNameBuilder();
1939
            }
1940
            return table;
1941
        }
1942

    
1943
        @Override
1944
        public UpdateColumnBuilder column() {
1945
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1946
            this.columns.add(column);
1947
            return column;
1948
        }
1949

    
1950
        @Override
1951
        public boolean has_where() {
1952
            return this.where != null;
1953
        }
1954

    
1955
        @Override
1956
        public String toString() {
1957
            return this.toString(formatter());
1958
        }
1959

    
1960
        @Override
1961
        public String toString(Formatter<Value> formatter) {
1962
            if (formatter!=null && formatter.canApply(this)) {
1963
                return formatter.format(this);
1964
            }
1965
            /*
1966
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1967
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1968
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1969
             * output_expression [ AS output_name ] [, ...] ]
1970
             */
1971
            StringBuilder columnsAndValues = new StringBuilder();
1972

    
1973
            boolean first = true;
1974
            for (UpdateColumnBuilder column : columns) {
1975
                if (first) {
1976
                    first = false;
1977
                } else {
1978
                    columnsAndValues.append(", ");
1979
                }
1980
                columnsAndValues.append(as_identifier(column.getName()));
1981
                columnsAndValues.append(" = ");
1982
                columnsAndValues.append(column.getValue().toString(formatter));
1983
            }
1984

    
1985
            String sql;
1986
            if (this.has_where()) {
1987
                sql = MessageFormat.format(
1988
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1989
                        this.table.toString(formatter),
1990
                        columnsAndValues.toString(),
1991
                        this.where.toString(formatter)
1992
                );
1993
            } else {
1994
                sql = MessageFormat.format(
1995
                        STMT_UPDATE_table_SET_columnsAndValues,
1996
                        this.table.toString(formatter),
1997
                        columnsAndValues.toString()
1998
                );
1999
            }
2000
            return sql;
2001
        }
2002
    }
2003

    
2004
    public class DeleteBuilderBase
2005
            extends AbstractStatement
2006
            implements DeleteBuilder {
2007

    
2008
        protected GeometryExpressionBuilder where;
2009
        protected TableNameBuilder table;
2010

    
2011
        public DeleteBuilderBase() {
2012
        }
2013

    
2014
        @Override
2015
        public void accept(Visitor visitor, VisitorFilter filter) {
2016
            boolean visitChildren = true;
2017
            if (filter==null || filter.accept(this)) {
2018
                visitor.visit(this);
2019
            } else {
2020
                visitChildren = !filter.skipChildren();
2021
            }
2022
            if(visitChildren){
2023
                if (this.table != null) {
2024
                    this.table.accept(visitor, filter);
2025
                }
2026
                if (this.has_where()) {
2027
                    this.where.accept(visitor, filter);
2028
                }
2029
            }
2030
        }
2031

    
2032
        @Override
2033
        public GeometryExpressionBuilder where() {
2034
            if (this.where == null) {
2035
                this.where = createExpressionBuilder();
2036
            }
2037
            return this.where;
2038
        }
2039

    
2040
        @Override
2041
        public TableNameBuilder table() {
2042
            if (table == null) {
2043
                table = createTableNameBuilder();
2044
            }
2045
            return table;
2046
        }
2047

    
2048
        @Override
2049
        public boolean has_where() {
2050
            return this.where != null;
2051
        }
2052

    
2053
        @Override
2054
        public String toString() {
2055
            return this.toString(formatter());
2056
        }
2057

    
2058
        @Override
2059
        public String toString(Formatter<Value> formatter) {
2060
            if (formatter!=null && formatter.canApply(this)) {
2061
                return formatter.format(this);
2062
            }
2063
            /*
2064
             * DELETE FROM table_name
2065
             * WHERE some_column=some_value; 
2066
             */
2067
            String sql;
2068
            if (this.has_where()) {
2069
                sql = MessageFormat.format(
2070
                        STMT_DELETE_FROM_table_WHERE_expresion,
2071
                        this.table.toString(formatter),
2072
                        this.where.toString(formatter)
2073
                );
2074
            } else {
2075
                sql = MessageFormat.format(
2076
                        STMT_DELETE_FROM_table,
2077
                        this.table.toString(formatter)
2078
                );
2079
            }
2080
            return sql;
2081
        }
2082
    }
2083

    
2084
    public class CreateIndexBuilderBase
2085
            extends AbstractStatement
2086
            implements CreateIndexBuilder {
2087

    
2088
        protected boolean ifNotExist = false;
2089
        protected boolean isUnique = false;
2090
        protected String indexName;
2091
        protected boolean isSpatial = false;
2092
        protected TableNameBuilder table;
2093
        protected final List<String> columns;
2094

    
2095
        public CreateIndexBuilderBase() {
2096
            this.columns = new ArrayList<>();
2097
        }
2098

    
2099
        @Override
2100
        public CreateIndexBuilder unique() {
2101
            this.isUnique = true;
2102
            return this;
2103
        }
2104

    
2105
        @Override
2106
        public CreateIndexBuilder if_not_exist() {
2107
            this.ifNotExist = true;
2108
            return this;
2109
        }
2110

    
2111
        @Override
2112
        public CreateIndexBuilder name(String name) {
2113
            this.indexName = name;
2114
            return this;
2115
        }
2116

    
2117
        @Override
2118
        public CreateIndexBuilder name(String tableName, String columnName) {
2119
            this.indexName = tableName + "_IDX_" + columnName;
2120
            return this;
2121
        }
2122

    
2123
        @Override
2124
        public CreateIndexBuilder spatial() {
2125
            this.isSpatial = true;
2126
            return this;
2127
        }
2128

    
2129
        @Override
2130
        public CreateIndexBuilder column(String name) {
2131
            this.columns.add(name);
2132
            return this;
2133
        }
2134

    
2135
        @Override
2136
        public TableNameBuilder table() {
2137
            if (table == null) {
2138
                table = createTableNameBuilder();
2139
            }
2140
            return table;
2141
        }
2142

    
2143
        @Override
2144
        public void accept(Visitor visitor, VisitorFilter filter) {
2145
            boolean visitChildren = true;
2146
            if (filter==null || filter.accept(this)) {
2147
                visitor.visit(this);
2148
            } else {
2149
                visitChildren = !filter.skipChildren();
2150
            }
2151
            if(visitChildren){
2152
                if (this.table != null) {
2153
                    this.table.accept(visitor, filter);
2154
                }
2155
            }
2156
        }
2157

    
2158
        @Override
2159
        public String toString() {
2160
            return this.toString(formatter());
2161
        }
2162

    
2163
        @Override
2164
        public String toString(Formatter<Value> formatter) {
2165
            if (formatter!=null && formatter.canApply(this)) {
2166
                return formatter.format(this);
2167
            }
2168
            StringBuilder builder = new StringBuilder();
2169
            boolean first = true;
2170
            for (String sql : toStrings(formatter)) {
2171
                if (StringUtils.isEmpty(sql)) {
2172
                    continue;
2173
                }
2174
                if (first) {
2175
                    first = false;
2176
                } else {
2177
                    builder.append("; ");
2178
                }
2179
                builder.append(sql);
2180
            }
2181
            return builder.toString();
2182
        }
2183

    
2184
        @Override
2185
        public List<String> toStrings() {
2186
            return this.toStrings(formatter());
2187
        }
2188

    
2189
        @Override
2190
        public List<String> toStrings(Formatter formatter) {
2191
            StringBuilder builder = new StringBuilder();
2192
            builder.append("CREATE ");
2193
            if (this.isUnique) {
2194
                builder.append("UNIQUE ");
2195
            }
2196
            builder.append("INDEX ");
2197
            if (this.ifNotExist) {
2198
                builder.append("IF NOT EXISTS ");
2199
            }
2200
            builder.append(as_identifier(this.indexName));
2201
            builder.append(" ON ");
2202
            builder.append(this.table.toString(formatter));
2203
            if (this.isSpatial) {
2204
                builder.append(" USING GIST ");
2205
            }
2206
            builder.append(" ( ");
2207
            boolean is_first_column = true;
2208
            for (String column : this.columns) {
2209
                if (is_first_column) {
2210
                    is_first_column = false;
2211
                } else {
2212
                    builder.append(", ");
2213
                }
2214
                builder.append(column);
2215
            }
2216
            builder.append(" )");
2217

    
2218
            List<String> sqls = new ArrayList<>();
2219
            sqls.add(builder.toString());
2220
            return sqls;
2221
        }
2222

    
2223
    }
2224

    
2225
    public class DropIndexBuilderBase
2226
            extends AbstractStatement
2227
            implements DropIndexBuilder {
2228

    
2229
        protected boolean ifNotExist = false;
2230
        protected String indexName;
2231

    
2232
        public DropIndexBuilderBase() {
2233
        }
2234

    
2235
        @Override
2236
        public DropIndexBuilder if_not_exist() {
2237
            this.ifNotExist = true;
2238
            return this;
2239
        }
2240

    
2241
        @Override
2242
        public DropIndexBuilder name(String name) {
2243
            this.indexName = name;
2244
            return this;
2245
        }
2246

    
2247
        @Override
2248
        public DropIndexBuilder name(String tableName, String columnName) {
2249
            this.indexName = tableName + "_IDX_" + columnName;
2250
            return this;
2251
        }
2252

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

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

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

    
2284
        @Override
2285
        public List<String> toStrings(Formatter formatter) {
2286
            StringBuilder builder = new StringBuilder();
2287
            builder.append("DROP INDEX ");
2288
            if (this.ifNotExist) {
2289
                builder.append("IF NOT EXISTS ");
2290
            }
2291
            builder.append(as_identifier(this.indexName));
2292
            List<String> sqls = new ArrayList<>();
2293
            sqls.add(builder.toString());
2294
            return sqls;
2295
        }
2296

    
2297
    }
2298

    
2299
    public class AlterTableBuilderBase
2300
            extends AbstractStatement
2301
            implements AlterTableBuilder {
2302

    
2303
        protected TableNameBuilder table;
2304
        protected List<String> drops;
2305
        protected List<ColumnDescriptor> adds;
2306
        protected List<ColumnDescriptor> alters;
2307
        protected List<Pair<String, String>> renames;
2308
        protected String drop_primary_key_column;
2309

    
2310
        public AlterTableBuilderBase() {
2311
            this.drops = new ArrayList<>();
2312
            this.adds = new ArrayList<>();
2313
            this.alters = new ArrayList<>();
2314
            this.renames = new ArrayList<>();
2315
        }
2316

    
2317
        @Override
2318
        public boolean isEmpty() {
2319
            return this.drops.isEmpty()
2320
                    && this.adds.isEmpty()
2321
                    && this.alters.isEmpty()
2322
                    && this.renames.isEmpty();
2323
        }
2324

    
2325
        @Override
2326
        public void accept(Visitor visitor, VisitorFilter filter) {
2327
            boolean visitChildren = true;
2328
            if (filter==null || filter.accept(this)) {
2329
                visitor.visit(this);
2330
            } else {
2331
                visitChildren = !filter.skipChildren();
2332
            }
2333
            if(visitChildren){
2334
                if (this.table != null) {
2335
                    this.table.accept(visitor, filter);
2336
                }
2337
            }
2338
        }
2339

    
2340
        @Override
2341
        public TableNameBuilder table() {
2342
            if (table == null) {
2343
                table = createTableNameBuilder();
2344
            }
2345
            return table;
2346
        }
2347

    
2348
        @Override
2349
        public AlterTableBuilder drop_column(String columnName) {
2350
            this.drops.add(columnName);
2351
            return this;
2352
        }
2353

    
2354
        @Override
2355
        public AlterTableBuilder drop_primary_key(String columnName) {
2356
            this.drop_primary_key_column = columnName;
2357
            return this;
2358
        }
2359

    
2360
        @Override
2361
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2362
            this.adds.add(new ColumnDescriptorBase(fad));
2363
            return this;
2364
        }
2365

    
2366
        @Override
2367
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2368
            if (isPk || isAutomatic) {
2369
                allowNulls = false;
2370
            }
2371
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2372
            return this;
2373
        }
2374

    
2375
        @Override
2376
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2377
            if (StringUtils.isEmpty(columnName)) {
2378
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2379
            }
2380
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2381
            return this;
2382
        }
2383

    
2384
        @Override
2385
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2386
            if (StringUtils.isEmpty(columnName)) {
2387
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2388
            }
2389
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2390
            return this;
2391
        }
2392

    
2393
        @Override
2394
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2395
            this.alters.add(new ColumnDescriptorBase(fad));
2396
            return this;
2397
        }
2398

    
2399
        @Override
2400
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2401
            if (isPk || isAutomatic) {
2402
                allowNulls = false;
2403
            }
2404
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2405
            return this;
2406
        }
2407

    
2408
        @Override
2409
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2410
            if (StringUtils.isEmpty(columnName)) {
2411
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2412
            }
2413
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2414
            return this;
2415
        }
2416

    
2417
        @Override
2418
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2419
            if (StringUtils.isEmpty(columnName)) {
2420
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2421
            }
2422
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2423
            return this;
2424
        }
2425

    
2426
        @Override
2427
        public AlterTableBuilder rename_column(String source, String target) {
2428
            this.renames.add(new ImmutablePair(source, target));
2429
            return this;
2430
        }
2431

    
2432
        protected String getConstrainName(String constrainType, String columnName) {
2433
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2434
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2435
            return constraint_name;
2436
        }
2437

    
2438
        @Override
2439
        public String toString() {
2440
            return this.toString(formatter());
2441
        }
2442

    
2443
        @Override
2444
        public String toString(Formatter<Value> formatter) {
2445
            if (formatter!=null && formatter.canApply(this)) {
2446
                return formatter.format(this);
2447
            }
2448
            StringBuilder builder = new StringBuilder();
2449
            boolean first = true;
2450
            for (String sql : toStrings(formatter)) {
2451
                if (StringUtils.isEmpty(sql)) {
2452
                    continue;
2453
                }
2454
                if (first) {
2455
                    first = false;
2456
                } else {
2457
                    builder.append("; ");
2458
                }
2459
                builder.append(sql);
2460
            }
2461
            return builder.toString();
2462
        }
2463

    
2464
        @Override
2465
        public List<String> toStrings() {
2466
            return this.toStrings(formatter());
2467
        }
2468

    
2469
        @Override
2470
        public List<String> toStrings(Formatter formatter) {
2471
            List<String> sqls = new ArrayList<>();
2472
            if (this.isEmpty()) {
2473
                return sqls;
2474
            }
2475
            for (String column : drops) {
2476
                StringBuilder builder = new StringBuilder();
2477
                builder.append("ALTER TABLE ");
2478
                builder.append(this.table.toString(formatter));
2479
                builder.append(" DROP COLUMN IF EXISTS ");
2480
                builder.append(as_identifier(column));
2481
                sqls.add(builder.toString());
2482
            }
2483
            for (ColumnDescriptor column : adds) {
2484
                StringBuilder builder = new StringBuilder();
2485
                builder.append("ALTER TABLE ");
2486
                builder.append(this.table.toString(formatter));
2487
                builder.append(" ADD COLUMN ");
2488
                builder.append(as_identifier(column.getName()));
2489
                builder.append(" ");
2490
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2491
                    builder.append(" SERIAL");
2492
                } else {
2493
                    builder.append(
2494
                            sqltype(
2495
                                    column.getType(),
2496
                                    column.getSize(),
2497
                                    column.getPrecision(),
2498
                                    column.getScale(),
2499
                                    column.getGeometryType(),
2500
                                    column.getGeometrySubtype()
2501
                            )
2502
                    );
2503
                }
2504
                if (column.getDefaultValue() == null) {
2505
                    if (column.allowNulls()) {
2506
                        builder.append(" DEFAULT NULL");
2507
                    }
2508
                } else {
2509
                    builder.append(" DEFAULT '");
2510
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2511
                    builder.append("'");
2512
                }
2513
                if (column.allowNulls()) {
2514
                    builder.append(" NULL");
2515
                } else {
2516
                    builder.append(" NOT NULL");
2517
                }
2518
                if (column.isPrimaryKey()) {
2519
                    builder.append(" PRIMARY KEY");
2520
                }
2521
                sqls.add(builder.toString());
2522
            }
2523
            for (ColumnDescriptor column : alters) {
2524
                StringBuilder builder = new StringBuilder();
2525
                builder.append("ALTER TABLE ");
2526
                builder.append(this.table.toString(formatter));
2527
                builder.append(" ALTER COLUMN ");
2528
                builder.append(as_identifier(column.getName()));
2529
                builder.append(" SET DATA TYPE ");
2530
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2531
                    builder.append(" SERIAL");
2532
                } else {
2533
                    builder.append(
2534
                            sqltype(
2535
                                    column.getType(),
2536
                                    column.getSize(),
2537
                                    column.getPrecision(),
2538
                                    column.getScale(),
2539
                                    column.getGeometryType(),
2540
                                    column.getGeometrySubtype()
2541
                            )
2542
                    );
2543
                }
2544
                if (column.getDefaultValue() == null) {
2545
                    if (column.allowNulls()) {
2546
                        builder.append(" DEFAULT NULL");
2547
                    } else {
2548
                        builder.append(" DROP DEFAULT");
2549
                    }
2550
                } else {
2551
                    builder.append(" DEFAULT '");
2552
                    builder.append(column.getDefaultValue().toString());
2553
                    builder.append("'");
2554
                }
2555
                sqls.add(builder.toString());
2556
            }
2557
            for (Pair<String, String> pair : renames) {
2558
                StringBuilder builder = new StringBuilder();
2559
                builder.append("ALTER TABLE ");
2560
                builder.append(this.table.toString(formatter));
2561
                builder.append(" RENAME COLUMN ");
2562
                builder.append(as_identifier(pair.getLeft()));
2563
                builder.append(" TO ");
2564
                builder.append(as_identifier(pair.getRight()));
2565
                sqls.add(builder.toString());
2566
            }
2567
            return sqls;
2568
        }
2569

    
2570
    }
2571

    
2572
    public class CreateTableBuilderBase
2573
            extends AbstractStatement
2574
            implements CreateTableBuilder {
2575

    
2576
        protected TableNameBuilder table;
2577
        protected List<ColumnDescriptor> columns;
2578

    
2579
        public CreateTableBuilderBase() {
2580
            this.columns = new ArrayList<>();
2581
        }
2582

    
2583
        @Override
2584
        public void accept(Visitor visitor, VisitorFilter filter) {
2585
            boolean visitChildren = true;
2586
            if (filter==null || filter.accept(this)) {
2587
                visitor.visit(this);
2588
            } else {
2589
                visitChildren = !filter.skipChildren();
2590
            }
2591
            if(visitChildren){
2592
                if (this.table != null) {
2593
                    this.table.accept(visitor, filter);
2594
                }
2595
            }
2596
        }
2597

    
2598
        @Override
2599
        public TableNameBuilder table() {
2600
            if (table == null) {
2601
                table = createTableNameBuilder();
2602
            }
2603
            return table;
2604
        }
2605

    
2606
        @Override
2607
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2608
            this.columns.add(new ColumnDescriptorBase(fad));
2609
            return this;
2610
        }
2611

    
2612
        @Override
2613
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2614
            if (StringUtils.isEmpty(columnName)) {
2615
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2616
            }
2617
            if (isPk || isAutomatic) {
2618
                allowNulls = false;
2619
            }
2620
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2621
            return this;
2622
        }
2623

    
2624
        @Override
2625
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2626
            if (StringUtils.isEmpty(columnName)) {
2627
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2628
            }
2629
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2630
            return this;
2631
        }
2632

    
2633
        @Override
2634
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2635
            if (StringUtils.isEmpty(columnName)) {
2636
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2637
            }
2638
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2639
            return this;
2640
        }
2641

    
2642
        @Override
2643
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2644
            if (StringUtils.isEmpty(columnName)) {
2645
                return null;
2646
            }
2647
            for (ColumnDescriptor column : columns) {
2648
                if (columnName.equals(column.getName())) {
2649
                    return column;
2650
                }
2651
            }
2652
            return null;
2653
        }
2654

    
2655
        @Override
2656
        public String toString() {
2657
            return this.toString(formatter());
2658
        }
2659

    
2660
        @Override
2661
        public String toString(Formatter<Value> formatter) {
2662
            if (formatter!=null && formatter.canApply(this)) {
2663
                return formatter.format(this);
2664
            }
2665
            StringBuilder builder = new StringBuilder();
2666
            boolean first = true;
2667
            for (String sql : toStrings(formatter)) {
2668
                if (StringUtils.isEmpty(sql)) {
2669
                    continue;
2670
                }
2671
                if (first) {
2672
                    first = false;
2673
                } else {
2674
                    builder.append("; ");
2675
                }
2676
                builder.append(sql);
2677
            }
2678
            return builder.toString();
2679
        }
2680

    
2681
        @Override
2682
        public List<String> toStrings() {
2683
            return this.toStrings(formatter());
2684
        }
2685

    
2686
        @Override
2687
        /*
2688
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
2689
        */
2690
        public List<String> toStrings(Formatter formatter) {
2691
            List<String> sqls = new ArrayList<>();
2692
            /**
2693
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2694
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2695
             * column_constraint [ ... ] ] | table_constraint | LIKE
2696
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2697
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2698
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2699
             *
2700
             * where column_constraint is:
2701
             *
2702
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2703
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2704
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2705
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2706
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2707
             *
2708
             * and table_constraint is:
2709
             *
2710
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2711
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2712
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2713
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2714
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2715
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2716
             */
2717
            
2718
            StringBuilder builder = new StringBuilder();
2719

    
2720
            builder.append("CREATE TABLE ");
2721
            builder.append(this.table.toString(formatter));
2722
            builder.append(" (");
2723
            boolean first = true;
2724
            for (ColumnDescriptor column : columns) {
2725
                if (first) {
2726
                    first = false;
2727
                } else {
2728
                    builder.append(", ");
2729
                }
2730
                builder.append(as_identifier(column.getName()));
2731
                builder.append(" ");
2732
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2733
                    builder.append("SERIAL");
2734
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2735
                    builder.append("BIGSERIAL");
2736
                } else {
2737
                    builder.append(sqltype(
2738
                            column.getType(),
2739
                            column.getSize(),
2740
                            column.getPrecision(),
2741
                            column.getScale(),
2742
                            column.getGeometryType(),
2743
                            column.getGeometrySubtype()
2744
                    )
2745
                    );
2746
                }
2747
                if (column.getDefaultValue() == null) {
2748
                    if (column.allowNulls()) {
2749
                        builder.append(" DEFAULT NULL");
2750
                    }
2751
                } else {
2752
                    builder.append(" DEFAULT '");
2753
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2754
                    builder.append("'");
2755
                }
2756
                if (column.allowNulls()) {
2757
                    builder.append(" NULL");
2758
                } else {
2759
                    builder.append(" NOT NULL");
2760
                }
2761
                if (column.isPrimaryKey()) {
2762
                    builder.append(" PRIMARY KEY");
2763
                }
2764
            }
2765
            builder.append(" )");
2766
            sqls.add(builder.toString());
2767
            return sqls;
2768
        }
2769
    }
2770

    
2771
    public class InsertColumnBuilderBase
2772
            extends AbstractStatement
2773
            implements InsertColumnBuilder {
2774

    
2775
        protected Variable name;
2776
        protected Value value;
2777

    
2778
        public InsertColumnBuilderBase() {
2779
        }
2780

    
2781
        @Override
2782
        public void accept(Visitor visitor, VisitorFilter filter) {
2783
            boolean visitChildren = true;
2784
            if (filter==null || filter.accept(this)) {
2785
                visitor.visit(this);
2786
            } else {
2787
                visitChildren = !filter.skipChildren();
2788
            }
2789
            if(visitChildren){
2790
                if (this.name != null) {
2791
                    this.name.accept(visitor, filter);
2792
                }
2793
                if (this.value != null) {
2794
                    this.value.accept(visitor, filter);
2795
                }
2796
            }
2797
        }
2798

    
2799
        @Override
2800
        public InsertColumnBuilder name(String name) {
2801
            this.name = expression().variable(name);
2802
            return this;
2803
        }
2804

    
2805
        @Override
2806
        public InsertColumnBuilder with_value(Value value) {
2807
            this.value = value;
2808
            return this;
2809
        }
2810

    
2811
        @Override
2812
        public String getName() {
2813
            return this.name.name();
2814
        }
2815

    
2816
        @Override
2817
        public Value getValue() {
2818
            return this.value;
2819
        }
2820

    
2821
        @Override
2822
        public String toString() {
2823
            return this.toString(formatter());
2824
        }
2825

    
2826
        @Override
2827
        public String toString(Formatter<Value> formatter) {
2828
            if (formatter!=null && formatter.canApply(this)) {
2829
                return formatter.format(this);
2830
            }
2831
            return this.value.toString(formatter);
2832
        }
2833
    }
2834

    
2835
    public class InsertBuilderBase
2836
            extends AbstractStatement
2837
            implements InsertBuilder {
2838

    
2839
        protected List<InsertColumnBuilder> columns;
2840
        protected TableNameBuilder table;
2841

    
2842
        public InsertBuilderBase() {
2843
            this.columns = new ArrayList<>();
2844
        }
2845

    
2846
        @Override
2847
        public void accept(Visitor visitor, VisitorFilter filter) {
2848
            boolean visitChildren = true;
2849
            if (filter==null || filter.accept(this)) {
2850
                visitor.visit(this);
2851
            } else {
2852
                visitChildren = !filter.skipChildren();
2853
            }
2854
            if(visitChildren){
2855
                if (this.table != null) {
2856
                    this.table.accept(visitor, filter);
2857
                }
2858
                for (InsertColumnBuilder column : columns) {
2859
                    column.accept(visitor, filter);
2860
                }
2861
            }
2862
        }
2863

    
2864
        @Override
2865
        public TableNameBuilder table() {
2866
            if (table == null) {
2867
                table = createTableNameBuilder();
2868
            }
2869
            return table;
2870
        }
2871

    
2872
        @Override
2873
        public InsertColumnBuilder column() {
2874
            InsertColumnBuilder column = createInsertColumnBuilder();
2875
            this.columns.add(column);
2876
            return column;
2877
        }
2878

    
2879
        @Override
2880
        public String toString() {
2881
            return this.toString(formatter());
2882
        }
2883

    
2884
        @Override
2885
        public String toString(Formatter<Value> formatter) {
2886
            if (formatter!=null && formatter.canApply(this)) {
2887
                return formatter.format(this);
2888
            }
2889
            /*
2890
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2891
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2892
             * output_expression [ AS output_name ] [, ...] ]
2893
             */
2894
            StringBuilder builderColumns = new StringBuilder();
2895
            StringBuilder builderValues = new StringBuilder();
2896

    
2897
            boolean first = true;
2898
            for (InsertColumnBuilder column : columns) {
2899
                if (first) {
2900
                    first = false;
2901
                } else {
2902
                    builderColumns.append(", ");
2903
                }
2904
                builderColumns.append(as_identifier(column.getName()));
2905
            }
2906
            first = true;
2907
            for (InsertColumnBuilder column : columns) {
2908
                if (first) {
2909
                    first = false;
2910
                } else {
2911
                    builderValues.append(", ");
2912
                }
2913
                builderValues.append(column.toString(formatter));
2914
            }
2915

    
2916
            String sql = MessageFormat.format(
2917
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2918
                    this.table.toString(formatter),
2919
                    builderColumns.toString(),
2920
                    builderValues.toString()
2921
            );
2922
            return sql;
2923

    
2924
        }
2925
    }
2926

    
2927
    public class UpdateTableStatisticsBuilderBase
2928
            extends AbstractStatement
2929
            implements UpdateTableStatisticsBuilder {
2930

    
2931
        protected TableNameBuilder table;
2932

    
2933
        @Override
2934
        public void accept(Visitor visitor, VisitorFilter filter) {
2935
            boolean visitChildren = true;
2936
            if (filter==null || filter.accept(this)) {
2937
                visitor.visit(this);
2938
            } else {
2939
                visitChildren = !filter.skipChildren();
2940
            }
2941
            if(visitChildren){
2942
                if (this.table != null) {
2943
                    this.table.accept(visitor, filter);
2944
                }
2945
            }
2946
        }
2947

    
2948
        @Override
2949
        public TableNameBuilder table() {
2950
            if (table == null) {
2951
                table = createTableNameBuilder();
2952
            }
2953
            return table;
2954
        }
2955

    
2956
        @Override
2957
        public String toString() {
2958
            return this.toString(formatter());
2959
        }
2960

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

    
2982
        @Override
2983
        public List<String> toStrings() {
2984
            return this.toStrings(formatter());
2985
        }
2986

    
2987
        @Override
2988
        public List<String> toStrings(Formatter formatter) {
2989
            List<String> sqls = new ArrayList<>();
2990

    
2991
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2992
                String sql = MessageFormat.format(
2993
                        STMT_UPDATE_TABLE_STATISTICS_table,
2994
                        table.toString(formatter)
2995
                );
2996
                if (!StringUtils.isEmpty(sql)) {
2997
                    sqls.add(sql);
2998
                }
2999
            }
3000
            return sqls;
3001
        }
3002
    }
3003

    
3004
    protected GeometryExpressionBuilder expressionBuilder;
3005

    
3006
    protected String defaultSchema;
3007
    protected boolean supportSchemas;
3008
    protected boolean hasSpatialFunctions;
3009
    protected GeometrySupportType geometrySupportType;
3010
    protected boolean allowAutomaticValues;
3011

    
3012
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
3013

    
3014
    protected String constant_true = "(1=1)";
3015
    protected String constant_false = "(1<>1)";
3016

    
3017
    protected String type_boolean = "BOOLEAN";
3018
    protected String type_byte = "TINYINT";
3019
    protected String type_bytearray = "BYTEA";
3020
    protected String type_geometry = "TEXT";
3021
    protected String type_char = "CHARACTER(1)";
3022
    protected String type_date = "DATE";
3023
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
3024
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
3025
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
3026
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
3027
    protected String type_int = "INT";
3028
    protected String type_long = "BIGINT";
3029
    protected String type_string = "TEXT";
3030
    protected String type_string_p = "VARCHAR({0,Number,#######})";
3031
    protected String type_time = "TIME";
3032
    protected String type_timestamp = "TIMESTAMP";
3033
    protected String type_version = "VARCHAR(30)";
3034
    protected String type_URI = "TEXT";
3035
    protected String type_URL = "TEXT";
3036
    protected String type_FILE = "TEXT";
3037
    protected String type_FOLDER = "TEXT";
3038

    
3039
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
3040
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
3041
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
3042
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
3043
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
3044
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
3045
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
3046
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
3047
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
3048
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3049

    
3050
    public SQLBuilderBase() {
3051
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3052
        this.expressionBuilder.setProperty("SQLBUILDER", this);
3053

    
3054
        this.hasSpatialFunctions = false;
3055
        this.supportSchemas = true;
3056
        this.geometrySupportType = GeometrySupportType.WKT;
3057

    
3058
        this.defaultSchema = "public";
3059
        this.allowAutomaticValues = true;
3060

    
3061
    }
3062
    
3063
    @Override
3064
    public void setProperties(Class filter, final Object... values) {
3065
        this.expressionBuilder.setProperties(filter, values);
3066
        setProperties(this, filter, values);
3067
    }
3068
    
3069
    @Override
3070
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3071
        if(visitable == null){
3072
            return;
3073
        }
3074
        if(visitable instanceof PropertiesSupport){
3075
            for (int i = 0; i < values.length; i+=2) {
3076
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3077
            }
3078
        }
3079
        visitable.accept((Visitable v) -> {
3080
            if(v instanceof PropertiesSupport){
3081
                for (int i = 0; i < values.length; i+=2) {
3082
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3083
                }
3084
            }
3085
        }, new ClassVisitorFilter(filter) );
3086
    }
3087

    
3088
    public String quote_for_identifiers() {
3089
        return "\"";
3090
    }
3091

    
3092
    public String quote_for_strings() {
3093
        return "'";
3094
    }
3095

    
3096
    @Override
3097
    public String as_identifier(String id) {
3098
        String quote = this.quote_for_identifiers();
3099
//        No se porque no esta disponible wrapIfMissing
3100
//        return StringUtils.wrapIfMissing(id,quote);
3101
        if (id.startsWith(quote)) {
3102
            return id;
3103
        }
3104
        return quote + id + quote;
3105

    
3106
    }
3107

    
3108
    @Override
3109
    public String as_string(String s) {
3110
        String quote = this.quote_for_strings();
3111
//        No se porque no esta disponible wrapIfMissing
3112
//        return StringUtils.wrapIfMissing(id,quote);
3113
        if (s.startsWith(quote)) {
3114
            return s;
3115
        }
3116
        return quote + s + quote;
3117

    
3118
    }
3119

    
3120
    @Override
3121
    public String as_string(byte[] data) {
3122
        return this.expressionBuilder.bytearray_0x(data);
3123
//        return this.expressionBuilder.bytearray_hex(data);
3124
//        return this.expressionBuilder.bytearray_x(data);
3125
    }
3126
    
3127
    @Override
3128
    public String as_string(boolean value) {
3129
        return value? "TRUE" : "FALSE";
3130
    }
3131

    
3132
    @Override
3133
    public String as_string(Number value) {
3134
        return Objects.toString(value);
3135
    }
3136
    
3137
    @Override
3138
    public String as_string(Object value) {
3139
        if( value == null ) {
3140
            return "NULL";
3141
        }
3142
        if( value instanceof CharSequence ) {
3143
            return as_string(value.toString());
3144
        }
3145
        if( value instanceof Number ) {
3146
            return as_string((Number)value);
3147
        }
3148
        if( value instanceof Boolean ) {
3149
            return as_string((boolean)value);
3150
        }
3151
        if( value instanceof byte[] ) {
3152
            return as_string((byte[])value);
3153
        }
3154
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3155
    }
3156
    
3157
    @Override
3158
    public GeometryExpressionBuilder expression() {
3159
        return this.expressionBuilder;
3160
    }
3161

    
3162
    @Override
3163
    public boolean has_spatial_functions() {
3164
        return this.hasSpatialFunctions;
3165
    }
3166

    
3167
    @Override
3168
    public GeometrySupportType geometry_support_type() {
3169
        return this.geometrySupportType;
3170
    }
3171

    
3172
    protected GeometryExpressionBuilder createExpressionBuilder() {
3173
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3174
    }
3175

    
3176
    @Override
3177
    public Object srs_id(IProjection projection) {
3178
        String abrev = projection.getAbrev();
3179
        return abrev.split(":")[1].trim();
3180
    }
3181

    
3182
    @Override
3183
    public String default_schema() {
3184
        return this.defaultSchema;
3185
    }
3186

    
3187
    @Override
3188
    public boolean support_schemas() {
3189
        return this.supportSchemas;
3190
    }
3191

    
3192
    @Override
3193
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3194
        switch (type) {
3195
            case DataTypes.BOOLEAN:
3196
                return type_boolean;
3197
            case DataTypes.CHAR:
3198
                return type_char;
3199

    
3200

    
3201
            case DataTypes.BYTE:
3202
                return type_byte;
3203
            case DataTypes.INT:
3204
                return type_int;
3205
            case DataTypes.LONG:
3206
                return type_long;
3207

    
3208
            case DataTypes.FLOAT:
3209
                return type_float;
3210
            case DataTypes.DOUBLE:
3211
                return type_double;
3212
            case DataTypes.DECIMAL:
3213
                if (precision < 1) {
3214
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3215
                }
3216
                if (scale < 1) {
3217
                  return MessageFormat.format(type_decimal_p, precision);
3218
                }
3219
                return MessageFormat.format(type_decimal_ps, precision, scale);
3220

    
3221
                
3222
            case DataTypes.STRING:
3223
                if (size < 0) {
3224
                    return type_string;
3225
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3226
                    return MessageFormat.format(type_string_p, size);
3227
                }
3228
                return type_string;
3229

    
3230
                
3231
            case DataTypes.DATE:
3232
                return type_date;
3233
            case DataTypes.TIME:
3234
                return type_time;
3235
            case DataTypes.TIMESTAMP:
3236
                return type_timestamp;
3237

    
3238
            case DataTypes.BYTEARRAY:
3239
                return type_bytearray;
3240

    
3241
            case DataTypes.GEOMETRY:
3242
                return type_geometry;
3243

    
3244
            case DataTypes.VERSION:
3245
                return type_version;
3246
            case DataTypes.URI:
3247
                return type_URI;
3248
            case DataTypes.URL:
3249
                return type_URL;
3250
            case DataTypes.FILE:
3251
                return type_FILE;
3252
            case DataTypes.FOLDER:
3253
                return type_FOLDER;
3254
            default:
3255
                return null;
3256
        }
3257
    }
3258

    
3259
    @Override
3260
    public Object sqlgeometrytype(int type, int subtype) {
3261
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3262
        // identificadores numericos para el tipo y otros strings.
3263
        // Por defecto vamos a devolver strings.
3264
        if (sqlgeometrytypes == null) {
3265
            sqlgeometrytypes = new HashMap<>();
3266
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3267
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3268
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3269
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3270

    
3271
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3272
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3273
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3274
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3275

    
3276
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3277
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3278
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3279
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3280

    
3281
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3282
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3283
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3284
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3285

    
3286
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3287
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3288
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3289
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3290

    
3291
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3292
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3293
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3294
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3295

    
3296
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3297
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3298
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3299
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3300

    
3301
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3302
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3303
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3304
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3305

    
3306
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3307
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3308
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3309
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3310
        }
3311
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3312
    }
3313

    
3314
    @Override
3315
    public Object sqlgeometrydimension(int type, int subtype) {
3316
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3317
        // identificadores numericos para las dimensiones y otros strings.
3318
        // Por defecto vamos a devolver enteros.
3319
        switch (subtype) {
3320
            case Geometry.SUBTYPES.GEOM3D:
3321
                return 3;
3322
            case Geometry.SUBTYPES.GEOM2DM:
3323
                return 3;
3324
            case Geometry.SUBTYPES.GEOM3DM:
3325
                return 4;
3326
            case Geometry.SUBTYPES.GEOM2D:
3327
            default:
3328
                return 2;
3329
        }
3330
    }
3331

    
3332
    @Override
3333
    public SelectColumnBuilder column() {
3334
        return createSelectColumnBuilder();
3335
    }
3336

    
3337
    @Override
3338
    public TableNameBuilder createTableNameBuilder() {
3339
        return new TableNameBuilderBase();
3340
    }
3341

    
3342
    protected SelectColumnBuilder createSelectColumnBuilder() {
3343
        return new SelectColumnBuilderBase(this);
3344
    }
3345

    
3346
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3347
        return new UpdateColumnBuilderBase();
3348
    }
3349

    
3350
    protected InsertColumnBuilder createInsertColumnBuilder() {
3351
        return new InsertColumnBuilderBase();
3352
    }
3353

    
3354
    protected OrderByBuilder createOrderByBuilder() {
3355
        return new OrderByBuilderBase();
3356
    }
3357

    
3358
    protected FromBuilder createFromBuilder() {
3359
        return new FromBuilderBase();
3360
    }
3361

    
3362
    public SelectBuilder createSelectBuilder() {
3363
        return new SelectBuilderBase();
3364
    }
3365

    
3366
    protected UpdateBuilder createUpdateBuilder() {
3367
        return new UpdateBuilderBase();
3368
    }
3369

    
3370
    protected DeleteBuilder createDeleteBuilder() {
3371
        return new DeleteBuilderBase();
3372
    }
3373

    
3374
    protected GrantBuilder createGrantBuilder() {
3375
        return new GrantBuilderBase();
3376
    }
3377

    
3378
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3379
        return new GrantRoleBuilderBase(table, role);
3380
    }
3381

    
3382
    protected DropTableBuilder createDropTableBuilder() {
3383
        return new DropTableBuilderBase();
3384
    }
3385

    
3386
    protected CreateTableBuilder createCreateTableBuilder() {
3387
        return new CreateTableBuilderBase();
3388
    }
3389

    
3390
    protected AlterTableBuilder createAlterTableBuilder() {
3391
        return new AlterTableBuilderBase();
3392
    }
3393

    
3394
    protected InsertBuilder createInsertBuilder() {
3395
        return new InsertBuilderBase();
3396
    }
3397

    
3398
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3399
        return new UpdateTableStatisticsBuilderBase();
3400
    }
3401

    
3402
    protected CreateIndexBuilder createCreateIndexBuilder() {
3403
        return new CreateIndexBuilderBase();
3404
    }
3405

    
3406
    protected DropIndexBuilder createDropIndexBuilder() {
3407
        return new DropIndexBuilderBase();
3408
    }
3409

    
3410
    @Override
3411
    public SelectBuilder select() {
3412
        if (this.select == null) {
3413
            this.select = this.createSelectBuilder();
3414
        }
3415
        return this.select;
3416
    }
3417

    
3418
    @Override
3419
    public UpdateBuilder update() {
3420
        if (this.update == null) {
3421
            this.update = this.createUpdateBuilder();
3422
        }
3423
        return this.update;
3424
    }
3425

    
3426
    @Override
3427
    public UpdateTableStatisticsBuilder update_table_statistics() {
3428
        if (this.update_table_statistics == null) {
3429
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3430
        }
3431
        return this.update_table_statistics;
3432
    }
3433

    
3434
    @Override
3435
    public DropTableBuilder drop_table() {
3436
        if (this.drop_table == null) {
3437
            this.drop_table = this.createDropTableBuilder();
3438
        }
3439
        return this.drop_table;
3440
    }
3441

    
3442
    @Override
3443
    public CreateIndexBuilder create_index() {
3444
        if (this.create_index == null) {
3445
            this.create_index = this.createCreateIndexBuilder();
3446
        }
3447
        return this.create_index;
3448
    }
3449

    
3450
    @Override
3451
    public DropIndexBuilder drop_index() {
3452
        if (this.drop_index == null) {
3453
            this.drop_index = this.createDropIndexBuilder();
3454
        }
3455
        return this.drop_index;
3456
    }
3457

    
3458
    @Override
3459
    public DeleteBuilder delete() {
3460
        if (this.delete == null) {
3461
            this.delete = this.createDeleteBuilder();
3462
        }
3463
        return this.delete;
3464
    }
3465

    
3466
    @Override
3467
    public InsertBuilder insert() {
3468
        if (this.insert == null) {
3469
            this.insert = this.createInsertBuilder();
3470
        }
3471
        return this.insert;
3472
    }
3473

    
3474
    @Override
3475
    public TableNameBuilder table_name() {
3476
        if (this.table_name == null) {
3477
            this.table_name = this.createTableNameBuilder();
3478
        }
3479
        return this.table_name;
3480
    }
3481

    
3482
    
3483
    @Override
3484
    public AlterTableBuilder alter_table() {
3485
        if (this.alter_table == null) {
3486
            this.alter_table = this.createAlterTableBuilder();
3487
        }
3488
        return this.alter_table;
3489
    }
3490

    
3491
    @Override
3492
    public CreateTableBuilder create_table() {
3493
        if (this.create_table == null) {
3494
            this.create_table = this.createCreateTableBuilder();
3495
        }
3496
        return this.create_table;
3497
    }
3498

    
3499
    @Override
3500
    public GrantBuilder grant() {
3501
        if (this.grant == null) {
3502
            this.grant = this.createGrantBuilder();
3503
        }
3504
        return this.grant;
3505
    }
3506
    
3507
    @Override
3508
    public Column column(String name) {
3509
        ColumnBase col = new ColumnBase(null, name);
3510
        return col;
3511
    }
3512

    
3513
    @Override
3514
    public Column column(TableNameBuilder table, String name) {
3515
        ColumnBase col = new ColumnBase(table, name);
3516
        return col;
3517
    }
3518
    
3519
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3520
        return new JoinBase(type, table, expression);
3521
    }
3522

    
3523
    @Override
3524
    public void accept(Visitor visitor, VisitorFilter filter) {
3525
        if (this.select != null) {
3526
            this.select.accept(visitor, filter);
3527
        }
3528
        if (this.update != null) {
3529
            this.update.accept(visitor, filter);
3530
        }
3531
        if (this.insert != null) {
3532
            this.insert.accept(visitor, filter);
3533
        }
3534
        if (this.delete != null) {
3535
            this.delete.accept(visitor, filter);
3536
        }
3537
        if (this.alter_table != null) {
3538
            this.alter_table.accept(visitor, filter);
3539
        }
3540
        if (this.create_table != null) {
3541
            this.create_table.accept(visitor, filter);
3542
        }
3543
        if (this.drop_table != null) {
3544
            this.drop_table.accept(visitor, filter);
3545
        }
3546
        if (this.table_name != null) {
3547
            this.table_name.accept(visitor, filter);
3548
        }
3549
    }
3550

    
3551
    @Override
3552
    public Formatter formatter() {
3553
        return expression().formatter();
3554
    }
3555

    
3556
    @Override
3557
    public String toString() {
3558
        return this.toString(formatter());
3559
    }
3560

    
3561
    @Override
3562
    public String toString(Formatter formatter) {
3563
        if (this.select != null) {
3564
            return this.select.toString(formatter);
3565
        }
3566
        if (this.update != null) {
3567
            return this.update.toString(formatter);
3568
        }
3569
        if (this.insert != null) {
3570
            return this.insert.toString(formatter);
3571
        }
3572
        if (this.delete != null) {
3573
            return this.delete.toString(formatter);
3574
        }
3575
        if (this.alter_table != null) {
3576
            return this.alter_table.toString(formatter);
3577
        }
3578
        if (this.create_table != null) {
3579
            return this.create_table.toString(formatter);
3580
        }
3581
        if (this.drop_table != null) {
3582
            return this.drop_table.toString(formatter);
3583
        }
3584
        if (this.update_table_statistics != null) {
3585
            return this.update_table_statistics.toString(formatter);
3586
        }
3587
        if (this.create_index != null) {
3588
            return this.create_index.toString(formatter);
3589
        }
3590
        if (this.drop_index != null) {
3591
            return this.drop_index.toString(formatter);
3592
        }
3593
        if (this.table_name != null) {
3594
            return this.table_name.toString(formatter);
3595
        }
3596
        return "";
3597
    }
3598

    
3599
    @Override
3600
    public CountBuilder count() {
3601
        return new CountBuilderBase();
3602
    }
3603

    
3604
    @Override
3605
    public List<Parameter> parameters() {
3606
        final List<Parameter> params = new ArrayList<>();
3607
        this.accept((Visitable value) -> {
3608
            params.add((Parameter) value);
3609
        }, new ClassVisitorFilter(Parameter.class));
3610
        return params;
3611
    }
3612

    
3613
    @Override
3614
    public List<Variable> variables() {
3615
        final List<Variable> vars = new ArrayList<>();
3616
        this.accept(new Visitor() {
3617
            @Override
3618
            public void visit(Visitable value) {
3619
                if (!vars.contains((Variable) value)) {
3620
                    vars.add((Variable) value);
3621
                }
3622
            }
3623
        }, new ClassVisitorFilter(Variable.class));
3624
        return vars;
3625
    }
3626

    
3627
    @Override
3628
    public List<String> parameters_names() {
3629
        List<String> params = new ArrayList<>();
3630
        for (Parameter param : parameters()) {
3631
            String s;
3632
            switch (param.type()) {
3633
                case PARAMETER_TYPE_CONSTANT:
3634
                    Object theValue = param.value();
3635
                    if (theValue == null) {
3636
                        s = "null";
3637
                    } else if (theValue instanceof String) {
3638
                        s = "'" + (String) theValue + "'";
3639
                    } else {
3640
                        s = theValue.toString();
3641
                    }
3642
                    break;
3643
                case PARAMETER_TYPE_VARIABLE:
3644
                default:
3645
                    s = "\"" + param.name() + "\"";
3646
            }
3647
            params.add(s);
3648
        }
3649
        return params;
3650
    }
3651

    
3652
    @Override
3653
    public List<String> variables_names() {
3654
        List<String> vars = new ArrayList<>();
3655
        for (Variable var : this.variables()) {
3656
            vars.add(var.name());
3657
        }
3658
        Collections.sort(vars);
3659
        return vars;
3660
    }    
3661
    
3662
    protected String[] aggregateFunctionNames = new String[] {
3663
        "MAX",
3664
        "MIN",
3665
        "COUNT",
3666
        "SUM"
3667
    };
3668
    
3669
    @Override
3670
    public boolean isAggregateFunction(String funcname) {
3671
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
3672
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
3673
                return true;
3674
            }
3675
        }
3676
        return false;
3677
    }
3678

    
3679
    @Override
3680
    public int getMaxRecomendedSQLLength() {
3681
        return DEFAULT_RECOMENDED_SQL_LENGTH;
3682
    }
3683
    
3684
    
3685
}