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

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

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

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

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

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

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

    
91
    protected class ColumnDescriptorBase implements ColumnDescriptor {
92

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
356
    public class ColumnBase extends AbstractValue implements Column {
357

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

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

    
373

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
488
        @Override
489
        public boolean has_name() {
490
            return !StringUtils.isBlank(this.tableName);
491
        }
492

    
493
        @Override
494
        public boolean has_database() {
495
            return !StringUtils.isBlank(this.databaseName);
496
        }
497

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

    
503
        @Override
504
        public String toString(Formatter<Value> formatter) {
505
            if (formatter!=null && formatter.canApply(this)) {
506
                return formatter.format(this);
507
            }
508
            if (this.has_database()) {
509
                if (this.has_schema()) {
510
                    return as_identifier(this.databaseName) + "."
511
                            + as_identifier(this.schemaName) + "."
512
                            + as_identifier(this.tableName);
513
                }
514
            } else {
515
                if (this.has_schema()) {
516
                    return as_identifier(this.schemaName) + "."
517
                            + as_identifier(this.tableName);
518
                }
519
            }
520
            return as_identifier(this.tableName);
521
        }
522

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

    
555
        @Override
556
        public int hashCode() {
557
            int hash = 7;
558
            hash = 37 * hash + Objects.hashCode(this.toString());
559
            return hash;
560
        }
561

    
562
    }
563

    
564
    public class CountBuilderBase
565
            extends AbstractStatementPart
566
            implements CountBuilder {
567

    
568
        protected Value value;
569
        protected boolean distinct;
570
        protected boolean all;
571

    
572
        public CountBuilderBase() {
573
            this.value = null;
574
            this.distinct = false;
575
            this.all = false;
576
        }
577
        
578
        @Override
579
        public CountBuilderBase clone() throws CloneNotSupportedException {
580
            CountBuilderBase other = (CountBuilderBase) super.clone();
581
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
582
            return other;
583
        }
584
        
585
        @Override
586
        public CountBuilder all() {
587
            this.all = true;
588
            return this;
589
        }
590

    
591
        @Override
592
        public CountBuilder column(Value value) {
593
            this.value = value;
594
            return this;
595
        }
596

    
597
        @Override
598
        public CountBuilder distinct() {
599
            this.distinct = true;
600
            return this;
601
        }
602

    
603
        @Override
604
        public String toString() {
605
            return this.toString(formatter());
606
        }
607

    
608
        @Override
609
        public String toString(Formatter formatter) {
610
            if (formatter!=null && formatter.canApply(this)) {
611
                return formatter.format(this);
612
            }
613
            if (this.all) {
614
                return "COUNT(*)";
615
            }
616
            if (this.distinct) {
617
                return MessageFormat.format(
618
                        "COUNT(DISTINCT {0})",
619
                        value.toString(formatter)
620
                );
621
            }
622
            return MessageFormat.format(
623
                    "COUNT({0})",
624
                    value.toString(formatter)
625
            );
626
        }
627

    
628
    }
629

    
630
    protected class JoinBase 
631
            extends AbstractStatementPart
632
            implements StatementPart 
633
        {
634
        protected String type;
635
        protected TableNameBuilder table;
636
        protected Value expression;
637
        
638
        public JoinBase(String type, TableNameBuilder table, Value expression) {
639
            this.type = type;
640
            this.table = table;
641
            this.expression = expression;
642
        }
643
        
644
        @Override
645
        public JoinBase clone() throws CloneNotSupportedException {
646
            JoinBase other = (JoinBase) super.clone();
647
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
648
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
649
            return other;
650
        }
651

    
652
        @Override
653
        public String toString() {
654
            return this.toString(formatter());
655
        }
656

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

    
679
        protected TableNameBuilder tableName;
680
        protected String subquery;
681
        protected String passthrough;
682
        protected List<JoinBase> joins;
683

    
684
        public FromBuilderBase() {
685
            this.tableName = null;
686
            this.subquery = null;
687
            this.passthrough = null;
688
            this.joins = null;
689
        }
690
        
691
        @Override
692
        public FromBuilderBase clone() throws CloneNotSupportedException {
693
            FromBuilderBase other = (FromBuilderBase) super.clone();
694
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
695
            if (joins!=null) {
696
                for (int i = 0; i < joins.size(); i++) {
697
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
698
                }
699
            }
700
            return other;
701
        }
702

    
703
        @Override
704
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
705
            JoinBase join = createJoin("LEFT", table, expression);
706
            if( this.joins==null ) {
707
                this.joins = new ArrayList<>();
708
            }
709
            this.joins.add(join);
710
            return this;
711
        }
712
        
713
        @Override
714
        public TableNameBuilder table() {
715
            if (tableName == null) {
716
                this.tableName = createTableNameBuilder();
717
            }
718
            return this.tableName;
719
        }
720

    
721
        @Override
722
        public void accept(Visitor visitor, VisitorFilter filter) {
723
            boolean visitChildren = true;
724
            if (filter==null || filter.accept(this)) {
725
                visitor.visit(this);
726
            } else {
727
                visitChildren = !filter.skipChildren();
728
            }
729
            if(visitChildren){
730
                if (this.tableName != null) {
731
                    this.tableName.accept(visitor, filter);
732
                }
733
            }
734
        }
735

    
736
        @Override
737
        public FromBuilder custom(String passthrough) {
738
            this.passthrough = passthrough;
739
            return this;
740
        }
741

    
742
        @Override
743
        public FromBuilder subquery(String subquery) {
744
            this.subquery = subquery;
745
            return this;
746
        }
747

    
748
        @Override
749
        public String toString() {
750
            return this.toString(formatter());
751
        }
752

    
753
        @Override
754
        public String toString(Formatter<Value> formatter) {
755
            if (formatter!=null && formatter.canApply(this)) {
756
                return formatter.format(this);
757
            }
758
            if (!StringUtils.isEmpty(passthrough)) {
759
                return passthrough;
760
            }
761
            if (!StringUtils.isEmpty(subquery)) {
762
                return "( " + this.subquery + ") as _subquery_alias_ ";
763
            }
764
            if( this.joins==null || this.joins.isEmpty() ) {
765
                return this.tableName.toString(formatter);
766
            }
767
            StringBuilder builder = new StringBuilder();
768
            builder.append(this.tableName.toString(formatter));
769
            for (JoinBase join : this.joins) {
770
                builder.append(" ");
771
                builder.append(join.toString(formatter));
772
            }
773
            return builder.toString();
774
        }
775

    
776
    }
777

    
778
    public class SelectColumnBuilderBase
779
            extends AbstractStatementPart
780
            implements SelectColumnBuilder {
781

    
782
        protected Column name = null;
783
        protected String alias = null;
784
        protected Value value = null;
785
        protected boolean asGeometry = false;
786
        protected TableNameBuilder table;
787
        protected SQLBuilder sqlbuilder;
788
        
789
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
790
            this.sqlbuilder = sqlbuilder;
791
        }
792
        
793
        @Override
794
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
795
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
796
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
797
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
798
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
799
            return other;
800
        }
801

    
802
        @Override
803
        public void accept(Visitor visitor, VisitorFilter filter) {
804
            boolean visitChildren = true;
805
            if (filter==null || filter.accept(this)) {
806
                visitor.visit(this);
807
            } else {
808
                visitChildren = !filter.skipChildren();
809
            }
810
            if(visitChildren){
811
                if (this.value != null) {
812
                    this.value.accept(visitor, filter);
813
                } else if (this.name != null) {
814
                    this.name.accept(visitor, filter);
815
                }
816
            }
817
        }
818

    
819
        @Override
820
        public void replace(Value target, Value replacement) {
821
            if (this.name!=null ) {
822
                if( this.name == target) {
823
                    if(replacement == null){
824
                        this.name = null;
825
                    } else if(replacement instanceof Column){
826
                        this.name = (Column) replacement;
827
                    } else if(replacement instanceof Variable){
828
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
829
                    } else {
830
                        this.value = replacement;
831
                    }
832
                }
833
            }
834
            if( this.value!=null ) {
835
                if (this.value == target) {
836
                    this.value = replacement;
837
                } else {
838
                    this.value.replace(target, replacement);
839
                }
840
            }
841
        }
842

    
843
        @Override
844
        public SelectColumnBuilder name(String name) {
845
            return this.name(null, name);
846
        }
847

    
848
        @Override
849
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
850
            String quote = quote_for_identifiers();
851
            if (name.startsWith(quote)) {
852
                // Remove quotes
853
                name = name.substring(1, name.length() - 1);
854
            }
855
            this.table = table;
856
            this.name = new ColumnBase(this.table, name);
857
            this.value = null;
858
            this.asGeometry = false;
859
            return this;
860
        }
861

    
862
        @Override
863
        public SelectColumnBuilder all() {
864
            this.name = null;
865
            this.value = expression().custom("*");
866
            this.asGeometry = false;
867
            return this;
868
        }
869

    
870
        @Override
871
        public SelectColumnBuilder as_geometry() {
872
            this.asGeometry = true;
873
            return this;
874
        }
875

    
876
        @Override
877
        public SelectColumnBuilder value(Value value) {
878
            this.value = value;
879
            return this;
880
        }
881

    
882
        @Override
883
        public SelectColumnBuilder as(String alias) {
884
            this.alias = alias;
885
            return this;
886
        }
887

    
888
        @Override
889
        public String getName() {
890
            if (this.name==null) {
891
                return null;
892
            }
893
            return this.name.name();
894
        }
895

    
896
        @Override
897
        public String getAlias() {
898
            return this.alias;
899
        }
900

    
901
        @Override
902
        public Value getValue() {
903
            return this.value;
904
        }
905

    
906
        @Override
907
        public String toString() {
908
            return this.toString(formatter());
909
        }
910

    
911
        @Override
912
        public String toString(Formatter<Value> formatter) {
913
            if (formatter!=null && formatter.canApply(this)) {
914
                return formatter.format(this);
915
            }
916
            StringBuilder builder = new StringBuilder();
917
            if (this.asGeometry) {
918
                if(this.value == VALUE_NULL){
919
                    builder.append(this.value.toString(formatter));
920
                } else {
921
                    builder.append(expression().ST_AsBinary(this.name).toString(formatter));
922
                }
923
            } else {
924
                if (this.value == null) {
925
                    builder.append(this.name.toString(formatter));
926
                } else {
927
                    builder.append(this.value.toString(formatter));
928
                }
929
            }
930
            if (this.alias != null) {
931
                builder.append(" AS ");
932
                builder.append(as_identifier(this.alias));
933
            }
934
            return builder.toString();
935
        }
936
        
937
        @Override
938
        public boolean isGeometry() {
939
            return this.asGeometry;
940
        }
941
        
942
        @Override
943
        public TableNameBuilder getTable() {
944
            return this.table;
945
        }
946
        
947
        @Override
948
        public boolean isAggregateFunction() {
949
            if( this.value == null ) {
950
                return false;
951
            }
952
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
953
                return false;
954
            }
955
            String funcname = ((ExpressionBuilder.Function)this.value).name();
956
            return this.sqlbuilder.isAggregateFunction(funcname);
957
        }
958
    }
959

    
960
    public class OrderByBuilderBase
961
            extends AbstractStatementPart
962
            implements OrderByBuilder {
963

    
964
        protected Value value;
965
        protected String custom;
966
        protected boolean ascending;
967
        protected int nullsMode;
968

    
969
        public OrderByBuilderBase() {
970
            this.ascending = true;
971
            this.nullsMode = MODE_NULLS_LAST;
972
        }
973
        
974
        @Override
975
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
976
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
977
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
978
            return other;
979
        }
980
        
981
        @Override
982
        public void accept(Visitor visitor, VisitorFilter filter) {
983
            boolean visitChildren = true;
984
            if (filter==null || filter.accept(this)) {
985
                visitor.visit(this);
986
            } else {
987
                visitChildren = !filter.skipChildren();
988
            }
989
            if(visitChildren){
990
                if (this.value!=null) {
991
                    this.value.accept(visitor, filter);
992
                }
993
            }
994
        }
995

    
996
        @Override
997
        public OrderByBuilder column(String name) {
998
            this.value = expression().variable(name);
999
            return this;
1000
        }
1001
        
1002
        @Override
1003
        public boolean isColumn(String name) {
1004
            if(this.value instanceof ExpressionBuilder.Variable){
1005
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1006
            }
1007
            return false;
1008
        }
1009
        
1010
        @Override
1011
        public boolean isColumn(Value value) {
1012
            if(value instanceof ExpressionBuilder.Variable){
1013
                return isColumn(((ExpressionBuilder.Variable)value).name());
1014
            }
1015
            return this.value == value;
1016
        }
1017
        
1018
        @Override
1019
        public OrderByBuilder value(Value expression) {
1020
            this.value = expression;
1021
            return this;
1022
        }
1023
        
1024
        @Override
1025
        public OrderByBuilder custom(String order) {
1026
            this.custom = order;
1027
            return this;
1028
        }
1029

    
1030
        @Override
1031
        public OrderByBuilder ascending() {
1032
            this.ascending = true;
1033
            return this;
1034
        }
1035

    
1036
        @Override
1037
        public OrderByBuilder ascending(boolean asc) {
1038
            this.ascending = asc;
1039
            return this;
1040
        }
1041

    
1042
        @Override
1043
        public OrderByBuilder descending() {
1044
            this.ascending = false;
1045
            return this;
1046
        }
1047

    
1048
        @Override
1049
        public OrderByBuilder nulls(int mode) {
1050
            this.nullsMode = mode;
1051
            return this;
1052
        }
1053

    
1054
        @Override
1055
        public int getNullsMode() {
1056
            return this.nullsMode;
1057
        }
1058

    
1059
        @Override
1060
        public String toString() {
1061
            return this.toString(formatter());
1062
        }
1063

    
1064
        @Override
1065
        public String toString(Formatter<Value> formatter) {
1066
            if (formatter!=null && formatter.canApply(this)) {
1067
                return formatter.format(this);
1068
            }
1069
            if (!StringUtils.isEmpty(this.custom)) {
1070
                return this.custom;
1071
            }
1072
            String order_s = this.value.toString(formatter);
1073
            if (this.ascending) {
1074
                order_s += " ASC";
1075
            } else {
1076
                order_s += " DESC";
1077
            }
1078
            switch(this.nullsMode) {
1079
                case MODE_NULLS_NOT_SPECIFIED:
1080
                    break;
1081
                case MODE_NULLS_FIRST:
1082
                    order_s += " NULLS FIRST";
1083
                    break;
1084
                case MODE_NULLS_LAST:
1085
                default:
1086
                    order_s += " NULLS LAST";
1087
                    break;
1088
            }
1089
            return order_s;
1090
        }
1091

    
1092
        @Override
1093
        public void replace(Value target, Value replacement) {
1094
            super.replace(target, replacement);
1095
            if(target == this.value){
1096
                this.value = replacement;
1097
                return;
1098
            }
1099
            if(this.value == null){
1100
                return;
1101
            }
1102
            this.value.replace(target, replacement);
1103
        }
1104
        
1105
        
1106
    }
1107

    
1108
    public class SelectBuilderBase
1109
            extends AbstractStatement
1110
            implements SelectBuilder {
1111

    
1112
        protected FromBuilder from;
1113
        protected GeometryExpressionBuilder where;
1114
        protected long limit = -1;
1115
        protected long offset = -1;
1116
        protected List<SelectColumnBuilder> columns;
1117
        protected List<OrderByBuilder> order_by;
1118
        protected boolean distinct;
1119
        protected List<Value> groupColumn;
1120
        protected boolean check_order_and_offset = true;
1121

    
1122
        public SelectBuilderBase() {
1123
            this.columns = new ArrayList<>();
1124
            this.distinct = false;
1125
        }
1126
        @Override
1127
        public List<Value> getGroups() {
1128
            return this.groupColumn;
1129
        }
1130
        
1131
        @Override
1132
        public List<SelectColumnBuilder> getColumns() {
1133
            return Collections.unmodifiableList(this.columns);
1134
    }
1135
        
1136
        @Override
1137
        public void remove_column(String columnName) {
1138
            SelectColumnBuilder found = null;
1139
            for (SelectColumnBuilder column : columns) {
1140
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1141
                    found = column;
1142
                    break;
1143
                }
1144
                    
1145
            }
1146
            if(found!=null) {
1147
                columns.remove(found);
1148
            }
1149
        }
1150

    
1151
        @Override
1152
        public SelectBuilder group_by(Value... columns) {
1153
            if( this.groupColumn==null ) {
1154
                this.groupColumn = new ArrayList<>();
1155
            }
1156
            for (Value column : columns) {
1157
                this.groupColumn.add(column);
1158
            }
1159
            return this;
1160
        }
1161

    
1162
        @Override
1163
        public void accept(Visitor visitor, VisitorFilter filter) {
1164
            boolean visitChildren = true;
1165
            if (filter==null || filter.accept(this)) {
1166
                visitor.visit(this);
1167
            } else {
1168
                visitChildren = !filter.skipChildren();
1169
            }
1170
            if(visitChildren){
1171
                for (SelectColumnBuilder column : columns) {
1172
                    column.accept(visitor, filter);
1173
                }
1174
                if (this.has_from()) {
1175
                    this.from.accept(visitor, filter);
1176
                }
1177
                if (this.has_where()) {
1178
                    this.where.accept(visitor, filter);
1179
                }
1180
                if (this.has_order_by()) {
1181
                    for (OrderByBuilder order : order_by) {
1182
                        order.accept(visitor, filter);
1183
                    }
1184
                }
1185
                if (this.has_group_by()) {
1186
                    for (Value group : groupColumn) {
1187
                        group.accept(visitor, filter);
1188
                    }
1189
                }
1190
            }
1191
        }
1192

    
1193
        @Override
1194
        public void replace(Value target, Value replacement) {
1195
            if( this.columns!=null ) {
1196
                for (int i = 0; i < columns.size(); i++) {
1197
                    SelectColumnBuilder column = columns.get(i);
1198
                    if( column == target ) {
1199
                        columns.set(i, (SelectColumnBuilder) replacement);
1200
                    } else {
1201
                        column.replace(target, replacement);
1202
                    }
1203
                }
1204
            }
1205
            if (this.has_from()) {
1206
                if( this.from == target ) {
1207
                    this.from = (FromBuilder) replacement;
1208
                } else {
1209
                    this.from.replace(target, replacement);
1210
                }
1211
            }
1212
            if (this.has_where()) {
1213
                if( this.where == target ) {
1214
                    this.where = (GeometryExpressionBuilder) replacement;
1215
                } else if( this.where.value() == target ) {
1216
                    this.where.value(replacement);
1217
                } else {
1218
                    this.where.value().replace(target, replacement);
1219
                }
1220
            }
1221
            if (this.has_order_by()) {
1222
                for (int i = 0; i < order_by.size(); i++) {
1223
                    OrderByBuilder order = order_by.get(i);
1224
                    if( order == target ) {
1225
                        order_by.set(i, (OrderByBuilder) replacement);
1226
                    } else {
1227
                        order.replace(target, replacement);
1228
                    }
1229
                }
1230
            }
1231
            if (this.has_group_by()) {
1232
                for (int i = 0; i < groupColumn.size(); i++) {
1233
                    Value group = groupColumn.get(i);
1234
                    if( group == target ) {
1235
                        groupColumn.set(i, replacement);
1236
                    } else {
1237
                        group.replace(target, replacement);
1238
                    }
1239
                }
1240
            }
1241
        }
1242

    
1243
        @Override
1244
        public SelectBuilder distinct() {
1245
            this.distinct = true;
1246
            return this;
1247
        }
1248

    
1249
        @Override
1250
        public SelectColumnBuilder column() {
1251
            SelectColumnBuilder builder = createSelectColumnBuilder();
1252
            this.columns.add(builder);
1253
            return builder;
1254
        }
1255

    
1256
        @Override
1257
        public SelectColumnBuilder column(String name) {
1258
            for (SelectColumnBuilder column : columns) {
1259
                if (StringUtils.equals(name, column.getName())) {
1260
                    return column;
1261
                }
1262
            }
1263
            SelectColumnBuilder builder = createSelectColumnBuilder();
1264
            builder.name(name);
1265
            this.columns.add(builder);
1266
            return builder;
1267
        }
1268

    
1269
        @Override
1270
        public SelectBuilder remove_all_columns() {
1271
            this.columns = new ArrayList<>();
1272
            return this;
1273
        }
1274
        
1275
        @Override
1276
        public boolean has_column(String name) {
1277
            for (SelectColumnBuilder column : columns) {
1278
                if (StringUtils.equals(name, column.getName())) {
1279
                    return true;
1280
                }
1281
                if (StringUtils.equals(name, column.getAlias())) {
1282
                    return true;
1283
                }
1284
            }
1285
            return false;
1286
        }
1287

    
1288
        @Override
1289
        public FromBuilder from() {
1290
            if (this.from == null) {
1291
                this.from = createFromBuilder();
1292
            }
1293
            return this.from;
1294
        }
1295

    
1296
        @Override
1297
        public boolean has_from() {
1298
            return this.from != null;
1299
        }
1300

    
1301
        @Override
1302
        public GeometryExpressionBuilder where() {
1303
            if (this.where == null) {
1304
                this.where = createExpressionBuilder();
1305
            }
1306
            return this.where;
1307
        }
1308

    
1309
        @Override
1310
        public boolean has_where() {
1311
            if (this.where == null) {
1312
                return false;
1313
            }
1314
            return this.where.value() != null;
1315
        }
1316

    
1317
        @Override
1318
        public SelectBuilder limit(long limit) {
1319
            this.limit = limit;
1320
            return this;
1321
        }
1322

    
1323
        @Override
1324
        public SelectBuilder limit(Long limit) {
1325
            if (limit == null) {
1326
                this.limit = -1;
1327
            } else {
1328
                this.limit = limit;
1329
            }
1330
            return this;
1331
        }
1332

    
1333
        @Override
1334
        public boolean has_limit() {
1335
            return this.limit >= 0;
1336
        }
1337

    
1338
        @Override
1339
        public SelectBuilder offset(long offset) {
1340
            this.offset = offset;
1341
            return this;
1342
        }
1343

    
1344
        @Override
1345
        public boolean has_offset() {
1346
            return this.offset > 0;
1347
        }
1348

    
1349
        @Override
1350
        public OrderByBuilder order_by() {
1351
            if (this.order_by == null) {
1352
                this.order_by = new ArrayList<>();
1353
            }
1354
            OrderByBuilder order = createOrderByBuilder();
1355
            this.order_by.add(order);
1356
            return order;
1357
        }
1358
        
1359
        @Override
1360
        public OrderByBuilder getOrderBy(Value column) {
1361
            if(this.order_by == null){
1362
                return null;
1363
            }
1364
            for (OrderByBuilder orderByBuilder : this.order_by) {
1365
                if(orderByBuilder.isColumn(column)){
1366
                    return orderByBuilder;
1367
                }
1368
            }
1369
            return null;
1370
        }
1371
        
1372
        @Override
1373
        public OrderByBuilder getOrderBy(String column) {
1374
            if(this.order_by == null){
1375
                return null;
1376
            }
1377
            for (OrderByBuilder orderByBuilder : this.order_by) {
1378
                if(orderByBuilder.isColumn(column)){
1379
                    return orderByBuilder;
1380
                }
1381
            }
1382
            return null;
1383
        }
1384
        
1385
        @Override
1386
        public boolean isGroupBy(String column) {
1387
            if(this.groupColumn == null){
1388
                return false;
1389
            }
1390
            for (Value group : this.groupColumn) {
1391
                if(group instanceof Variable){
1392
                    if(StringUtils.equalsIgnoreCase(((Variable)group).name(), column)){
1393
                        return true;
1394
                    }
1395
                }
1396
            }
1397
            return false;
1398
        }
1399

    
1400
        @Override
1401
        public boolean has_order_by() {
1402
            if (this.order_by == null) {
1403
                return false;
1404
            }
1405
            return !this.order_by.isEmpty();
1406
        }
1407
        
1408
        @Override
1409
        public boolean has_group_by() {
1410
            if (this.groupColumn == null) {
1411
                return false;
1412
            }
1413
            return !this.groupColumn.isEmpty();
1414
        }
1415
        
1416
        @Override
1417
        public boolean has_aggregate_functions() {
1418
            if (this.columns == null || this.columns.isEmpty() ) {
1419
                return false;
1420
            }
1421
            for (SelectColumnBuilder column : this.columns) {
1422
                if( column.isAggregateFunction() ) {
1423
                    return true;
1424
                }
1425
            }
1426
            return false;
1427
        }
1428
        
1429
        @Override
1430
        public void disable_check_order_and_offset() {
1431
          this.check_order_and_offset = false;
1432
        }
1433
        
1434
        protected boolean isValid(StringBuilder message) {
1435
            if (message == null) {
1436
                message = new StringBuilder();
1437
            }
1438
            if( this.check_order_and_offset ) {
1439
              if (this.has_offset() && !this.has_order_by()) {
1440
                  // Algunos gestores de BBDD requieren que se especifique un
1441
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1442
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1443
                  // siempre.
1444
                  message.append("Can't use OFFSET without an ORDER BY.");
1445
                  return false;
1446
              }
1447
            }
1448
            return true;
1449
        }
1450

    
1451
        @Override
1452
        public String toString() {
1453
            return this.toString(formatter());
1454
        }
1455

    
1456
        @Override
1457
        public String toString(Formatter<Value> formatter) {
1458
            if (formatter!=null && formatter.canApply(this)) {
1459
                return formatter.format(this);
1460
            }
1461
            StringBuilder builder = new StringBuilder();
1462
            if (!this.isValid(builder)) {
1463
                throw new IllegalStateException(builder.toString());
1464
            }
1465
            builder.append("SELECT ");
1466
            if (this.distinct) {
1467
                builder.append("DISTINCT ");
1468
            }
1469
            boolean first = true;
1470
            for (SelectColumnBuilder column : columns) {
1471
                if (first) {
1472
                    first = false;
1473
                } else {
1474
                    builder.append(", ");
1475
                }
1476
                builder.append(column.toString(formatter));
1477
            }
1478

    
1479
            if (this.has_from()) {
1480
                builder.append(" FROM ");
1481
                builder.append(this.from.toString(formatter));
1482
            }
1483
            if (this.has_where()) {
1484
                builder.append(" WHERE ");
1485
                builder.append(this.where.toString(formatter));
1486
            }
1487
            if( this.has_group_by() ) {
1488
                builder.append(" GROUP BY ");
1489
                builder.append(this.groupColumn.get(0).toString(formatter));
1490
                for (int i = 1; i < groupColumn.size(); i++) {
1491
                    builder.append(", ");
1492
                    builder.append(this.groupColumn.get(i).toString(formatter));
1493
                }
1494
            }
1495
            if (this.has_order_by()) {
1496
                builder.append(" ORDER BY ");
1497
                first = true;
1498
                for (OrderByBuilder item : this.order_by) {
1499
                    if (first) {
1500
                        first = false;
1501
                    } else {
1502
                        builder.append(", ");
1503
                    }
1504
                    builder.append(item.toString(formatter));
1505
                }
1506
            }
1507

    
1508
            if (this.has_limit()) {
1509
                builder.append(" LIMIT ");
1510
                builder.append(this.limit);
1511
            }
1512
            if (this.has_offset()) {
1513
                builder.append(" OFFSET ");
1514
                builder.append(this.offset);
1515
            }
1516
            return builder.toString();
1517

    
1518
        }
1519
    }
1520

    
1521
    public class DropTableBuilderBase
1522
            extends AbstractStatement
1523
            implements DropTableBuilder {
1524

    
1525
        protected TableNameBuilder table;
1526

    
1527
        @Override
1528
        public TableNameBuilder table() {
1529
            if (table == null) {
1530
                table = createTableNameBuilder();
1531
            }
1532
            return table;
1533
        }
1534

    
1535
        @Override
1536
        public void accept(Visitor visitor, VisitorFilter filter) {
1537
            boolean visitChildren = true;
1538
            if (filter==null || filter.accept(this)) {
1539
                visitor.visit(this);
1540
            } else {
1541
                visitChildren = !filter.skipChildren();
1542
            }
1543
            if(visitChildren){
1544
                this.table.accept(visitor, filter);
1545
            }
1546
        }
1547

    
1548
        @Override
1549
        public String toString() {
1550
            return this.toString(formatter());
1551
        }
1552

    
1553
        @Override
1554
        public String toString(Formatter<Value> formatter) {
1555
            if (formatter!=null && formatter.canApply(this)) {
1556
                return formatter.format(this);
1557
            }
1558
            StringBuilder builder = new StringBuilder();
1559
            boolean first = true;
1560
            for (String sql : toStrings(formatter)) {
1561
                if (StringUtils.isEmpty(sql)) {
1562
                    continue;
1563
                }
1564
                if (first) {
1565
                    first = false;
1566
                } else {
1567
                    builder.append("; ");
1568
                }
1569
                builder.append(sql);
1570
            }
1571
            return builder.toString();
1572
        }
1573

    
1574
        @Override
1575
        public List<String> toStrings() {
1576
            return this.toStrings(formatter());
1577
        }
1578

    
1579
        @Override
1580
        public List<String> toStrings(Formatter formatter) {
1581
            List<String> sqls = new ArrayList<>();
1582

    
1583
            sqls.add(
1584
                    MessageFormat.format(
1585
                            STMT_DROP_TABLE_table,
1586
                            this.table.toString(formatter)
1587
                    )
1588
            );
1589
            String sql;
1590
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1591
                if (this.table.has_schema()) {
1592
                    sql = MessageFormat.format(
1593
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1594
                            as_string(this.table.getSchema()),
1595
                            as_string(this.table.getName())
1596
                    );
1597
                } else {
1598
                    sql = MessageFormat.format(
1599
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1600
                            as_identifier(this.table.getName())
1601
                    );
1602
                }
1603
                if (!StringUtils.isEmpty(sql)) {
1604
                    sqls.add(sql);
1605
                }
1606
            }
1607
            return sqls;
1608
        }
1609
    }
1610

    
1611
    public class GrantRoleBuilderBase
1612
            extends AbstractStatementPart
1613
            implements GrantRoleBuilder {
1614

    
1615
        protected TableNameBuilder table;
1616
        protected String role;
1617
        protected Set<Privilege> privileges;
1618

    
1619
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1620
            this.table = table;
1621
            this.role = role;
1622
            this.privileges = new HashSet<>();
1623
        }
1624
        
1625
        @Override
1626
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1627
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1628
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1629
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1630
            
1631
            return other;
1632
        }
1633

    
1634
        @Override
1635
        public GrantRoleBuilder privilege(Privilege privilege) {
1636
            privileges.add(privilege);
1637
            return this;
1638
        }
1639

    
1640
        @Override
1641
        public GrantRoleBuilder select() {
1642
            privileges.add(Privilege.SELECT);
1643
            return this;
1644
        }
1645

    
1646
        @Override
1647
        public GrantRoleBuilder update() {
1648
            privileges.add(Privilege.UPDATE);
1649
            return this;
1650
        }
1651

    
1652
        @Override
1653
        public GrantRoleBuilder insert() {
1654
            privileges.add(Privilege.INSERT);
1655
            return this;
1656
        }
1657

    
1658
        @Override
1659
        public GrantRoleBuilder delete() {
1660
            privileges.add(Privilege.DELETE);
1661
            return this;
1662
        }
1663

    
1664
        @Override
1665
        public GrantRoleBuilder truncate() {
1666
            privileges.add(Privilege.TRUNCATE);
1667
            return this;
1668
        }
1669

    
1670
        @Override
1671
        public GrantRoleBuilder reference() {
1672
            privileges.add(Privilege.REFERENCE);
1673
            return this;
1674
        }
1675

    
1676
        @Override
1677
        public GrantRoleBuilder trigger() {
1678
            privileges.add(Privilege.TRIGGER);
1679
            return this;
1680
        }
1681

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

    
1688
        protected String getPrivilegeName(Privilege privilege) {
1689
            switch (privilege) {
1690
                case DELETE:
1691
                    return "DELETE";
1692
                case INSERT:
1693
                    return "INSERT";
1694
                case REFERENCE:
1695
                    return "REFERENCE";
1696
                case SELECT:
1697
                    return "SELECT";
1698
                case TRIGGER:
1699
                    return "TRIGGER";
1700
                case TRUNCATE:
1701
                    return "TRUNCATE";
1702
                case UPDATE:
1703
                    return "UPDATE";
1704
                case ALL:
1705
                default:
1706
                    return "ALL";
1707
            }
1708
        }
1709

    
1710
        @Override
1711
        public String toString() {
1712
            return this.toString(formatter());
1713
        }
1714

    
1715
        @Override
1716
        public String toString(Formatter<Value> formatter) {
1717
            if (formatter!=null && formatter.canApply(this)) {
1718
                return formatter.format(this);
1719
            }
1720
            StringBuilder builder = new StringBuilder();
1721
            boolean first = true;
1722
            for (Privilege privilege : privileges) {
1723
                if (first) {
1724
                    first = false;
1725
                } else {
1726
                    builder.append(", ");
1727
                }
1728
                builder.append(this.getPrivilegeName(privilege));
1729
            }
1730
            String sql = MessageFormat.format(
1731
                    STMT_GRANT_privileges_ON_table_TO_role,
1732
                    builder.toString(),
1733
                    table.toString(formatter),
1734
                    role
1735
            );
1736
            return sql;
1737
        }
1738
    }
1739

    
1740
    public class GrantBuilderBase
1741
            extends AbstractStatement
1742
            implements GrantBuilder {
1743

    
1744
        protected TableNameBuilder table;
1745
        protected Map<String, GrantRoleBuilder> roles;
1746

    
1747
        public GrantBuilderBase() {
1748
            this.roles = new HashMap<>();
1749
        }
1750

    
1751
        @Override
1752
        public TableNameBuilder table() {
1753
            if (table == null) {
1754
                table = createTableNameBuilder();
1755
            }
1756
            return table;
1757
        }
1758

    
1759
        @Override
1760
        public void accept(Visitor visitor, VisitorFilter filter) {
1761
            boolean visitChildren = true;
1762
            if (filter==null || filter.accept(this)) {
1763
                visitor.visit(this);
1764
            } else {
1765
                visitChildren = !filter.skipChildren();
1766
            }
1767
            if(visitChildren){
1768
                if (this.table != null) {
1769
                    this.table.accept(visitor, filter);
1770
                }
1771
            }
1772
        }
1773

    
1774
        @Override
1775
        public GrantRoleBuilder role(String role) {
1776
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1777
            if (roleBuilder == null) {
1778
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1779
                this.roles.put(role, roleBuilder);
1780
            }
1781
            return roleBuilder;
1782
        }
1783

    
1784
        @Override
1785
        public String toString() {
1786
            return this.toString(formatter());
1787
        }
1788

    
1789
        @Override
1790
        public String toString(Formatter<Value> formatter) {
1791
            if (formatter!=null && formatter.canApply(this)) {
1792
                return formatter.format(this);
1793
            }
1794
            StringBuilder builder = new StringBuilder();
1795
            boolean first = true;
1796
            for (String sql : toStrings(formatter)) {
1797
                if (StringUtils.isEmpty(sql)) {
1798
                    continue;
1799
                }
1800
                if (first) {
1801
                    first = false;
1802
                } else {
1803
                    builder.append("; ");
1804
                }
1805
                builder.append(sql);
1806
            }
1807
            return builder.toString();
1808
        }
1809

    
1810
        @Override
1811
        public List<String> toStrings() {
1812
            return this.toStrings(formatter());
1813
        }
1814

    
1815
        @Override
1816
        public List<String> toStrings(Formatter formatter) {
1817
            List<String> sqls = new ArrayList<>();
1818
            for (GrantRoleBuilder role : roles.values()) {
1819
                sqls.add(role.toString(formatter));
1820
            }
1821
            return sqls;
1822
        }
1823
    }
1824

    
1825
    public class UpdateColumnBuilderBase
1826
            extends InsertColumnBuilderBase
1827
            implements UpdateColumnBuilder {
1828

    
1829
        public UpdateColumnBuilderBase() {
1830
            super();
1831
        }
1832

    
1833
        @Override
1834
        public UpdateColumnBuilder name(String name) {
1835
            return (UpdateColumnBuilder) super.name(name);
1836
        }
1837

    
1838
        @Override
1839
        public UpdateColumnBuilder with_value(Value value) {
1840
            return (UpdateColumnBuilder) super.with_value(value);
1841
        }
1842

    
1843
    }
1844

    
1845
    public class UpdateBuilderBase
1846
            extends AbstractStatement
1847
            implements UpdateBuilder {
1848

    
1849
        protected GeometryExpressionBuilder where;
1850
        protected List<UpdateColumnBuilder> columns;
1851
        protected TableNameBuilder table;
1852

    
1853
        public UpdateBuilderBase() {
1854
            this.columns = new ArrayList<>();
1855
        }
1856

    
1857
        @Override
1858
        public void accept(Visitor visitor, VisitorFilter filter) {
1859
            boolean visitChildren = true;
1860
            if (filter==null || filter.accept(this)) {
1861
                visitor.visit(this);
1862
            } else {
1863
                visitChildren = !filter.skipChildren();
1864
            }
1865
            if(visitChildren){
1866
                if (this.table != null) {
1867
                    this.table.accept(visitor, filter);
1868
                }
1869
                for (UpdateColumnBuilder column : columns) {
1870
                    column.accept(visitor, filter);
1871
                }
1872
                if (this.has_where()) {
1873
                    this.where.accept(visitor, filter);
1874
                }
1875
            }
1876
        }
1877

    
1878
        @Override
1879
        public GeometryExpressionBuilder where() {
1880
            if (this.where == null) {
1881
                this.where = createExpressionBuilder();
1882
            }
1883
            return this.where;
1884
        }
1885

    
1886
        @Override
1887
        public TableNameBuilder table() {
1888
            if (table == null) {
1889
                table = createTableNameBuilder();
1890
            }
1891
            return table;
1892
        }
1893

    
1894
        @Override
1895
        public UpdateColumnBuilder column() {
1896
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1897
            this.columns.add(column);
1898
            return column;
1899
        }
1900

    
1901
        @Override
1902
        public boolean has_where() {
1903
            return this.where != null;
1904
        }
1905

    
1906
        @Override
1907
        public String toString() {
1908
            return this.toString(formatter());
1909
        }
1910

    
1911
        @Override
1912
        public String toString(Formatter<Value> formatter) {
1913
            if (formatter!=null && formatter.canApply(this)) {
1914
                return formatter.format(this);
1915
            }
1916
            /*
1917
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1918
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1919
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1920
             * output_expression [ AS output_name ] [, ...] ]
1921
             */
1922
            StringBuilder columnsAndValues = new StringBuilder();
1923

    
1924
            boolean first = true;
1925
            for (UpdateColumnBuilder column : columns) {
1926
                if (first) {
1927
                    first = false;
1928
                } else {
1929
                    columnsAndValues.append(", ");
1930
                }
1931
                columnsAndValues.append(as_identifier(column.getName()));
1932
                columnsAndValues.append(" = ");
1933
                columnsAndValues.append(column.getValue().toString(formatter));
1934
            }
1935

    
1936
            String sql;
1937
            if (this.has_where()) {
1938
                sql = MessageFormat.format(
1939
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1940
                        this.table.toString(formatter),
1941
                        columnsAndValues.toString(),
1942
                        this.where.toString(formatter)
1943
                );
1944
            } else {
1945
                sql = MessageFormat.format(
1946
                        STMT_UPDATE_table_SET_columnsAndValues,
1947
                        this.table.toString(formatter),
1948
                        columnsAndValues.toString()
1949
                );
1950
            }
1951
            return sql;
1952
        }
1953
    }
1954

    
1955
    public class DeleteBuilderBase
1956
            extends AbstractStatement
1957
            implements DeleteBuilder {
1958

    
1959
        protected GeometryExpressionBuilder where;
1960
        protected TableNameBuilder table;
1961

    
1962
        public DeleteBuilderBase() {
1963
        }
1964

    
1965
        @Override
1966
        public void accept(Visitor visitor, VisitorFilter filter) {
1967
            boolean visitChildren = true;
1968
            if (filter==null || filter.accept(this)) {
1969
                visitor.visit(this);
1970
            } else {
1971
                visitChildren = !filter.skipChildren();
1972
            }
1973
            if(visitChildren){
1974
                if (this.table != null) {
1975
                    this.table.accept(visitor, filter);
1976
                }
1977
                if (this.has_where()) {
1978
                    this.where.accept(visitor, filter);
1979
                }
1980
            }
1981
        }
1982

    
1983
        @Override
1984
        public GeometryExpressionBuilder where() {
1985
            if (this.where == null) {
1986
                this.where = createExpressionBuilder();
1987
            }
1988
            return this.where;
1989
        }
1990

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

    
1999
        @Override
2000
        public boolean has_where() {
2001
            return this.where != null;
2002
        }
2003

    
2004
        @Override
2005
        public String toString() {
2006
            return this.toString(formatter());
2007
        }
2008

    
2009
        @Override
2010
        public String toString(Formatter<Value> formatter) {
2011
            if (formatter!=null && formatter.canApply(this)) {
2012
                return formatter.format(this);
2013
            }
2014
            /*
2015
             * DELETE FROM table_name
2016
             * WHERE some_column=some_value; 
2017
             */
2018
            String sql;
2019
            if (this.has_where()) {
2020
                sql = MessageFormat.format(
2021
                        STMT_DELETE_FROM_table_WHERE_expresion,
2022
                        this.table.toString(formatter),
2023
                        this.where.toString(formatter)
2024
                );
2025
            } else {
2026
                sql = MessageFormat.format(
2027
                        STMT_DELETE_FROM_table,
2028
                        this.table.toString(formatter)
2029
                );
2030
            }
2031
            return sql;
2032
        }
2033
    }
2034

    
2035
    public class CreateIndexBuilderBase
2036
            extends AbstractStatement
2037
            implements CreateIndexBuilder {
2038

    
2039
        protected boolean ifNotExist = false;
2040
        protected boolean isUnique = false;
2041
        protected String indexName;
2042
        protected boolean isSpatial = false;
2043
        protected TableNameBuilder table;
2044
        protected final List<String> columns;
2045

    
2046
        public CreateIndexBuilderBase() {
2047
            this.columns = new ArrayList<>();
2048
        }
2049

    
2050
        @Override
2051
        public CreateIndexBuilder unique() {
2052
            this.isUnique = true;
2053
            return this;
2054
        }
2055

    
2056
        @Override
2057
        public CreateIndexBuilder if_not_exist() {
2058
            this.ifNotExist = true;
2059
            return this;
2060
        }
2061

    
2062
        @Override
2063
        public CreateIndexBuilder name(String name) {
2064
            this.indexName = name;
2065
            return this;
2066
        }
2067

    
2068
        @Override
2069
        public CreateIndexBuilder name(String tableName, String columnName) {
2070
            this.indexName = tableName + "_IDX_" + columnName;
2071
            return this;
2072
        }
2073

    
2074
        @Override
2075
        public CreateIndexBuilder spatial() {
2076
            this.isSpatial = true;
2077
            return this;
2078
        }
2079

    
2080
        @Override
2081
        public CreateIndexBuilder column(String name) {
2082
            this.columns.add(name);
2083
            return this;
2084
        }
2085

    
2086
        @Override
2087
        public TableNameBuilder table() {
2088
            if (table == null) {
2089
                table = createTableNameBuilder();
2090
            }
2091
            return table;
2092
        }
2093

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

    
2109
        @Override
2110
        public String toString() {
2111
            return this.toString(formatter());
2112
        }
2113

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

    
2135
        @Override
2136
        public List<String> toStrings() {
2137
            return this.toStrings(formatter());
2138
        }
2139

    
2140
        @Override
2141
        public List<String> toStrings(Formatter formatter) {
2142
            StringBuilder builder = new StringBuilder();
2143
            builder.append("CREATE ");
2144
            if (this.isUnique) {
2145
                builder.append("UNIQUE ");
2146
            }
2147
            builder.append("INDEX ");
2148
            if (this.ifNotExist) {
2149
                builder.append("IF NOT EXISTS ");
2150
            }
2151
            builder.append(as_identifier(this.indexName));
2152
            builder.append(" ON ");
2153
            builder.append(this.table.toString(formatter));
2154
            if (this.isSpatial) {
2155
                builder.append(" USING GIST ");
2156
            }
2157
            builder.append(" ( ");
2158
            boolean is_first_column = true;
2159
            for (String column : this.columns) {
2160
                if (is_first_column) {
2161
                    is_first_column = false;
2162
                } else {
2163
                    builder.append(", ");
2164
                }
2165
                builder.append(column);
2166
            }
2167
            builder.append(" )");
2168

    
2169
            List<String> sqls = new ArrayList<>();
2170
            sqls.add(builder.toString());
2171
            return sqls;
2172
        }
2173

    
2174
    }
2175

    
2176
    public class DropIndexBuilderBase
2177
            extends AbstractStatement
2178
            implements DropIndexBuilder {
2179

    
2180
        protected boolean ifNotExist = false;
2181
        protected String indexName;
2182

    
2183
        public DropIndexBuilderBase() {
2184
        }
2185

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

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

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

    
2204
        @Override
2205
        public String toString() {
2206
            return this.toString(formatter());
2207
        }
2208

    
2209
        @Override
2210
        public String toString(Formatter<Value> formatter) {
2211
            if (formatter!=null && formatter.canApply(this)) {
2212
                return formatter.format(this);
2213
            }
2214
            StringBuilder builder = new StringBuilder();
2215
            boolean first = true;
2216
            for (String sql : toStrings(formatter)) {
2217
                if (StringUtils.isEmpty(sql)) {
2218
                    continue;
2219
                }
2220
                if (first) {
2221
                    first = false;
2222
                } else {
2223
                    builder.append("; ");
2224
                }
2225
                builder.append(sql);
2226
            }
2227
            return builder.toString();
2228
        }
2229

    
2230
        @Override
2231
        public List<String> toStrings() {
2232
            return this.toStrings(formatter());
2233
        }
2234

    
2235
        @Override
2236
        public List<String> toStrings(Formatter formatter) {
2237
            StringBuilder builder = new StringBuilder();
2238
            builder.append("DROP INDEX ");
2239
            if (this.ifNotExist) {
2240
                builder.append("IF NOT EXISTS ");
2241
            }
2242
            builder.append(as_identifier(this.indexName));
2243
            List<String> sqls = new ArrayList<>();
2244
            sqls.add(builder.toString());
2245
            return sqls;
2246
        }
2247

    
2248
    }
2249

    
2250
    public class AlterTableBuilderBase
2251
            extends AbstractStatement
2252
            implements AlterTableBuilder {
2253

    
2254
        protected TableNameBuilder table;
2255
        protected List<String> drops;
2256
        protected List<ColumnDescriptor> adds;
2257
        protected List<ColumnDescriptor> alters;
2258
        protected List<Pair<String, String>> renames;
2259
        protected String drop_primary_key_column;
2260

    
2261
        public AlterTableBuilderBase() {
2262
            this.drops = new ArrayList<>();
2263
            this.adds = new ArrayList<>();
2264
            this.alters = new ArrayList<>();
2265
            this.renames = new ArrayList<>();
2266
        }
2267

    
2268
        @Override
2269
        public boolean isEmpty() {
2270
            return this.drops.isEmpty()
2271
                    && this.adds.isEmpty()
2272
                    && this.alters.isEmpty()
2273
                    && this.renames.isEmpty();
2274
        }
2275

    
2276
        @Override
2277
        public void accept(Visitor visitor, VisitorFilter filter) {
2278
            boolean visitChildren = true;
2279
            if (filter==null || filter.accept(this)) {
2280
                visitor.visit(this);
2281
            } else {
2282
                visitChildren = !filter.skipChildren();
2283
            }
2284
            if(visitChildren){
2285
                if (this.table != null) {
2286
                    this.table.accept(visitor, filter);
2287
                }
2288
            }
2289
        }
2290

    
2291
        @Override
2292
        public TableNameBuilder table() {
2293
            if (table == null) {
2294
                table = createTableNameBuilder();
2295
            }
2296
            return table;
2297
        }
2298

    
2299
        @Override
2300
        public AlterTableBuilder drop_column(String columnName) {
2301
            this.drops.add(columnName);
2302
            return this;
2303
        }
2304

    
2305
        @Override
2306
        public AlterTableBuilder drop_primary_key(String columnName) {
2307
            this.drop_primary_key_column = columnName;
2308
            return this;
2309
        }
2310

    
2311
        @Override
2312
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2313
            this.adds.add(new ColumnDescriptorBase(fad));
2314
            return this;
2315
        }
2316

    
2317
        @Override
2318
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2319
            if (isPk || isAutomatic) {
2320
                allowNulls = false;
2321
            }
2322
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2323
            return this;
2324
        }
2325

    
2326
        @Override
2327
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2328
            if (StringUtils.isEmpty(columnName)) {
2329
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2330
            }
2331
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2332
            return this;
2333
        }
2334

    
2335
        @Override
2336
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2337
            if (StringUtils.isEmpty(columnName)) {
2338
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2339
            }
2340
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2341
            return this;
2342
        }
2343

    
2344
        @Override
2345
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2346
            this.alters.add(new ColumnDescriptorBase(fad));
2347
            return this;
2348
        }
2349

    
2350
        @Override
2351
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2352
            if (isPk || isAutomatic) {
2353
                allowNulls = false;
2354
            }
2355
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2356
            return this;
2357
        }
2358

    
2359
        @Override
2360
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2361
            if (StringUtils.isEmpty(columnName)) {
2362
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2363
            }
2364
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2365
            return this;
2366
        }
2367

    
2368
        @Override
2369
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2370
            if (StringUtils.isEmpty(columnName)) {
2371
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2372
            }
2373
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2374
            return this;
2375
        }
2376

    
2377
        @Override
2378
        public AlterTableBuilder rename_column(String source, String target) {
2379
            this.renames.add(new ImmutablePair(source, target));
2380
            return this;
2381
        }
2382

    
2383
        protected String getConstrainName(String constrainType, String columnName) {
2384
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2385
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2386
            return constraint_name;
2387
        }
2388

    
2389
        @Override
2390
        public String toString() {
2391
            return this.toString(formatter());
2392
        }
2393

    
2394
        @Override
2395
        public String toString(Formatter<Value> formatter) {
2396
            if (formatter!=null && formatter.canApply(this)) {
2397
                return formatter.format(this);
2398
            }
2399
            StringBuilder builder = new StringBuilder();
2400
            boolean first = true;
2401
            for (String sql : toStrings(formatter)) {
2402
                if (StringUtils.isEmpty(sql)) {
2403
                    continue;
2404
                }
2405
                if (first) {
2406
                    first = false;
2407
                } else {
2408
                    builder.append("; ");
2409
                }
2410
                builder.append(sql);
2411
            }
2412
            return builder.toString();
2413
        }
2414

    
2415
        @Override
2416
        public List<String> toStrings() {
2417
            return this.toStrings(formatter());
2418
        }
2419

    
2420
        @Override
2421
        public List<String> toStrings(Formatter formatter) {
2422
            List<String> sqls = new ArrayList<>();
2423
            if (this.isEmpty()) {
2424
                return sqls;
2425
            }
2426
            for (String column : drops) {
2427
                StringBuilder builder = new StringBuilder();
2428
                builder.append("ALTER TABLE ");
2429
                builder.append(this.table.toString(formatter));
2430
                builder.append(" DROP COLUMN IF EXISTS ");
2431
                builder.append(as_identifier(column));
2432
                sqls.add(builder.toString());
2433
            }
2434
            for (ColumnDescriptor column : adds) {
2435
                StringBuilder builder = new StringBuilder();
2436
                builder.append("ALTER TABLE ");
2437
                builder.append(this.table.toString(formatter));
2438
                builder.append(" ADD COLUMN ");
2439
                builder.append(as_identifier(column.getName()));
2440
                builder.append(" ");
2441
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2442
                    builder.append(" SERIAL");
2443
                } else {
2444
                    builder.append(
2445
                            sqltype(
2446
                                    column.getType(),
2447
                                    column.getSize(),
2448
                                    column.getPrecision(),
2449
                                    column.getScale(),
2450
                                    column.getGeometryType(),
2451
                                    column.getGeometrySubtype()
2452
                            )
2453
                    );
2454
                }
2455
                if (column.getDefaultValue() == null) {
2456
                    if (column.allowNulls()) {
2457
                        builder.append(" DEFAULT NULL");
2458
                    }
2459
                } else {
2460
                    builder.append(" DEFAULT '");
2461
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2462
                    builder.append("'");
2463
                }
2464
                if (column.allowNulls()) {
2465
                    builder.append(" NULL");
2466
                } else {
2467
                    builder.append(" NOT NULL");
2468
                }
2469
                if (column.isPrimaryKey()) {
2470
                    builder.append(" PRIMARY KEY");
2471
                }
2472
                sqls.add(builder.toString());
2473
            }
2474
            for (ColumnDescriptor column : alters) {
2475
                StringBuilder builder = new StringBuilder();
2476
                builder.append("ALTER TABLE ");
2477
                builder.append(this.table.toString(formatter));
2478
                builder.append(" ALTER COLUMN ");
2479
                builder.append(as_identifier(column.getName()));
2480
                builder.append(" SET DATA TYPE ");
2481
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2482
                    builder.append(" SERIAL");
2483
                } else {
2484
                    builder.append(
2485
                            sqltype(
2486
                                    column.getType(),
2487
                                    column.getSize(),
2488
                                    column.getPrecision(),
2489
                                    column.getScale(),
2490
                                    column.getGeometryType(),
2491
                                    column.getGeometrySubtype()
2492
                            )
2493
                    );
2494
                }
2495
                if (column.getDefaultValue() == null) {
2496
                    if (column.allowNulls()) {
2497
                        builder.append(" DEFAULT NULL");
2498
                    } else {
2499
                        builder.append(" DROP DEFAULT");
2500
                    }
2501
                } else {
2502
                    builder.append(" DEFAULT '");
2503
                    builder.append(column.getDefaultValue().toString());
2504
                    builder.append("'");
2505
                }
2506
                sqls.add(builder.toString());
2507
            }
2508
            for (Pair<String, String> pair : renames) {
2509
                StringBuilder builder = new StringBuilder();
2510
                builder.append("ALTER TABLE ");
2511
                builder.append(this.table.toString(formatter));
2512
                builder.append(" RENAME COLUMN ");
2513
                builder.append(as_identifier(pair.getLeft()));
2514
                builder.append(" TO ");
2515
                builder.append(as_identifier(pair.getRight()));
2516
                sqls.add(builder.toString());
2517
            }
2518
            return sqls;
2519
        }
2520

    
2521
    }
2522

    
2523
    public class CreateTableBuilderBase
2524
            extends AbstractStatement
2525
            implements CreateTableBuilder {
2526

    
2527
        protected TableNameBuilder table;
2528
        protected List<ColumnDescriptor> columns;
2529

    
2530
        public CreateTableBuilderBase() {
2531
            this.columns = new ArrayList<>();
2532
        }
2533

    
2534
        @Override
2535
        public void accept(Visitor visitor, VisitorFilter filter) {
2536
            boolean visitChildren = true;
2537
            if (filter==null || filter.accept(this)) {
2538
                visitor.visit(this);
2539
            } else {
2540
                visitChildren = !filter.skipChildren();
2541
            }
2542
            if(visitChildren){
2543
                if (this.table != null) {
2544
                    this.table.accept(visitor, filter);
2545
                }
2546
            }
2547
        }
2548

    
2549
        @Override
2550
        public TableNameBuilder table() {
2551
            if (table == null) {
2552
                table = createTableNameBuilder();
2553
            }
2554
            return table;
2555
        }
2556

    
2557
        @Override
2558
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2559
            this.columns.add(new ColumnDescriptorBase(fad));
2560
            return this;
2561
        }
2562

    
2563
        @Override
2564
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2565
            if (StringUtils.isEmpty(columnName)) {
2566
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2567
            }
2568
            if (isPk || isAutomatic) {
2569
                allowNulls = false;
2570
            }
2571
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2572
            return this;
2573
        }
2574

    
2575
        @Override
2576
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2577
            if (StringUtils.isEmpty(columnName)) {
2578
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2579
            }
2580
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2581
            return this;
2582
        }
2583

    
2584
        @Override
2585
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2586
            if (StringUtils.isEmpty(columnName)) {
2587
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2588
            }
2589
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2590
            return this;
2591
        }
2592

    
2593
        @Override
2594
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2595
            if (StringUtils.isEmpty(columnName)) {
2596
                return null;
2597
            }
2598
            for (ColumnDescriptor column : columns) {
2599
                if (columnName.equals(column.getName())) {
2600
                    return column;
2601
                }
2602
            }
2603
            return null;
2604
        }
2605

    
2606
        @Override
2607
        public String toString() {
2608
            return this.toString(formatter());
2609
        }
2610

    
2611
        @Override
2612
        public String toString(Formatter<Value> formatter) {
2613
            if (formatter!=null && formatter.canApply(this)) {
2614
                return formatter.format(this);
2615
            }
2616
            StringBuilder builder = new StringBuilder();
2617
            boolean first = true;
2618
            for (String sql : toStrings(formatter)) {
2619
                if (StringUtils.isEmpty(sql)) {
2620
                    continue;
2621
                }
2622
                if (first) {
2623
                    first = false;
2624
                } else {
2625
                    builder.append("; ");
2626
                }
2627
                builder.append(sql);
2628
            }
2629
            return builder.toString();
2630
        }
2631

    
2632
        @Override
2633
        public List<String> toStrings() {
2634
            return this.toStrings(formatter());
2635
        }
2636

    
2637
        @Override
2638
        /*
2639
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
2640
        */
2641
        public List<String> toStrings(Formatter formatter) {
2642
            List<String> sqls = new ArrayList<>();
2643
            /**
2644
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2645
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2646
             * column_constraint [ ... ] ] | table_constraint | LIKE
2647
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2648
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2649
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2650
             *
2651
             * where column_constraint is:
2652
             *
2653
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2654
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2655
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2656
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2657
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2658
             *
2659
             * and table_constraint is:
2660
             *
2661
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2662
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2663
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2664
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2665
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2666
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2667
             */
2668
            
2669
            StringBuilder builder = new StringBuilder();
2670

    
2671
            builder.append("CREATE TABLE ");
2672
            builder.append(this.table.toString(formatter));
2673
            builder.append(" (");
2674
            boolean first = true;
2675
            for (ColumnDescriptor column : columns) {
2676
                if (first) {
2677
                    first = false;
2678
                } else {
2679
                    builder.append(", ");
2680
                }
2681
                builder.append(as_identifier(column.getName()));
2682
                builder.append(" ");
2683
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2684
                    builder.append("SERIAL");
2685
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2686
                    builder.append("BIGSERIAL");
2687
                } else {
2688
                    builder.append(sqltype(
2689
                            column.getType(),
2690
                            column.getSize(),
2691
                            column.getPrecision(),
2692
                            column.getScale(),
2693
                            column.getGeometryType(),
2694
                            column.getGeometrySubtype()
2695
                    )
2696
                    );
2697
                }
2698
                if (column.getDefaultValue() == null) {
2699
                    if (column.allowNulls()) {
2700
                        builder.append(" DEFAULT NULL");
2701
                    }
2702
                } else {
2703
                    builder.append(" DEFAULT '");
2704
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2705
                    builder.append("'");
2706
                }
2707
                if (column.allowNulls()) {
2708
                    builder.append(" NULL");
2709
                } else {
2710
                    builder.append(" NOT NULL");
2711
                }
2712
                if (column.isPrimaryKey()) {
2713
                    builder.append(" PRIMARY KEY");
2714
                }
2715
            }
2716
            builder.append(" )");
2717
            sqls.add(builder.toString());
2718
            return sqls;
2719
        }
2720
    }
2721

    
2722
    public class InsertColumnBuilderBase
2723
            extends AbstractStatement
2724
            implements InsertColumnBuilder {
2725

    
2726
        protected Variable name;
2727
        protected Value value;
2728

    
2729
        public InsertColumnBuilderBase() {
2730
        }
2731

    
2732
        @Override
2733
        public void accept(Visitor visitor, VisitorFilter filter) {
2734
            boolean visitChildren = true;
2735
            if (filter==null || filter.accept(this)) {
2736
                visitor.visit(this);
2737
            } else {
2738
                visitChildren = !filter.skipChildren();
2739
            }
2740
            if(visitChildren){
2741
                if (this.name != null) {
2742
                    this.name.accept(visitor, filter);
2743
                }
2744
                if (this.value != null) {
2745
                    this.value.accept(visitor, filter);
2746
                }
2747
            }
2748
        }
2749

    
2750
        @Override
2751
        public InsertColumnBuilder name(String name) {
2752
            this.name = expression().variable(name);
2753
            return this;
2754
        }
2755

    
2756
        @Override
2757
        public InsertColumnBuilder with_value(Value value) {
2758
            this.value = value;
2759
            return this;
2760
        }
2761

    
2762
        @Override
2763
        public String getName() {
2764
            return this.name.name();
2765
        }
2766

    
2767
        @Override
2768
        public Value getValue() {
2769
            return this.value;
2770
        }
2771

    
2772
        @Override
2773
        public String toString() {
2774
            return this.toString(formatter());
2775
        }
2776

    
2777
        @Override
2778
        public String toString(Formatter<Value> formatter) {
2779
            if (formatter!=null && formatter.canApply(this)) {
2780
                return formatter.format(this);
2781
            }
2782
            return this.value.toString(formatter);
2783
        }
2784
    }
2785

    
2786
    public class InsertBuilderBase
2787
            extends AbstractStatement
2788
            implements InsertBuilder {
2789

    
2790
        protected List<InsertColumnBuilder> columns;
2791
        protected TableNameBuilder table;
2792

    
2793
        public InsertBuilderBase() {
2794
            this.columns = new ArrayList<>();
2795
        }
2796

    
2797
        @Override
2798
        public void accept(Visitor visitor, VisitorFilter filter) {
2799
            boolean visitChildren = true;
2800
            if (filter==null || filter.accept(this)) {
2801
                visitor.visit(this);
2802
            } else {
2803
                visitChildren = !filter.skipChildren();
2804
            }
2805
            if(visitChildren){
2806
                if (this.table != null) {
2807
                    this.table.accept(visitor, filter);
2808
                }
2809
                for (InsertColumnBuilder column : columns) {
2810
                    column.accept(visitor, filter);
2811
                }
2812
            }
2813
        }
2814

    
2815
        @Override
2816
        public TableNameBuilder table() {
2817
            if (table == null) {
2818
                table = createTableNameBuilder();
2819
            }
2820
            return table;
2821
        }
2822

    
2823
        @Override
2824
        public InsertColumnBuilder column() {
2825
            InsertColumnBuilder column = createInsertColumnBuilder();
2826
            this.columns.add(column);
2827
            return column;
2828
        }
2829

    
2830
        @Override
2831
        public String toString() {
2832
            return this.toString(formatter());
2833
        }
2834

    
2835
        @Override
2836
        public String toString(Formatter<Value> formatter) {
2837
            if (formatter!=null && formatter.canApply(this)) {
2838
                return formatter.format(this);
2839
            }
2840
            /*
2841
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2842
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2843
             * output_expression [ AS output_name ] [, ...] ]
2844
             */
2845
            StringBuilder builderColumns = new StringBuilder();
2846
            StringBuilder builderValues = new StringBuilder();
2847

    
2848
            boolean first = true;
2849
            for (InsertColumnBuilder column : columns) {
2850
                if (first) {
2851
                    first = false;
2852
                } else {
2853
                    builderColumns.append(", ");
2854
                }
2855
                builderColumns.append(as_identifier(column.getName()));
2856
            }
2857
            first = true;
2858
            for (InsertColumnBuilder column : columns) {
2859
                if (first) {
2860
                    first = false;
2861
                } else {
2862
                    builderValues.append(", ");
2863
                }
2864
                builderValues.append(column.toString(formatter));
2865
            }
2866

    
2867
            String sql = MessageFormat.format(
2868
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2869
                    this.table.toString(formatter),
2870
                    builderColumns.toString(),
2871
                    builderValues.toString()
2872
            );
2873
            return sql;
2874

    
2875
        }
2876
    }
2877

    
2878
    public class UpdateTableStatisticsBuilderBase
2879
            extends AbstractStatement
2880
            implements UpdateTableStatisticsBuilder {
2881

    
2882
        protected TableNameBuilder table;
2883

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

    
2899
        @Override
2900
        public TableNameBuilder table() {
2901
            if (table == null) {
2902
                table = createTableNameBuilder();
2903
            }
2904
            return table;
2905
        }
2906

    
2907
        @Override
2908
        public String toString() {
2909
            return this.toString(formatter());
2910
        }
2911

    
2912
        @Override
2913
        public String toString(Formatter<Value> formatter) {
2914
            if (formatter!=null && formatter.canApply(this)) {
2915
                return formatter.format(this);
2916
            }
2917
            StringBuilder builder = new StringBuilder();
2918
            boolean first = true;
2919
            for (String sql : toStrings(formatter)) {
2920
                if (StringUtils.isEmpty(sql)) {
2921
                    continue;
2922
                }
2923
                if (first) {
2924
                    first = false;
2925
                } else {
2926
                    builder.append("; ");
2927
                }
2928
                builder.append(sql);
2929
            }
2930
            return builder.toString();
2931
        }
2932

    
2933
        @Override
2934
        public List<String> toStrings() {
2935
            return this.toStrings(formatter());
2936
        }
2937

    
2938
        @Override
2939
        public List<String> toStrings(Formatter formatter) {
2940
            List<String> sqls = new ArrayList<>();
2941

    
2942
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2943
                String sql = MessageFormat.format(
2944
                        STMT_UPDATE_TABLE_STATISTICS_table,
2945
                        table.toString(formatter)
2946
                );
2947
                if (!StringUtils.isEmpty(sql)) {
2948
                    sqls.add(sql);
2949
                }
2950
            }
2951
            return sqls;
2952
        }
2953
    }
2954

    
2955
    protected GeometryExpressionBuilder expressionBuilder;
2956

    
2957
    protected String defaultSchema;
2958
    protected boolean supportSchemas;
2959
    protected boolean hasSpatialFunctions;
2960
    protected GeometrySupportType geometrySupportType;
2961
    protected boolean allowAutomaticValues;
2962

    
2963
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2964

    
2965
    protected String constant_true = "(1=1)";
2966
    protected String constant_false = "(1<>1)";
2967

    
2968
    protected String type_boolean = "BOOLEAN";
2969
    protected String type_byte = "TINYINT";
2970
    protected String type_bytearray = "BYTEA";
2971
    protected String type_geometry = "TEXT";
2972
    protected String type_char = "CHARACTER(1)";
2973
    protected String type_date = "DATE";
2974
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2975
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2976
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2977
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2978
    protected String type_int = "INT";
2979
    protected String type_long = "BIGINT";
2980
    protected String type_string = "TEXT";
2981
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2982
    protected String type_time = "TIME";
2983
    protected String type_timestamp = "TIMESTAMP";
2984
    protected String type_version = "VARCHAR(30)";
2985
    protected String type_URI = "TEXT";
2986
    protected String type_URL = "TEXT";
2987
    protected String type_FILE = "TEXT";
2988
    protected String type_FOLDER = "TEXT";
2989

    
2990
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2991
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2992
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2993
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2994
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2995
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2996
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2997
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2998
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2999
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3000

    
3001
    public SQLBuilderBase() {
3002
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3003
        this.expressionBuilder.setProperty("SQLBUILDER", this);
3004

    
3005
        this.hasSpatialFunctions = false;
3006
        this.supportSchemas = true;
3007
        this.geometrySupportType = GeometrySupportType.WKT;
3008

    
3009
        this.defaultSchema = "public";
3010
        this.allowAutomaticValues = true;
3011

    
3012
    }
3013
    
3014
    @Override
3015
    public void setProperties(Class filter, final Object... values) {
3016
        this.expressionBuilder.setProperties(filter, values);
3017
        setProperties(this, filter, values);
3018
    }
3019
    
3020
    @Override
3021
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3022
        if(visitable == null){
3023
            return;
3024
        }
3025
        if(visitable instanceof PropertiesSupport){
3026
            for (int i = 0; i < values.length; i+=2) {
3027
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3028
            }
3029
        }
3030
        visitable.accept((Visitable v) -> {
3031
            if(v instanceof PropertiesSupport){
3032
                for (int i = 0; i < values.length; i+=2) {
3033
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3034
                }
3035
            }
3036
        }, new ClassVisitorFilter(filter) );
3037
    }
3038

    
3039
    public String quote_for_identifiers() {
3040
        return "\"";
3041
    }
3042

    
3043
    public String quote_for_strings() {
3044
        return "'";
3045
    }
3046

    
3047
    @Override
3048
    public String as_identifier(String id) {
3049
        String quote = this.quote_for_identifiers();
3050
//        No se porque no esta disponible wrapIfMissing
3051
//        return StringUtils.wrapIfMissing(id,quote);
3052
        if (id.startsWith(quote)) {
3053
            return id;
3054
        }
3055
        return quote + id + quote;
3056

    
3057
    }
3058

    
3059
    @Override
3060
    public String as_string(String s) {
3061
        String quote = this.quote_for_strings();
3062
//        No se porque no esta disponible wrapIfMissing
3063
//        return StringUtils.wrapIfMissing(id,quote);
3064
        if (s.startsWith(quote)) {
3065
            return s;
3066
        }
3067
        return quote + s + quote;
3068

    
3069
    }
3070

    
3071
    @Override
3072
    public String as_string(byte[] data) {
3073
        return this.expressionBuilder.bytearray_0x(data);
3074
//        return this.expressionBuilder.bytearray_hex(data);
3075
//        return this.expressionBuilder.bytearray_x(data);
3076
    }
3077
    
3078
    @Override
3079
    public String as_string(boolean value) {
3080
        return value? "TRUE" : "FALSE";
3081
    }
3082

    
3083
    @Override
3084
    public String as_string(Number value) {
3085
        return Objects.toString(value);
3086
    }
3087
    
3088
    @Override
3089
    public String as_string(Object value) {
3090
        if( value == null ) {
3091
            return "NULL";
3092
        }
3093
        if( value instanceof CharSequence ) {
3094
            return as_string(value.toString());
3095
        }
3096
        if( value instanceof Number ) {
3097
            return as_string((Number)value);
3098
        }
3099
        if( value instanceof Boolean ) {
3100
            return as_string((boolean)value);
3101
        }
3102
        if( value instanceof byte[] ) {
3103
            return as_string((byte[])value);
3104
        }
3105
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3106
    }
3107
    
3108
    @Override
3109
    public GeometryExpressionBuilder expression() {
3110
        return this.expressionBuilder;
3111
    }
3112

    
3113
    @Override
3114
    public boolean has_spatial_functions() {
3115
        return this.hasSpatialFunctions;
3116
    }
3117

    
3118
    @Override
3119
    public GeometrySupportType geometry_support_type() {
3120
        return this.geometrySupportType;
3121
    }
3122

    
3123
    protected GeometryExpressionBuilder createExpressionBuilder() {
3124
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3125
    }
3126

    
3127
    @Override
3128
    public Object srs_id(IProjection projection) {
3129
        String abrev = projection.getAbrev();
3130
        return abrev.split(":")[1].trim();
3131
    }
3132

    
3133
    @Override
3134
    public String default_schema() {
3135
        return this.defaultSchema;
3136
    }
3137

    
3138
    @Override
3139
    public boolean support_schemas() {
3140
        return this.supportSchemas;
3141
    }
3142

    
3143
    @Override
3144
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3145
        switch (type) {
3146
            case DataTypes.BOOLEAN:
3147
                return type_boolean;
3148
            case DataTypes.CHAR:
3149
                return type_char;
3150

    
3151

    
3152
            case DataTypes.BYTE:
3153
                return type_byte;
3154
            case DataTypes.INT:
3155
                return type_int;
3156
            case DataTypes.LONG:
3157
                return type_long;
3158

    
3159
            case DataTypes.FLOAT:
3160
                return type_float;
3161
            case DataTypes.DOUBLE:
3162
                return type_double;
3163
            case DataTypes.DECIMAL:
3164
                if (precision < 1) {
3165
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3166
                }
3167
                if (scale < 1) {
3168
                  return MessageFormat.format(type_decimal_p, precision);
3169
                }
3170
                return MessageFormat.format(type_decimal_ps, precision, scale);
3171

    
3172
                
3173
            case DataTypes.STRING:
3174
                if (size < 0) {
3175
                    return type_string;
3176
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3177
                    return MessageFormat.format(type_string_p, size);
3178
                }
3179
                return type_string;
3180

    
3181
                
3182
            case DataTypes.DATE:
3183
                return type_date;
3184
            case DataTypes.TIME:
3185
                return type_time;
3186
            case DataTypes.TIMESTAMP:
3187
                return type_timestamp;
3188

    
3189
            case DataTypes.BYTEARRAY:
3190
                return type_bytearray;
3191

    
3192
            case DataTypes.GEOMETRY:
3193
                return type_geometry;
3194

    
3195
            case DataTypes.VERSION:
3196
                return type_version;
3197
            case DataTypes.URI:
3198
                return type_URI;
3199
            case DataTypes.URL:
3200
                return type_URL;
3201
            case DataTypes.FILE:
3202
                return type_FILE;
3203
            case DataTypes.FOLDER:
3204
                return type_FOLDER;
3205
            default:
3206
                return null;
3207
        }
3208
    }
3209

    
3210
    @Override
3211
    public Object sqlgeometrytype(int type, int subtype) {
3212
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3213
        // identificadores numericos para el tipo y otros strings.
3214
        // Por defecto vamos a devolver strings.
3215
        if (sqlgeometrytypes == null) {
3216
            sqlgeometrytypes = new HashMap<>();
3217
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3218
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3219
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3220
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3221

    
3222
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3223
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3224
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3225
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3226

    
3227
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3228
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3229
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3230
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3231

    
3232
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3233
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3234
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3235
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3236

    
3237
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3238
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3239
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3240
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3241

    
3242
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3243
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3244
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3245
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3246

    
3247
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3248
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3249
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3250
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3251

    
3252
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3253
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3254
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3255
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3256

    
3257
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3258
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3259
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3260
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3261
        }
3262
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3263
    }
3264

    
3265
    @Override
3266
    public Object sqlgeometrydimension(int type, int subtype) {
3267
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3268
        // identificadores numericos para las dimensiones y otros strings.
3269
        // Por defecto vamos a devolver enteros.
3270
        switch (subtype) {
3271
            case Geometry.SUBTYPES.GEOM3D:
3272
                return 3;
3273
            case Geometry.SUBTYPES.GEOM2DM:
3274
                return 3;
3275
            case Geometry.SUBTYPES.GEOM3DM:
3276
                return 4;
3277
            case Geometry.SUBTYPES.GEOM2D:
3278
            default:
3279
                return 2;
3280
        }
3281
    }
3282

    
3283
    @Override
3284
    public TableNameBuilder createTableNameBuilder() {
3285
        return new TableNameBuilderBase();
3286
    }
3287

    
3288
    protected SelectColumnBuilder createSelectColumnBuilder() {
3289
        return new SelectColumnBuilderBase(this);
3290
    }
3291

    
3292
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3293
        return new UpdateColumnBuilderBase();
3294
    }
3295

    
3296
    protected InsertColumnBuilder createInsertColumnBuilder() {
3297
        return new InsertColumnBuilderBase();
3298
    }
3299

    
3300
    protected OrderByBuilder createOrderByBuilder() {
3301
        return new OrderByBuilderBase();
3302
    }
3303

    
3304
    protected FromBuilder createFromBuilder() {
3305
        return new FromBuilderBase();
3306
    }
3307

    
3308
    public SelectBuilder createSelectBuilder() {
3309
        return new SelectBuilderBase();
3310
    }
3311

    
3312
    protected UpdateBuilder createUpdateBuilder() {
3313
        return new UpdateBuilderBase();
3314
    }
3315

    
3316
    protected DeleteBuilder createDeleteBuilder() {
3317
        return new DeleteBuilderBase();
3318
    }
3319

    
3320
    protected GrantBuilder createGrantBuilder() {
3321
        return new GrantBuilderBase();
3322
    }
3323

    
3324
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3325
        return new GrantRoleBuilderBase(table, role);
3326
    }
3327

    
3328
    protected DropTableBuilder createDropTableBuilder() {
3329
        return new DropTableBuilderBase();
3330
    }
3331

    
3332
    protected CreateTableBuilder createCreateTableBuilder() {
3333
        return new CreateTableBuilderBase();
3334
    }
3335

    
3336
    protected AlterTableBuilder createAlterTableBuilder() {
3337
        return new AlterTableBuilderBase();
3338
    }
3339

    
3340
    protected InsertBuilder createInsertBuilder() {
3341
        return new InsertBuilderBase();
3342
    }
3343

    
3344
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3345
        return new UpdateTableStatisticsBuilderBase();
3346
    }
3347

    
3348
    protected CreateIndexBuilder createCreateIndexBuilder() {
3349
        return new CreateIndexBuilderBase();
3350
    }
3351

    
3352
    protected DropIndexBuilder createDropIndexBuilder() {
3353
        return new DropIndexBuilderBase();
3354
    }
3355

    
3356
    @Override
3357
    public SelectBuilder select() {
3358
        if (this.select == null) {
3359
            this.select = this.createSelectBuilder();
3360
        }
3361
        return this.select;
3362
    }
3363

    
3364
    @Override
3365
    public UpdateBuilder update() {
3366
        if (this.update == null) {
3367
            this.update = this.createUpdateBuilder();
3368
        }
3369
        return this.update;
3370
    }
3371

    
3372
    @Override
3373
    public UpdateTableStatisticsBuilder update_table_statistics() {
3374
        if (this.update_table_statistics == null) {
3375
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3376
        }
3377
        return this.update_table_statistics;
3378
    }
3379

    
3380
    @Override
3381
    public DropTableBuilder drop_table() {
3382
        if (this.drop_table == null) {
3383
            this.drop_table = this.createDropTableBuilder();
3384
        }
3385
        return this.drop_table;
3386
    }
3387

    
3388
    @Override
3389
    public CreateIndexBuilder create_index() {
3390
        if (this.create_index == null) {
3391
            this.create_index = this.createCreateIndexBuilder();
3392
        }
3393
        return this.create_index;
3394
    }
3395

    
3396
    @Override
3397
    public DropIndexBuilder drop_index() {
3398
        if (this.drop_index == null) {
3399
            this.drop_index = this.createDropIndexBuilder();
3400
        }
3401
        return this.drop_index;
3402
    }
3403

    
3404
    @Override
3405
    public DeleteBuilder delete() {
3406
        if (this.delete == null) {
3407
            this.delete = this.createDeleteBuilder();
3408
        }
3409
        return this.delete;
3410
    }
3411

    
3412
    @Override
3413
    public InsertBuilder insert() {
3414
        if (this.insert == null) {
3415
            this.insert = this.createInsertBuilder();
3416
        }
3417
        return this.insert;
3418
    }
3419

    
3420
    @Override
3421
    public TableNameBuilder table_name() {
3422
        if (this.table_name == null) {
3423
            this.table_name = this.createTableNameBuilder();
3424
        }
3425
        return this.table_name;
3426
    }
3427

    
3428
    
3429
    @Override
3430
    public AlterTableBuilder alter_table() {
3431
        if (this.alter_table == null) {
3432
            this.alter_table = this.createAlterTableBuilder();
3433
        }
3434
        return this.alter_table;
3435
    }
3436

    
3437
    @Override
3438
    public CreateTableBuilder create_table() {
3439
        if (this.create_table == null) {
3440
            this.create_table = this.createCreateTableBuilder();
3441
        }
3442
        return this.create_table;
3443
    }
3444

    
3445
    @Override
3446
    public GrantBuilder grant() {
3447
        if (this.grant == null) {
3448
            this.grant = this.createGrantBuilder();
3449
        }
3450
        return this.grant;
3451
    }
3452
    
3453
    @Override
3454
    public Column column(String name) {
3455
        ColumnBase col = new ColumnBase(null, name);
3456
        return col;
3457
    }
3458

    
3459
    @Override
3460
    public Column column(TableNameBuilder table, String name) {
3461
        ColumnBase col = new ColumnBase(table, name);
3462
        return col;
3463
    }
3464
    
3465
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3466
        return new JoinBase(type, table, expression);
3467
    }
3468

    
3469
    @Override
3470
    public void accept(Visitor visitor, VisitorFilter filter) {
3471
        if (this.select != null) {
3472
            this.select.accept(visitor, filter);
3473
        }
3474
        if (this.update != null) {
3475
            this.update.accept(visitor, filter);
3476
        }
3477
        if (this.insert != null) {
3478
            this.insert.accept(visitor, filter);
3479
        }
3480
        if (this.delete != null) {
3481
            this.delete.accept(visitor, filter);
3482
        }
3483
        if (this.alter_table != null) {
3484
            this.alter_table.accept(visitor, filter);
3485
        }
3486
        if (this.create_table != null) {
3487
            this.create_table.accept(visitor, filter);
3488
        }
3489
        if (this.drop_table != null) {
3490
            this.drop_table.accept(visitor, filter);
3491
        }
3492
        if (this.table_name != null) {
3493
            this.table_name.accept(visitor, filter);
3494
        }
3495
    }
3496

    
3497
    @Override
3498
    public Formatter formatter() {
3499
        return expression().formatter();
3500
    }
3501

    
3502
    @Override
3503
    public String toString() {
3504
        return this.toString(formatter());
3505
    }
3506

    
3507
    @Override
3508
    public String toString(Formatter formatter) {
3509
        if (this.select != null) {
3510
            return this.select.toString(formatter);
3511
        }
3512
        if (this.update != null) {
3513
            return this.update.toString(formatter);
3514
        }
3515
        if (this.insert != null) {
3516
            return this.insert.toString(formatter);
3517
        }
3518
        if (this.delete != null) {
3519
            return this.delete.toString(formatter);
3520
        }
3521
        if (this.alter_table != null) {
3522
            return this.alter_table.toString(formatter);
3523
        }
3524
        if (this.create_table != null) {
3525
            return this.create_table.toString(formatter);
3526
        }
3527
        if (this.drop_table != null) {
3528
            return this.drop_table.toString(formatter);
3529
        }
3530
        if (this.update_table_statistics != null) {
3531
            return this.update_table_statistics.toString(formatter);
3532
        }
3533
        if (this.create_index != null) {
3534
            return this.create_index.toString(formatter);
3535
        }
3536
        if (this.drop_index != null) {
3537
            return this.drop_index.toString(formatter);
3538
        }
3539
        if (this.table_name != null) {
3540
            return this.table_name.toString(formatter);
3541
        }
3542
        return "";
3543
    }
3544

    
3545
    @Override
3546
    public CountBuilder count() {
3547
        return new CountBuilderBase();
3548
    }
3549

    
3550
    @Override
3551
    public List<Parameter> parameters() {
3552
        final List<Parameter> params = new ArrayList<>();
3553
        this.accept((Visitable value) -> {
3554
            params.add((Parameter) value);
3555
        }, new ClassVisitorFilter(Parameter.class));
3556
        return params;
3557
    }
3558

    
3559
    @Override
3560
    public List<Variable> variables() {
3561
        final List<Variable> vars = new ArrayList<>();
3562
        this.accept(new Visitor() {
3563
            @Override
3564
            public void visit(Visitable value) {
3565
                if (!vars.contains((Variable) value)) {
3566
                    vars.add((Variable) value);
3567
                }
3568
            }
3569
        }, new ClassVisitorFilter(Variable.class));
3570
        return vars;
3571
    }
3572

    
3573
    @Override
3574
    public List<String> parameters_names() {
3575
        List<String> params = new ArrayList<>();
3576
        for (Parameter param : parameters()) {
3577
            String s;
3578
            switch (param.type()) {
3579
                case PARAMETER_TYPE_CONSTANT:
3580
                    Object theValue = param.value();
3581
                    if (theValue == null) {
3582
                        s = "null";
3583
                    } else if (theValue instanceof String) {
3584
                        s = "'" + (String) theValue + "'";
3585
                    } else {
3586
                        s = theValue.toString();
3587
                    }
3588
                    break;
3589
                case PARAMETER_TYPE_VARIABLE:
3590
                default:
3591
                    s = "\"" + param.name() + "\"";
3592
            }
3593
            params.add(s);
3594
        }
3595
        return params;
3596
    }
3597

    
3598
    @Override
3599
    public List<String> variables_names() {
3600
        List<String> vars = new ArrayList<>();
3601
        for (Variable var : this.variables()) {
3602
            vars.add(var.name());
3603
        }
3604
        Collections.sort(vars);
3605
        return vars;
3606
    }    
3607
    
3608
    protected String[] aggregateFunctionNames = new String[] {
3609
        "MAX",
3610
        "MIN",
3611
        "COUNT",
3612
        "SUM"
3613
    };
3614
    
3615
    @Override
3616
    public boolean isAggregateFunction(String funcname) {
3617
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
3618
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
3619
                return true;
3620
            }
3621
        }
3622
        return false;
3623
    }
3624

    
3625
    @Override
3626
    public int getMaxRecomendedSQLLength() {
3627
        return DEFAULT_RECOMENDED_SQL_LENGTH;
3628
    }
3629
    
3630
    
3631
}