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

History | View | Annotate | Download (124 KB)

1
package org.gvsig.fmap.dal.feature.spi;
2

    
3
import java.text.MessageFormat;
4
import java.util.ArrayList;
5
import java.util.Collections;
6
import java.util.HashMap;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.Objects;
11
import java.util.Set;
12
import org.apache.commons.lang3.StringUtils;
13
import org.apache.commons.lang3.tuple.ImmutablePair;
14
import org.apache.commons.lang3.tuple.Pair;
15
import org.cresques.cts.IProjection;
16
import org.gvsig.expressionevaluator.ExpressionBuilder;
17
import org.gvsig.expressionevaluator.ExpressionBuilder.AbstractValue;
18
import org.gvsig.expressionevaluator.ExpressionBuilder.ClassVisitorFilter;
19
import static org.gvsig.expressionevaluator.ExpressionBuilder.PARAMETER_TYPE_CONSTANT;
20
import static org.gvsig.expressionevaluator.ExpressionBuilder.PARAMETER_TYPE_VARIABLE;
21
import org.gvsig.expressionevaluator.ExpressionBuilder.Parameter;
22
import static org.gvsig.expressionevaluator.ExpressionBuilder.VALUE_NULL;
23
import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
24
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
25
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
26
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
27
import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
28
import org.gvsig.expressionevaluator.Formatter;
29
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
30
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
31
import org.gvsig.expressionevaluator.GeometryExpressionEvaluatorLocator;
32
import org.gvsig.fmap.dal.DataManager;
33
import org.gvsig.fmap.dal.DataStoreParameters;
34
import org.gvsig.fmap.dal.DataTypes;
35
import org.gvsig.fmap.dal.SQLBuilder;
36
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
37
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
38
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
41
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
42
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
43
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
44
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
45
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
46
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
47
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
48
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
49
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
50
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
51
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
52
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
53
import org.gvsig.fmap.geom.Geometry;
54
import org.gvsig.fmap.geom.GeometryUtils;
55
import org.gvsig.fmap.geom.primitive.Envelope;
56
import org.gvsig.tools.dataTypes.DataType;
57
import org.gvsig.tools.dynobject.Tags;
58
import org.gvsig.tools.lang.CloneableUtils;
59
import org.gvsig.tools.util.PropertiesSupport;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62

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

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

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

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

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

    
92
    protected class ColumnDescriptorBase implements ColumnDescriptor {
93

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
357
    public class ColumnBase extends AbstractValue implements Column {
358

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

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

    
374

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

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

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

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

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

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

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

    
427
        @Override
428
        public void setProperty(String name, Object value) {
429
            super.setProperty(name, value);
430
            if(this.table != null){
431
                this.table.setProperty(name, value);
432
            }
433
        }
434
        
435
        
436
    }
437

    
438
    public class TableNameBuilderBase
439
            extends AbstractStatementPart
440
            implements TableNameBuilder {
441

    
442
        public String tableName;
443
        public String schemaName;
444
        private String databaseName;
445

    
446
        public TableNameBuilderBase() {
447
        }
448
        
449
        @Override
450
        public void accept(Visitor visitor, VisitorFilter filter) {
451
            if (filter==null || filter.accept(this)) {
452
                visitor.visit(this);
453
            }
454
        }
455

    
456
        @Override
457
        public TableNameBuilder database(String name) {
458
            this.databaseName = name;
459
            return this;
460
        }
461

    
462
        @Override
463
        public TableNameBuilder schema(String name) {
464
            if (support_schemas()) {
465
                this.schemaName = name;
466
            }
467
            return this;
468
        }
469

    
470
        @Override
471
        public TableNameBuilder name(String name) {
472
            this.tableName = name;
473
            return this;
474
        }
475

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

    
481
        @Override
482
        public String getSchema() {
483
            return this.schemaName;
484
        }
485

    
486
        @Override
487
        public String getName() {
488
            return this.tableName;
489
        }
490

    
491
        @Override
492
        public boolean has_schema() {
493
            if (!support_schemas()) {
494
                return false;
495
            }
496
            return StringUtils.isNotBlank(this.schemaName);
497
        }
498

    
499
        @Override
500
        public boolean has_name() {
501
            return StringUtils.isNotBlank(this.tableName);
502
        }
503

    
504
        @Override
505
        public boolean has_database() {
506
            return StringUtils.isNotBlank(this.databaseName);
507
        }
508

    
509
        @Override
510
        public boolean isEmpty() {
511
            return !this.has_database() && !this.has_schema() && !this.has_name();
512
        }
513

    
514
        @Override
515
        public String toString() {
516
            return this.toString(formatter());
517
        }
518

    
519
        @Override
520
        public String toString(Formatter<Value> formatter) {
521
            if (formatter!=null && formatter.canApply(this)) {
522
                return formatter.format(this);
523
            }
524
            if (this.has_database()) {
525
                if (this.has_schema()) {
526
                    return as_identifier(this.databaseName) + "."
527
                            + as_identifier(this.schemaName) + "."
528
                            + as_identifier(this.tableName);
529
                }
530
//                return as_identifier(this.databaseName) + "."
531
//                        + as_identifier(this.tableName);
532
            } else {
533
                if (this.has_schema()) {
534
                    return as_identifier(this.schemaName) + "."
535
                            + as_identifier(this.tableName);
536
                }
537
            }
538
            return as_identifier(this.tableName);
539
        }
540

    
541
        @Override
542
        public boolean equals(Object obj) {
543
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
544
                return false;
545
            }
546
            TableNameBuilder other = (TableNameBuilder) obj;
547
            
548
            if (this.has_database() != other.has_database()) {
549
                return false;
550
            }
551
            String thisSchema = null;
552
            String otherSchema = null;
553
            if(support_schemas()) {
554
                thisSchema = this.schemaName;
555
                if (StringUtils.isBlank(thisSchema)) {
556
                    thisSchema = default_schema();
557
                }
558
                otherSchema = other.getSchema();
559
                if (StringUtils.isBlank(otherSchema)) {
560
                    otherSchema = default_schema();
561
                }
562
            }
563
            if (this.has_database()) {
564
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
565
                           StringUtils.equals(thisSchema, otherSchema) &&
566
                           StringUtils.equals(this.tableName,other.getName());
567
            } else {
568
                    return StringUtils.equals(thisSchema, otherSchema) &&
569
                           StringUtils.equals(this.tableName,other.getName());
570
            }
571
        }
572

    
573
        @Override
574
        public int hashCode() {
575
            int hash = 7;
576
            hash = 37 * hash + Objects.hashCode(this.toString());
577
            return hash;
578
        }
579

    
580
    }
581

    
582
    public class CountBuilderBase
583
            extends AbstractStatementPart
584
            implements CountBuilder {
585

    
586
        protected Value value;
587
        protected boolean distinct;
588
        protected boolean all;
589

    
590
        public CountBuilderBase() {
591
            this.value = null;
592
            this.distinct = false;
593
            this.all = false;
594
        }
595
        
596
        @Override
597
        public CountBuilderBase clone() throws CloneNotSupportedException {
598
            CountBuilderBase other = (CountBuilderBase) super.clone();
599
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
600
            return other;
601
        }
602
        
603
        @Override
604
        public CountBuilder all() {
605
            this.all = true;
606
            return this;
607
        }
608

    
609
        @Override
610
        public CountBuilder column(Value value) {
611
            this.value = value;
612
            return this;
613
        }
614

    
615
        @Override
616
        public CountBuilder distinct() {
617
            this.distinct = true;
618
            return this;
619
        }
620

    
621
        @Override
622
        public String toString() {
623
            return this.toString(formatter());
624
        }
625

    
626
        @Override
627
        public String toString(Formatter formatter) {
628
            if (formatter!=null && formatter.canApply(this)) {
629
                return formatter.format(this);
630
            }
631
            if (this.all) {
632
                return "COUNT(*)";
633
            }
634
            if (this.distinct) {
635
                return MessageFormat.format(
636
                        "COUNT(DISTINCT {0})",
637
                        value.toString(formatter)
638
                );
639
            }
640
            return MessageFormat.format(
641
                    "COUNT({0})",
642
                    value.toString(formatter)
643
            );
644
        }
645

    
646
    }
647

    
648
    protected class JoinBase 
649
            extends AbstractStatementPart
650
            implements JoinBuilder 
651
        {
652
        protected String type;
653
        protected TableNameBuilder table;
654
        protected Value expression;
655
        
656
        public JoinBase(String type, TableNameBuilder table, Value expression) {
657
            this.type = type;
658
            this.table = table;
659
            this.expression = expression;
660
        }
661
        
662
        @Override
663
        public JoinBase clone() throws CloneNotSupportedException {
664
            JoinBase other = (JoinBase) super.clone();
665
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
666
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
667
            return other;
668
        }
669

    
670
        @Override
671
        public String toString() {
672
            return this.toString(formatter());
673
        }
674

    
675
        @Override
676
        public String toString(Formatter<Value> formatter) {
677
            if (formatter!=null && formatter.canApply(this)) {
678
                return formatter.format(this);
679
            }
680
            StringBuilder builder = new StringBuilder();
681
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
682
            builder.append(this.type.toUpperCase());
683
            builder.append(" JOIN ");
684
            builder.append(this.table.toString(formatter));
685
            builder.append(" ON ");
686
            builder.append(this.expression.toString(formatter));
687
            return builder.toString();
688
        }
689
        
690
        @Override
691
        public TableNameBuilder getTable() {
692
            return this.table;
693
        }
694
        
695
        @Override
696
        public String getType() {
697
            return this.type;
698
        }
699

    
700
        @Override
701
        public Value getCondition() {
702
            return this.expression;
703
        }
704
    }
705
    
706
    public class FromBuilderBase
707
            extends AbstractStatementPart
708
            implements FromBuilder {
709

    
710
        protected TableNameBuilder tableName;
711
        protected String subquery;
712
        protected String passthrough;
713
        protected List<JoinBuilder> joins;
714

    
715
        public FromBuilderBase() {
716
            this.tableName = null;
717
            this.subquery = null;
718
            this.passthrough = null;
719
            this.joins = null;
720
        }
721
        
722
        @Override
723
        public FromBuilderBase clone() throws CloneNotSupportedException {
724
            FromBuilderBase other = (FromBuilderBase) super.clone();
725
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
726
            if (joins!=null) {
727
                for (int i = 0; i < joins.size(); i++) {
728
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
729
                }
730
            }
731
            return other;
732
        }
733

    
734
        @Override
735
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
736
            JoinBase join = createJoin("LEFT", table, expression);
737
            if( this.joins==null ) {
738
                this.joins = new ArrayList<>();
739
            }
740
            this.joins.add(join);
741
            return this;
742
        }
743
        
744
        @Override
745
        public TableNameBuilder table() {
746
            if (tableName == null) {
747
                this.tableName = createTableNameBuilder();
748
            }
749
            return this.tableName;
750
        }
751

    
752
        @Override
753
        public void accept(Visitor visitor, VisitorFilter filter) {
754
            boolean visitChildren = true;
755
            if (filter==null || filter.accept(this)) {
756
                visitor.visit(this);
757
            } else {
758
                visitChildren = !filter.skipChildren();
759
            }
760
            if(visitChildren){
761
                if (this.tableName != null) {
762
                    this.tableName.accept(visitor, filter);
763
                }
764
            }
765
        }
766

    
767
        @Override
768
        public FromBuilder custom(String passthrough) {
769
            this.passthrough = passthrough;
770
            return this;
771
        }
772

    
773
        @Override
774
        public FromBuilder subquery(String subquery) {
775
            this.subquery = subquery;
776
            return this;
777
        }
778

    
779
        @Override
780
        public String toString() {
781
            return this.toString(formatter());
782
        }
783

    
784
        @Override
785
        public String toString(Formatter<Value> formatter) {
786
            if (formatter!=null && formatter.canApply(this)) {
787
                return formatter.format(this);
788
            }
789
            if (!StringUtils.isEmpty(passthrough)) {
790
                return passthrough;
791
            }
792
            if (!StringUtils.isEmpty(subquery)) {
793
                return "( " + this.subquery + ") AS _subquery_alias_ ";
794
            }
795
            if( this.joins==null || this.joins.isEmpty() ) {
796
                return this.tableName.toString(formatter);
797
            }
798
            StringBuilder builder = new StringBuilder();
799
            builder.append(this.tableName.toString(formatter));
800
            for (JoinBuilder join : this.joins) {
801
                builder.append(" ");
802
                builder.append(join.toString(formatter));
803
            }
804
            return builder.toString();
805
        }
806

    
807
        @Override
808
        public List<JoinBuilder> getJoins() {
809
            return this.joins;
810
        }
811

    
812
    }
813

    
814
    public class SelectColumnBuilderBase
815
            extends AbstractStatementPart
816
            implements SelectColumnBuilder {
817

    
818
        protected Column name = null;
819
        protected String alias = null;
820
        protected Value value = null;
821
        protected boolean asGeometry = false;
822
        protected TableNameBuilder table;
823
        protected SQLBuilder sqlbuilder;
824
        
825
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
826
            this.sqlbuilder = sqlbuilder;
827
        }
828
        
829
        @Override
830
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
831
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
832
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
833
            other.name = (Column) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
834
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
835
            return other;
836
        }
837

    
838
        @Override
839
        public void accept(Visitor visitor, VisitorFilter filter) {
840
            boolean visitChildren = true;
841
            if (filter==null || filter.accept(this)) {
842
                visitor.visit(this);
843
            } else {
844
                visitChildren = !filter.skipChildren();
845
            }
846
            if(visitChildren){
847
                if (this.value != null) {
848
                    this.value.accept(visitor, filter);
849
                } else if (this.name != null) {
850
                    this.name.accept(visitor, filter);
851
                }
852
            }
853
        }
854

    
855
        @Override
856
        public void replace(Value target, Value replacement) {
857
            if (this.name!=null ) {
858
                if( this.name == target) {
859
                    if(replacement == null){
860
                        this.name = null;
861
                    } else if(replacement instanceof Column){
862
                        this.name = (Column) replacement;
863
                    } else if(replacement instanceof Variable){
864
                        this.name = new ColumnBase(this.table, ((Variable) replacement).name());
865
                    } else {
866
                        this.value = replacement;
867
                    }
868
                }
869
            }
870
            if( this.value!=null ) {
871
                if (this.value == target) {
872
                    this.value = replacement;
873
                } else {
874
                    this.value.replace(target, replacement);
875
                }
876
            }
877
        }
878

    
879
        @Override
880
        public SelectColumnBuilder name(String name) {
881
            return this.name(this.table, name);
882
        }
883

    
884
        @Override
885
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
886
            String quote = quote_for_identifiers();
887
            if (name.startsWith(quote)) {
888
                // Remove quotes
889
                name = name.substring(1, name.length() - 1);
890
            }
891
            this.table = table;
892
            this.name = new ColumnBase(this.table, name);
893
            this.value = null;
894
            this.asGeometry = false;
895
            return this;
896
        }
897
        
898
        public SelectColumnBuilder table(TableNameBuilder table) {
899
            this.table = table;
900
            if(this.name != null){
901
                this.name.table(table);
902
            }
903
            return this;
904
        }
905
        
906
        @Override
907
        public SelectColumnBuilder all() {
908
            this.name = null;
909
            this.value = expression().custom("*");
910
            this.asGeometry = false;
911
            return this;
912
        }
913

    
914
        @Override
915
        public SelectColumnBuilder as_geometry() {
916
            this.asGeometry = true;
917
            return this;
918
        }
919

    
920
        @Override
921
        public SelectColumnBuilder value(Value value) {
922
            this.value = value;
923
            return this;
924
        }
925

    
926
        @Override
927
        public SelectColumnBuilder as(String alias) {
928
            this.alias = alias;
929
            return this;
930
        }
931

    
932
        @Override
933
        public String getName() {
934
            if (this.name==null) {
935
                return null;
936
            }
937
            return this.name.name();
938
        }
939

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

    
945
        @Override
946
        public Value getValue() {
947
            return this.value;
948
        }
949

    
950
        @Override
951
        public String toString() {
952
            return this.toString(formatter());
953
        }
954

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

    
1004
    public class OrderByBuilderBase
1005
            extends AbstractStatementPart
1006
            implements OrderByBuilder {
1007

    
1008
        protected Value value;
1009
        protected String custom;
1010
        protected boolean ascending;
1011
        protected int nullsMode;
1012

    
1013
        public OrderByBuilderBase() {
1014
            this.ascending = true;
1015
            this.nullsMode = MODE_NULLS_LAST;
1016
        }
1017
        
1018
        @Override
1019
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
1020
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
1021
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
1022
            return other;
1023
        }
1024
        
1025
        @Override
1026
        public void accept(Visitor visitor, VisitorFilter filter) {
1027
            boolean visitChildren = true;
1028
            if (filter==null || filter.accept(this)) {
1029
                visitor.visit(this);
1030
            } else {
1031
                visitChildren = !filter.skipChildren();
1032
            }
1033
            if(visitChildren){
1034
                if (this.value!=null) {
1035
                    this.value.accept(visitor, filter);
1036
                }
1037
            }
1038
        }
1039

    
1040
        @Override
1041
        public OrderByBuilder column(String name) {
1042
            this.value = expression().variable(name);
1043
            return this;
1044
        }
1045
        
1046
        @Override
1047
        public boolean isColumn(String name) {
1048
            if(this.value instanceof ExpressionBuilder.Variable){
1049
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
1050
            }
1051
            return false;
1052
        }
1053
        
1054
        @Override
1055
        public boolean isColumn(Value value) {
1056
            if(value instanceof ExpressionBuilder.Variable){
1057
                return isColumn(((ExpressionBuilder.Variable)value).name());
1058
            }
1059
            return this.value == value;
1060
        }
1061
        
1062
        @Override
1063
        public OrderByBuilder value(Value expression) {
1064
            this.value = expression;
1065
            return this;
1066
        }
1067
        
1068
        @Override
1069
        public OrderByBuilder custom(String order) {
1070
            this.custom = order;
1071
            return this;
1072
        }
1073

    
1074
        @Override
1075
        public OrderByBuilder ascending() {
1076
            this.ascending = true;
1077
            return this;
1078
        }
1079

    
1080
        @Override
1081
        public OrderByBuilder ascending(boolean asc) {
1082
            this.ascending = asc;
1083
            return this;
1084
        }
1085

    
1086
        @Override
1087
        public OrderByBuilder descending() {
1088
            this.ascending = false;
1089
            return this;
1090
        }
1091

    
1092
        @Override
1093
        public OrderByBuilder nulls(int mode) {
1094
            this.nullsMode = mode;
1095
            return this;
1096
        }
1097

    
1098
        @Override
1099
        public int getNullsMode() {
1100
            return this.nullsMode;
1101
        }
1102

    
1103
        @Override
1104
        public String toString() {
1105
            return this.toString(formatter());
1106
        }
1107

    
1108
        @Override
1109
        public String toString(Formatter<Value> formatter) {
1110
            if (formatter!=null && formatter.canApply(this)) {
1111
                return formatter.format(this);
1112
            }
1113
            if (!StringUtils.isEmpty(this.custom)) {
1114
                return this.custom;
1115
            }
1116
            String order_s = this.value.toString(formatter);
1117
            if (this.ascending) {
1118
                order_s += " ASC";
1119
            } else {
1120
                order_s += " DESC";
1121
            }
1122
            switch(this.nullsMode) {
1123
                case MODE_NULLS_NOT_SPECIFIED:
1124
                    break;
1125
                case MODE_NULLS_FIRST:
1126
                    order_s += " NULLS FIRST";
1127
                    break;
1128
                case MODE_NULLS_LAST:
1129
                default:
1130
                    order_s += " NULLS LAST";
1131
                    break;
1132
            }
1133
            return order_s;
1134
        }
1135

    
1136
        @Override
1137
        public void replace(Value target, Value replacement) {
1138
            super.replace(target, replacement);
1139
            if(target == this.value){
1140
                this.value = replacement;
1141
                return;
1142
            }
1143
            if(this.value == null){
1144
                return;
1145
            }
1146
            this.value.replace(target, replacement);
1147
        }
1148
        
1149
        
1150
    }
1151

    
1152
    public class SelectBuilderBase
1153
            extends AbstractStatement
1154
            implements SelectBuilder {
1155

    
1156
        protected FromBuilder from;
1157
        protected GeometryExpressionBuilder where;
1158
        protected long limit = -1;
1159
        protected long offset = -1;
1160
        protected List<SelectColumnBuilder> columns;
1161
        protected List<OrderByBuilder> order_by;
1162
        protected boolean distinct;
1163
        protected List<Value> groupColumn;
1164
        protected boolean check_order_and_offset = true;
1165

    
1166
        public SelectBuilderBase() {
1167
            this.columns = new ArrayList<>();
1168
            this.distinct = false;
1169
        }
1170
        @Override
1171
        public List<Value> getGroups() {
1172
            return this.groupColumn;
1173
        }
1174
        
1175
        @Override
1176
        public List<SelectColumnBuilder> getColumns() {
1177
            return Collections.unmodifiableList(this.columns);
1178
    }
1179
        
1180
        @Override
1181
        public void remove_column(String columnName) {
1182
            SelectColumnBuilder found = null;
1183
            for (SelectColumnBuilder column : columns) {
1184
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1185
                    found = column;
1186
                    break;
1187
                }
1188
                    
1189
            }
1190
            if(found!=null) {
1191
                columns.remove(found);
1192
            }
1193
        }
1194

    
1195
        @Override
1196
        public SelectBuilder group_by(Value... columns) {
1197
            if( this.groupColumn==null ) {
1198
                this.groupColumn = new ArrayList<>();
1199
            }
1200
            for (Value column : columns) {
1201
                this.groupColumn.add(column);
1202
            }
1203
            return this;
1204
        }
1205

    
1206
        @Override
1207
        public void accept(Visitor visitor, VisitorFilter filter) {
1208
            boolean visitChildren = true;
1209
            if (filter==null || filter.accept(this)) {
1210
                visitor.visit(this);
1211
            } else {
1212
                visitChildren = !filter.skipChildren();
1213
            }
1214
            if(visitChildren){
1215
                for (SelectColumnBuilder column : columns) {
1216
                    column.accept(visitor, filter);
1217
                }
1218
                if (this.has_from()) {
1219
                    this.from.accept(visitor, filter);
1220
                }
1221
                if (this.has_where()) {
1222
                    this.where.accept(visitor, filter);
1223
                }
1224
                if (this.has_order_by()) {
1225
                    for (OrderByBuilder order : order_by) {
1226
                        order.accept(visitor, filter);
1227
                    }
1228
                }
1229
                if (this.has_group_by()) {
1230
                    for (Value group : groupColumn) {
1231
                        group.accept(visitor, filter);
1232
                    }
1233
                }
1234
            }
1235
        }
1236

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

    
1287
        @Override
1288
        public SelectBuilder distinct() {
1289
            this.distinct = true;
1290
            return this;
1291
        }
1292

    
1293
        @Override
1294
        public SelectColumnBuilder column() {
1295
            return column(createSelectColumnBuilder());
1296
        }
1297

    
1298
        @Override
1299
        public SelectColumnBuilder column(SelectColumnBuilder columnBuilder) {
1300
            this.columns.add(columnBuilder);
1301
            if( this.has_from() && !this.from().table().isEmpty() ) {
1302
                TableNameBuilder table = (TableNameBuilder) CloneableUtils.cloneQuietly(this.from().table());
1303
                columnBuilder.table(table);
1304
            }
1305
            return columnBuilder;
1306
        }
1307

    
1308
        @Override
1309
        public SelectColumnBuilder column(String name) {
1310
            for (SelectColumnBuilder column : columns) {
1311
                if (StringUtils.equals(name, column.getName())) {
1312
                    return column;
1313
                }
1314
            }
1315
            return column(createSelectColumnBuilder()).name(name);
1316
        }
1317

    
1318
        @Override
1319
        public SelectColumnBuilder getColumn(String name) {
1320
            for (SelectColumnBuilder column : columns) {
1321
                if (StringUtils.equals(name, column.getName())) {
1322
                    return column;
1323
                }
1324
            }
1325
            return null;
1326
        }
1327
        
1328
        @Override
1329
        public SelectBuilder remove_all_columns() {
1330
            this.columns = new ArrayList<>();
1331
            return this;
1332
        }
1333
        
1334
        @Override
1335
        public boolean has_column(String name) {
1336
            for (SelectColumnBuilder column : columns) {
1337
                if (StringUtils.equals(name, column.getName())) {
1338
                    return true;
1339
                }
1340
                if (StringUtils.equals(name, column.getAlias())) {
1341
                    return true;
1342
                }
1343
            }
1344
            return false;
1345
        }
1346

    
1347
        @Override
1348
        public FromBuilder from() {
1349
            if (this.from == null) {
1350
                this.from = createFromBuilder();
1351
            }
1352
            return this.from;
1353
        }
1354

    
1355
        @Override
1356
        public boolean has_from() {
1357
            return this.from != null;
1358
        }
1359

    
1360
        @Override
1361
        public GeometryExpressionBuilder where() {
1362
            if (this.where == null) {
1363
                this.where = createExpressionBuilder();
1364
            }
1365
            return this.where;
1366
        }
1367

    
1368
        @Override
1369
        public boolean has_where() {
1370
            if (this.where == null) {
1371
                return false;
1372
            }
1373
            return this.where.value() != null;
1374
        }
1375

    
1376
        @Override
1377
        public SelectBuilder limit(long limit) {
1378
            this.limit = limit;
1379
            return this;
1380
        }
1381

    
1382
        @Override
1383
        public SelectBuilder limit(Long limit) {
1384
            if (limit == null) {
1385
                this.limit = -1;
1386
            } else {
1387
                this.limit = limit;
1388
            }
1389
            return this;
1390
        }
1391

    
1392
        @Override
1393
        public boolean has_limit() {
1394
            return this.limit >= 0;
1395
        }
1396

    
1397
        @Override
1398
        public SelectBuilder offset(long offset) {
1399
            this.offset = offset;
1400
            return this;
1401
        }
1402

    
1403
        @Override
1404
        public boolean has_offset() {
1405
            return this.offset > 0;
1406
        }
1407

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

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

    
1510
        @Override
1511
        public String toString() {
1512
            return this.toString(formatter());
1513
        }
1514

    
1515
        @Override
1516
        public String toString(Formatter<Value> formatter) {
1517
            if (formatter!=null && formatter.canApply(this)) {
1518
                return formatter.format(this);
1519
            }
1520
            StringBuilder builder = new StringBuilder();
1521
            if (!this.isValid(builder)) {
1522
                throw new IllegalStateException(builder.toString());
1523
            }
1524
            builder.append("SELECT ");
1525
            if (this.distinct) {
1526
                builder.append("DISTINCT ");
1527
            }
1528
            boolean first = true;
1529
            for (SelectColumnBuilder column : columns) {
1530
                if (first) {
1531
                    first = false;
1532
                } else {
1533
                    builder.append(", ");
1534
                }
1535
                builder.append(column.toString(formatter));
1536
            }
1537

    
1538
            if (this.has_from()) {
1539
                builder.append(" FROM ");
1540
                builder.append(this.from.toString(formatter));
1541
            }
1542
            if (this.has_where()) {
1543
                builder.append(" WHERE ");
1544
                builder.append(this.where.toString(formatter));
1545
            }
1546
            if( this.has_group_by() ) {
1547
                builder.append(" GROUP BY ");
1548
                builder.append(this.groupColumn.get(0).toString(formatter));
1549
                for (int i = 1; i < groupColumn.size(); i++) {
1550
                    builder.append(", ");
1551
                    builder.append(this.groupColumn.get(i).toString(formatter));
1552
                }
1553
            }
1554
            if (this.has_order_by()) {
1555
                builder.append(" ORDER BY ");
1556
                first = true;
1557
                for (OrderByBuilder item : this.order_by) {
1558
                    if (first) {
1559
                        first = false;
1560
                    } else {
1561
                        builder.append(", ");
1562
                    }
1563
                    builder.append(item.toString(formatter));
1564
                }
1565
            }
1566

    
1567
            if (this.has_limit()) {
1568
                builder.append(" LIMIT ");
1569
                builder.append(this.limit);
1570
            }
1571
            if (this.has_offset()) {
1572
                builder.append(" OFFSET ");
1573
                builder.append(this.offset);
1574
            }
1575
            return builder.toString();
1576

    
1577
        }
1578
    }
1579

    
1580
    public class DropTableBuilderBase
1581
            extends AbstractStatement
1582
            implements DropTableBuilder {
1583

    
1584
        protected TableNameBuilder table;
1585

    
1586
        @Override
1587
        public TableNameBuilder table() {
1588
            if (table == null) {
1589
                table = createTableNameBuilder();
1590
            }
1591
            return table;
1592
        }
1593

    
1594
        @Override
1595
        public void accept(Visitor visitor, VisitorFilter filter) {
1596
            boolean visitChildren = true;
1597
            if (filter==null || filter.accept(this)) {
1598
                visitor.visit(this);
1599
            } else {
1600
                visitChildren = !filter.skipChildren();
1601
            }
1602
            if(visitChildren){
1603
                this.table.accept(visitor, filter);
1604
            }
1605
        }
1606

    
1607
        @Override
1608
        public String toString() {
1609
            return this.toString(formatter());
1610
        }
1611

    
1612
        @Override
1613
        public String toString(Formatter<Value> formatter) {
1614
            if (formatter!=null && formatter.canApply(this)) {
1615
                return formatter.format(this);
1616
            }
1617
            StringBuilder builder = new StringBuilder();
1618
            boolean first = true;
1619
            for (String sql : toStrings(formatter)) {
1620
                if (StringUtils.isEmpty(sql)) {
1621
                    continue;
1622
                }
1623
                if (first) {
1624
                    first = false;
1625
                } else {
1626
                    builder.append("; ");
1627
                }
1628
                builder.append(sql);
1629
            }
1630
            return builder.toString();
1631
        }
1632

    
1633
        @Override
1634
        public List<String> toStrings() {
1635
            return this.toStrings(formatter());
1636
        }
1637

    
1638
        @Override
1639
        public List<String> toStrings(Formatter formatter) {
1640
            List<String> sqls = new ArrayList<>();
1641

    
1642
            sqls.add(
1643
                    MessageFormat.format(
1644
                            STMT_DROP_TABLE_table,
1645
                            this.table.toString(formatter)
1646
                    )
1647
            );
1648
            String sql;
1649
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1650
                if (this.table.has_schema()) {
1651
                    sql = MessageFormat.format(
1652
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1653
                            as_string(this.table.getSchema()),
1654
                            as_string(this.table.getName())
1655
                    );
1656
                } else {
1657
                    sql = MessageFormat.format(
1658
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1659
                            as_identifier(this.table.getName())
1660
                    );
1661
                }
1662
                if (!StringUtils.isEmpty(sql)) {
1663
                    sqls.add(sql);
1664
                }
1665
            }
1666
            return sqls;
1667
        }
1668
    }
1669

    
1670
    public class GrantRoleBuilderBase
1671
            extends AbstractStatementPart
1672
            implements GrantRoleBuilder {
1673

    
1674
        protected TableNameBuilder table;
1675
        protected String role;
1676
        protected Set<Privilege> privileges;
1677

    
1678
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1679
            this.table = table;
1680
            this.role = role;
1681
            this.privileges = new HashSet<>();
1682
        }
1683
        
1684
        @Override
1685
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1686
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1687
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1688
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1689
            
1690
            return other;
1691
        }
1692

    
1693
        @Override
1694
        public GrantRoleBuilder privilege(Privilege privilege) {
1695
            privileges.add(privilege);
1696
            return this;
1697
        }
1698

    
1699
        @Override
1700
        public GrantRoleBuilder select() {
1701
            privileges.add(Privilege.SELECT);
1702
            return this;
1703
        }
1704

    
1705
        @Override
1706
        public GrantRoleBuilder update() {
1707
            privileges.add(Privilege.UPDATE);
1708
            return this;
1709
        }
1710

    
1711
        @Override
1712
        public GrantRoleBuilder insert() {
1713
            privileges.add(Privilege.INSERT);
1714
            return this;
1715
        }
1716

    
1717
        @Override
1718
        public GrantRoleBuilder delete() {
1719
            privileges.add(Privilege.DELETE);
1720
            return this;
1721
        }
1722

    
1723
        @Override
1724
        public GrantRoleBuilder truncate() {
1725
            privileges.add(Privilege.TRUNCATE);
1726
            return this;
1727
        }
1728

    
1729
        @Override
1730
        public GrantRoleBuilder reference() {
1731
            privileges.add(Privilege.REFERENCE);
1732
            return this;
1733
        }
1734

    
1735
        @Override
1736
        public GrantRoleBuilder trigger() {
1737
            privileges.add(Privilege.TRIGGER);
1738
            return this;
1739
        }
1740

    
1741
        @Override
1742
        public GrantRoleBuilder all() {
1743
            privileges.add(Privilege.ALL);
1744
            return this;
1745
        }
1746

    
1747
        protected String getPrivilegeName(Privilege privilege) {
1748
            switch (privilege) {
1749
                case DELETE:
1750
                    return "DELETE";
1751
                case INSERT:
1752
                    return "INSERT";
1753
                case REFERENCE:
1754
                    return "REFERENCE";
1755
                case SELECT:
1756
                    return "SELECT";
1757
                case TRIGGER:
1758
                    return "TRIGGER";
1759
                case TRUNCATE:
1760
                    return "TRUNCATE";
1761
                case UPDATE:
1762
                    return "UPDATE";
1763
                case ALL:
1764
                default:
1765
                    return "ALL";
1766
            }
1767
        }
1768

    
1769
        @Override
1770
        public String toString() {
1771
            return this.toString(formatter());
1772
        }
1773

    
1774
        @Override
1775
        public String toString(Formatter<Value> formatter) {
1776
            if (formatter!=null && formatter.canApply(this)) {
1777
                return formatter.format(this);
1778
            }
1779
            StringBuilder builder = new StringBuilder();
1780
            boolean first = true;
1781
            for (Privilege privilege : privileges) {
1782
                if (first) {
1783
                    first = false;
1784
                } else {
1785
                    builder.append(", ");
1786
                }
1787
                builder.append(this.getPrivilegeName(privilege));
1788
            }
1789
            String sql = MessageFormat.format(
1790
                    STMT_GRANT_privileges_ON_table_TO_role,
1791
                    builder.toString(),
1792
                    table.toString(formatter),
1793
                    role
1794
            );
1795
            return sql;
1796
        }
1797
    }
1798

    
1799
    public class GrantBuilderBase
1800
            extends AbstractStatement
1801
            implements GrantBuilder {
1802

    
1803
        protected TableNameBuilder table;
1804
        protected Map<String, GrantRoleBuilder> roles;
1805

    
1806
        public GrantBuilderBase() {
1807
            this.roles = new HashMap<>();
1808
        }
1809

    
1810
        @Override
1811
        public TableNameBuilder table() {
1812
            if (table == null) {
1813
                table = createTableNameBuilder();
1814
            }
1815
            return table;
1816
        }
1817

    
1818
        @Override
1819
        public void accept(Visitor visitor, VisitorFilter filter) {
1820
            boolean visitChildren = true;
1821
            if (filter==null || filter.accept(this)) {
1822
                visitor.visit(this);
1823
            } else {
1824
                visitChildren = !filter.skipChildren();
1825
            }
1826
            if(visitChildren){
1827
                if (this.table != null) {
1828
                    this.table.accept(visitor, filter);
1829
                }
1830
            }
1831
        }
1832

    
1833
        @Override
1834
        public GrantRoleBuilder role(String role) {
1835
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1836
            if (roleBuilder == null) {
1837
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1838
                this.roles.put(role, roleBuilder);
1839
            }
1840
            return roleBuilder;
1841
        }
1842

    
1843
        @Override
1844
        public String toString() {
1845
            return this.toString(formatter());
1846
        }
1847

    
1848
        @Override
1849
        public String toString(Formatter<Value> formatter) {
1850
            if (formatter!=null && formatter.canApply(this)) {
1851
                return formatter.format(this);
1852
            }
1853
            StringBuilder builder = new StringBuilder();
1854
            boolean first = true;
1855
            for (String sql : toStrings(formatter)) {
1856
                if (StringUtils.isEmpty(sql)) {
1857
                    continue;
1858
                }
1859
                if (first) {
1860
                    first = false;
1861
                } else {
1862
                    builder.append("; ");
1863
                }
1864
                builder.append(sql);
1865
            }
1866
            return builder.toString();
1867
        }
1868

    
1869
        @Override
1870
        public List<String> toStrings() {
1871
            return this.toStrings(formatter());
1872
        }
1873

    
1874
        @Override
1875
        public List<String> toStrings(Formatter formatter) {
1876
            List<String> sqls = new ArrayList<>();
1877
            for (GrantRoleBuilder role : roles.values()) {
1878
                sqls.add(role.toString(formatter));
1879
            }
1880
            return sqls;
1881
        }
1882
    }
1883

    
1884
    public class UpdateColumnBuilderBase
1885
            extends InsertColumnBuilderBase
1886
            implements UpdateColumnBuilder {
1887

    
1888
        public UpdateColumnBuilderBase() {
1889
            super();
1890
        }
1891

    
1892
        @Override
1893
        public UpdateColumnBuilder name(String name) {
1894
            return (UpdateColumnBuilder) super.name(name);
1895
        }
1896

    
1897
        @Override
1898
        public UpdateColumnBuilder with_value(Value value) {
1899
            return (UpdateColumnBuilder) super.with_value(value);
1900
        }
1901

    
1902
    }
1903

    
1904
    public class UpdateBuilderBase
1905
            extends AbstractStatement
1906
            implements UpdateBuilder {
1907

    
1908
        protected GeometryExpressionBuilder where;
1909
        protected List<UpdateColumnBuilder> columns;
1910
        protected TableNameBuilder table;
1911

    
1912
        public UpdateBuilderBase() {
1913
            this.columns = new ArrayList<>();
1914
        }
1915

    
1916
        @Override
1917
        public void accept(Visitor visitor, VisitorFilter filter) {
1918
            boolean visitChildren = true;
1919
            if (filter==null || filter.accept(this)) {
1920
                visitor.visit(this);
1921
            } else {
1922
                visitChildren = !filter.skipChildren();
1923
            }
1924
            if(visitChildren){
1925
                if (this.table != null) {
1926
                    this.table.accept(visitor, filter);
1927
                }
1928
                for (UpdateColumnBuilder column : columns) {
1929
                    column.accept(visitor, filter);
1930
                }
1931
                if (this.has_where()) {
1932
                    this.where.accept(visitor, filter);
1933
                }
1934
            }
1935
        }
1936

    
1937
        @Override
1938
        public GeometryExpressionBuilder where() {
1939
            if (this.where == null) {
1940
                this.where = createExpressionBuilder();
1941
            }
1942
            return this.where;
1943
        }
1944

    
1945
        @Override
1946
        public TableNameBuilder table() {
1947
            if (table == null) {
1948
                table = createTableNameBuilder();
1949
            }
1950
            return table;
1951
        }
1952

    
1953
        @Override
1954
        public UpdateColumnBuilder column() {
1955
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1956
            this.columns.add(column);
1957
            return column;
1958
        }
1959

    
1960
        @Override
1961
        public boolean has_where() {
1962
            return this.where != null;
1963
        }
1964

    
1965
        @Override
1966
        public String toString() {
1967
            return this.toString(formatter());
1968
        }
1969

    
1970
        @Override
1971
        public String toString(Formatter<Value> formatter) {
1972
            if (formatter!=null && formatter.canApply(this)) {
1973
                return formatter.format(this);
1974
            }
1975
            /*
1976
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1977
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1978
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1979
             * output_expression [ AS output_name ] [, ...] ]
1980
             */
1981
            StringBuilder columnsAndValues = new StringBuilder();
1982

    
1983
            boolean first = true;
1984
            for (UpdateColumnBuilder column : columns) {
1985
                if (first) {
1986
                    first = false;
1987
                } else {
1988
                    columnsAndValues.append(", ");
1989
                }
1990
                columnsAndValues.append(as_identifier(column.getName()));
1991
                columnsAndValues.append(" = ");
1992
                columnsAndValues.append(column.getValue().toString(formatter));
1993
            }
1994

    
1995
            String sql;
1996
            if (this.has_where()) {
1997
                sql = MessageFormat.format(
1998
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1999
                        this.table.toString(formatter),
2000
                        columnsAndValues.toString(),
2001
                        this.where.toString(formatter)
2002
                );
2003
            } else {
2004
                sql = MessageFormat.format(
2005
                        STMT_UPDATE_table_SET_columnsAndValues,
2006
                        this.table.toString(formatter),
2007
                        columnsAndValues.toString()
2008
                );
2009
            }
2010
            return sql;
2011
        }
2012
    }
2013

    
2014
    public class DeleteBuilderBase
2015
            extends AbstractStatement
2016
            implements DeleteBuilder {
2017

    
2018
        protected GeometryExpressionBuilder where;
2019
        protected TableNameBuilder table;
2020

    
2021
        public DeleteBuilderBase() {
2022
        }
2023

    
2024
        @Override
2025
        public void accept(Visitor visitor, VisitorFilter filter) {
2026
            boolean visitChildren = true;
2027
            if (filter==null || filter.accept(this)) {
2028
                visitor.visit(this);
2029
            } else {
2030
                visitChildren = !filter.skipChildren();
2031
            }
2032
            if(visitChildren){
2033
                if (this.table != null) {
2034
                    this.table.accept(visitor, filter);
2035
                }
2036
                if (this.has_where()) {
2037
                    this.where.accept(visitor, filter);
2038
                }
2039
            }
2040
        }
2041

    
2042
        @Override
2043
        public GeometryExpressionBuilder where() {
2044
            if (this.where == null) {
2045
                this.where = createExpressionBuilder();
2046
            }
2047
            return this.where;
2048
        }
2049

    
2050
        @Override
2051
        public TableNameBuilder table() {
2052
            if (table == null) {
2053
                table = createTableNameBuilder();
2054
            }
2055
            return table;
2056
        }
2057

    
2058
        @Override
2059
        public boolean has_where() {
2060
            return this.where != null;
2061
        }
2062

    
2063
        @Override
2064
        public String toString() {
2065
            return this.toString(formatter());
2066
        }
2067

    
2068
        @Override
2069
        public String toString(Formatter<Value> formatter) {
2070
            if (formatter!=null && formatter.canApply(this)) {
2071
                return formatter.format(this);
2072
            }
2073
            /*
2074
             * DELETE FROM table_name
2075
             * WHERE some_column=some_value; 
2076
             */
2077
            String sql;
2078
            if (this.has_where()) {
2079
                sql = MessageFormat.format(
2080
                        STMT_DELETE_FROM_table_WHERE_expresion,
2081
                        this.table.toString(formatter),
2082
                        this.where.toString(formatter)
2083
                );
2084
            } else {
2085
                sql = MessageFormat.format(
2086
                        STMT_DELETE_FROM_table,
2087
                        this.table.toString(formatter)
2088
                );
2089
            }
2090
            return sql;
2091
        }
2092
    }
2093

    
2094
    public class CreateIndexBuilderBase
2095
            extends AbstractStatement
2096
            implements CreateIndexBuilder {
2097

    
2098
        protected boolean ifNotExist = false;
2099
        protected boolean isUnique = false;
2100
        protected String indexName;
2101
        protected boolean isSpatial = false;
2102
        protected TableNameBuilder table;
2103
        protected final List<String> columns;
2104

    
2105
        public CreateIndexBuilderBase() {
2106
            this.columns = new ArrayList<>();
2107
        }
2108

    
2109
        @Override
2110
        public CreateIndexBuilder unique() {
2111
            this.isUnique = true;
2112
            return this;
2113
        }
2114

    
2115
        @Override
2116
        public CreateIndexBuilder if_not_exist() {
2117
            this.ifNotExist = true;
2118
            return this;
2119
        }
2120

    
2121
        @Override
2122
        public CreateIndexBuilder name(String name) {
2123
            this.indexName = name;
2124
            return this;
2125
        }
2126

    
2127
        @Override
2128
        public CreateIndexBuilder name(String tableName, String columnName) {
2129
            this.indexName = tableName + "_IDX_" + columnName;
2130
            return this;
2131
        }
2132

    
2133
        @Override
2134
        public CreateIndexBuilder spatial() {
2135
            this.isSpatial = true;
2136
            return this;
2137
        }
2138

    
2139
        @Override
2140
        public CreateIndexBuilder column(String name) {
2141
            this.columns.add(name);
2142
            return this;
2143
        }
2144

    
2145
        @Override
2146
        public TableNameBuilder table() {
2147
            if (table == null) {
2148
                table = createTableNameBuilder();
2149
            }
2150
            return table;
2151
        }
2152

    
2153
        @Override
2154
        public void accept(Visitor visitor, VisitorFilter filter) {
2155
            boolean visitChildren = true;
2156
            if (filter==null || filter.accept(this)) {
2157
                visitor.visit(this);
2158
            } else {
2159
                visitChildren = !filter.skipChildren();
2160
            }
2161
            if(visitChildren){
2162
                if (this.table != null) {
2163
                    this.table.accept(visitor, filter);
2164
                }
2165
            }
2166
        }
2167

    
2168
        @Override
2169
        public String toString() {
2170
            return this.toString(formatter());
2171
        }
2172

    
2173
        @Override
2174
        public String toString(Formatter<Value> formatter) {
2175
            if (formatter!=null && formatter.canApply(this)) {
2176
                return formatter.format(this);
2177
            }
2178
            StringBuilder builder = new StringBuilder();
2179
            boolean first = true;
2180
            for (String sql : toStrings(formatter)) {
2181
                if (StringUtils.isEmpty(sql)) {
2182
                    continue;
2183
                }
2184
                if (first) {
2185
                    first = false;
2186
                } else {
2187
                    builder.append("; ");
2188
                }
2189
                builder.append(sql);
2190
            }
2191
            return builder.toString();
2192
        }
2193

    
2194
        @Override
2195
        public List<String> toStrings() {
2196
            return this.toStrings(formatter());
2197
        }
2198

    
2199
        @Override
2200
        public List<String> toStrings(Formatter formatter) {
2201
            StringBuilder builder = new StringBuilder();
2202
            builder.append("CREATE ");
2203
            if (this.isUnique) {
2204
                builder.append("UNIQUE ");
2205
            }
2206
            builder.append("INDEX ");
2207
            if (this.ifNotExist) {
2208
                builder.append("IF NOT EXISTS ");
2209
            }
2210
            builder.append(as_identifier(this.indexName));
2211
            builder.append(" ON ");
2212
            builder.append(this.table.toString(formatter));
2213
            if (this.isSpatial) {
2214
                builder.append(" USING GIST ");
2215
            }
2216
            builder.append(" ( ");
2217
            boolean is_first_column = true;
2218
            for (String column : this.columns) {
2219
                if (is_first_column) {
2220
                    is_first_column = false;
2221
                } else {
2222
                    builder.append(", ");
2223
                }
2224
                builder.append(column);
2225
            }
2226
            builder.append(" )");
2227

    
2228
            List<String> sqls = new ArrayList<>();
2229
            sqls.add(builder.toString());
2230
            return sqls;
2231
        }
2232

    
2233
    }
2234

    
2235
    public class DropIndexBuilderBase
2236
            extends AbstractStatement
2237
            implements DropIndexBuilder {
2238

    
2239
        protected boolean ifNotExist = false;
2240
        protected String indexName;
2241

    
2242
        public DropIndexBuilderBase() {
2243
        }
2244

    
2245
        @Override
2246
        public DropIndexBuilder if_not_exist() {
2247
            this.ifNotExist = true;
2248
            return this;
2249
        }
2250

    
2251
        @Override
2252
        public DropIndexBuilder name(String name) {
2253
            this.indexName = name;
2254
            return this;
2255
        }
2256

    
2257
        @Override
2258
        public DropIndexBuilder name(String tableName, String columnName) {
2259
            this.indexName = tableName + "_IDX_" + columnName;
2260
            return this;
2261
        }
2262

    
2263
        @Override
2264
        public String toString() {
2265
            return this.toString(formatter());
2266
        }
2267

    
2268
        @Override
2269
        public String toString(Formatter<Value> formatter) {
2270
            if (formatter!=null && formatter.canApply(this)) {
2271
                return formatter.format(this);
2272
            }
2273
            StringBuilder builder = new StringBuilder();
2274
            boolean first = true;
2275
            for (String sql : toStrings(formatter)) {
2276
                if (StringUtils.isEmpty(sql)) {
2277
                    continue;
2278
                }
2279
                if (first) {
2280
                    first = false;
2281
                } else {
2282
                    builder.append("; ");
2283
                }
2284
                builder.append(sql);
2285
            }
2286
            return builder.toString();
2287
        }
2288

    
2289
        @Override
2290
        public List<String> toStrings() {
2291
            return this.toStrings(formatter());
2292
        }
2293

    
2294
        @Override
2295
        public List<String> toStrings(Formatter formatter) {
2296
            StringBuilder builder = new StringBuilder();
2297
            builder.append("DROP INDEX ");
2298
            if (this.ifNotExist) {
2299
                builder.append("IF NOT EXISTS ");
2300
            }
2301
            builder.append(as_identifier(this.indexName));
2302
            List<String> sqls = new ArrayList<>();
2303
            sqls.add(builder.toString());
2304
            return sqls;
2305
        }
2306

    
2307
    }
2308

    
2309
    public class AlterTableBuilderBase
2310
            extends AbstractStatement
2311
            implements AlterTableBuilder {
2312

    
2313
        protected TableNameBuilder table;
2314
        protected List<String> drops;
2315
        protected List<ColumnDescriptor> adds;
2316
        protected List<ColumnDescriptor> alters;
2317
        protected List<Pair<String, String>> renames;
2318
        protected String drop_primary_key_column;
2319

    
2320
        public AlterTableBuilderBase() {
2321
            this.drops = new ArrayList<>();
2322
            this.adds = new ArrayList<>();
2323
            this.alters = new ArrayList<>();
2324
            this.renames = new ArrayList<>();
2325
        }
2326

    
2327
        @Override
2328
        public boolean isEmpty() {
2329
            return this.drops.isEmpty()
2330
                    && this.adds.isEmpty()
2331
                    && this.alters.isEmpty()
2332
                    && this.renames.isEmpty();
2333
        }
2334

    
2335
        @Override
2336
        public void accept(Visitor visitor, VisitorFilter filter) {
2337
            boolean visitChildren = true;
2338
            if (filter==null || filter.accept(this)) {
2339
                visitor.visit(this);
2340
            } else {
2341
                visitChildren = !filter.skipChildren();
2342
            }
2343
            if(visitChildren){
2344
                if (this.table != null) {
2345
                    this.table.accept(visitor, filter);
2346
                }
2347
            }
2348
        }
2349

    
2350
        @Override
2351
        public TableNameBuilder table() {
2352
            if (table == null) {
2353
                table = createTableNameBuilder();
2354
            }
2355
            return table;
2356
        }
2357

    
2358
        @Override
2359
        public AlterTableBuilder drop_column(String columnName) {
2360
            this.drops.add(columnName);
2361
            return this;
2362
        }
2363

    
2364
        @Override
2365
        public AlterTableBuilder drop_primary_key(String columnName) {
2366
            this.drop_primary_key_column = columnName;
2367
            return this;
2368
        }
2369

    
2370
        @Override
2371
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2372
            this.adds.add(new ColumnDescriptorBase(fad));
2373
            return this;
2374
        }
2375

    
2376
        @Override
2377
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2378
            if (isPk || isAutomatic) {
2379
                allowNulls = false;
2380
            }
2381
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2382
            return this;
2383
        }
2384

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

    
2394
        @Override
2395
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2396
            if (StringUtils.isEmpty(columnName)) {
2397
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2398
            }
2399
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2400
            return this;
2401
        }
2402

    
2403
        @Override
2404
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2405
            this.alters.add(new ColumnDescriptorBase(fad));
2406
            return this;
2407
        }
2408

    
2409
        @Override
2410
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2411
            if (isPk || isAutomatic) {
2412
                allowNulls = false;
2413
            }
2414
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2415
            return this;
2416
        }
2417

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

    
2427
        @Override
2428
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2429
            if (StringUtils.isEmpty(columnName)) {
2430
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2431
            }
2432
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2433
            return this;
2434
        }
2435

    
2436
        @Override
2437
        public AlterTableBuilder rename_column(String source, String target) {
2438
            this.renames.add(new ImmutablePair(source, target));
2439
            return this;
2440
        }
2441

    
2442
        protected String getConstrainName(String constrainType, String columnName) {
2443
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2444
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2445
            return constraint_name;
2446
        }
2447

    
2448
        @Override
2449
        public String toString() {
2450
            return this.toString(formatter());
2451
        }
2452

    
2453
        @Override
2454
        public String toString(Formatter<Value> formatter) {
2455
            if (formatter!=null && formatter.canApply(this)) {
2456
                return formatter.format(this);
2457
            }
2458
            StringBuilder builder = new StringBuilder();
2459
            boolean first = true;
2460
            for (String sql : toStrings(formatter)) {
2461
                if (StringUtils.isEmpty(sql)) {
2462
                    continue;
2463
                }
2464
                if (first) {
2465
                    first = false;
2466
                } else {
2467
                    builder.append("; ");
2468
                }
2469
                builder.append(sql);
2470
            }
2471
            return builder.toString();
2472
        }
2473

    
2474
        @Override
2475
        public List<String> toStrings() {
2476
            return this.toStrings(formatter());
2477
        }
2478

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

    
2588
    }
2589

    
2590
    public class CreateTableBuilderBase
2591
            extends AbstractStatement
2592
            implements CreateTableBuilder {
2593

    
2594
        protected TableNameBuilder table;
2595
        protected List<ColumnDescriptor> columns;
2596

    
2597
        public CreateTableBuilderBase() {
2598
            this.columns = new ArrayList<>();
2599
        }
2600

    
2601
        @Override
2602
        public void accept(Visitor visitor, VisitorFilter filter) {
2603
            boolean visitChildren = true;
2604
            if (filter==null || filter.accept(this)) {
2605
                visitor.visit(this);
2606
            } else {
2607
                visitChildren = !filter.skipChildren();
2608
            }
2609
            if(visitChildren){
2610
                if (this.table != null) {
2611
                    this.table.accept(visitor, filter);
2612
                }
2613
            }
2614
        }
2615

    
2616
        @Override
2617
        public TableNameBuilder table() {
2618
            if (table == null) {
2619
                table = createTableNameBuilder();
2620
            }
2621
            return table;
2622
        }
2623

    
2624
        @Override
2625
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2626
            this.columns.add(new ColumnDescriptorBase(fad));
2627
            return this;
2628
        }
2629

    
2630
        @Override
2631
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2632
            if (StringUtils.isEmpty(columnName)) {
2633
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2634
            }
2635
            if (isPk || isAutomatic) {
2636
                allowNulls = false;
2637
            }
2638
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2639
            return this;
2640
        }
2641

    
2642
        @Override
2643
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2644
            if (StringUtils.isEmpty(columnName)) {
2645
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2646
            }
2647
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2648
            return this;
2649
        }
2650

    
2651
        @Override
2652
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2653
            if (StringUtils.isEmpty(columnName)) {
2654
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2655
            }
2656
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2657
            return this;
2658
        }
2659

    
2660
        @Override
2661
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2662
            if (StringUtils.isEmpty(columnName)) {
2663
                return null;
2664
            }
2665
            for (ColumnDescriptor column : columns) {
2666
                if (columnName.equals(column.getName())) {
2667
                    return column;
2668
                }
2669
            }
2670
            return null;
2671
        }
2672

    
2673
        @Override
2674
        public String toString() {
2675
            return this.toString(formatter());
2676
        }
2677

    
2678
        @Override
2679
        public String toString(Formatter<Value> formatter) {
2680
            if (formatter!=null && formatter.canApply(this)) {
2681
                return formatter.format(this);
2682
            }
2683
            StringBuilder builder = new StringBuilder();
2684
            boolean first = true;
2685
            for (String sql : toStrings(formatter)) {
2686
                if (StringUtils.isEmpty(sql)) {
2687
                    continue;
2688
                }
2689
                if (first) {
2690
                    first = false;
2691
                } else {
2692
                    builder.append("; ");
2693
                }
2694
                builder.append(sql);
2695
            }
2696
            return builder.toString();
2697
        }
2698

    
2699
        @Override
2700
        public List<String> toStrings() {
2701
            return this.toStrings(formatter());
2702
        }
2703

    
2704
        @Override
2705
        /*
2706
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
2707
        */
2708
        public List<String> toStrings(Formatter formatter) {
2709
            List<String> sqls = new ArrayList<>();
2710
            /**
2711
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2712
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2713
             * column_constraint [ ... ] ] | table_constraint | LIKE
2714
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2715
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2716
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2717
             *
2718
             * where column_constraint is:
2719
             *
2720
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2721
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2722
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2723
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2724
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2725
             *
2726
             * and table_constraint is:
2727
             *
2728
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2729
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2730
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2731
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2732
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2733
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2734
             */
2735
            
2736
            StringBuilder builder = new StringBuilder();
2737

    
2738
            builder.append("CREATE TABLE ");
2739
            builder.append(this.table.toString(formatter));
2740
            builder.append(" (");
2741
            boolean first = true;
2742
            for (ColumnDescriptor column : columns) {
2743
                if (first) {
2744
                    first = false;
2745
                } else {
2746
                    builder.append(", ");
2747
                }
2748
                builder.append(as_identifier(column.getName()));
2749
                builder.append(" ");
2750
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2751
                    builder.append("SERIAL");
2752
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2753
                    builder.append("BIGSERIAL");
2754
                } else {
2755
                    builder.append(sqltype(
2756
                            column.getType(),
2757
                            column.getSize(),
2758
                            column.getPrecision(),
2759
                            column.getScale(),
2760
                            column.getGeometryType(),
2761
                            column.getGeometrySubtype()
2762
                    )
2763
                    );
2764
                }
2765
                if (column.getDefaultValue() == null) {
2766
                    if (column.allowNulls()) {
2767
                        builder.append(" DEFAULT NULL");
2768
                    }
2769
                } else {
2770
                    builder.append(" DEFAULT '");
2771
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2772
                    builder.append("'");
2773
                }
2774
                if (column.allowNulls()) {
2775
                    builder.append(" NULL");
2776
                } else {
2777
                    builder.append(" NOT NULL");
2778
                }
2779
                if (column.isPrimaryKey()) {
2780
                    builder.append(" PRIMARY KEY");
2781
                }
2782
            }
2783
            builder.append(" )");
2784
            sqls.add(builder.toString());
2785
            return sqls;
2786
        }
2787
    }
2788

    
2789
    public class InsertColumnBuilderBase
2790
            extends AbstractStatement
2791
            implements InsertColumnBuilder {
2792

    
2793
        protected Variable name;
2794
        protected Value value;
2795

    
2796
        public InsertColumnBuilderBase() {
2797
        }
2798

    
2799
        @Override
2800
        public void accept(Visitor visitor, VisitorFilter filter) {
2801
            boolean visitChildren = true;
2802
            if (filter==null || filter.accept(this)) {
2803
                visitor.visit(this);
2804
            } else {
2805
                visitChildren = !filter.skipChildren();
2806
            }
2807
            if(visitChildren){
2808
                if (this.name != null) {
2809
                    this.name.accept(visitor, filter);
2810
                }
2811
                if (this.value != null) {
2812
                    this.value.accept(visitor, filter);
2813
                }
2814
            }
2815
        }
2816

    
2817
        @Override
2818
        public InsertColumnBuilder name(String name) {
2819
            this.name = expression().variable(name);
2820
            return this;
2821
        }
2822

    
2823
        @Override
2824
        public InsertColumnBuilder with_value(Value value) {
2825
            this.value = value;
2826
            return this;
2827
        }
2828

    
2829
        @Override
2830
        public String getName() {
2831
            return this.name.name();
2832
        }
2833

    
2834
        @Override
2835
        public Value getValue() {
2836
            return this.value;
2837
        }
2838

    
2839
        @Override
2840
        public String toString() {
2841
            return this.toString(formatter());
2842
        }
2843

    
2844
        @Override
2845
        public String toString(Formatter<Value> formatter) {
2846
            if (formatter!=null && formatter.canApply(this)) {
2847
                return formatter.format(this);
2848
            }
2849
            return this.value.toString(formatter);
2850
        }
2851
    }
2852

    
2853
    public class InsertBuilderBase
2854
            extends AbstractStatement
2855
            implements InsertBuilder {
2856

    
2857
        protected List<InsertColumnBuilder> columns;
2858
        protected TableNameBuilder table;
2859

    
2860
        public InsertBuilderBase() {
2861
            this.columns = new ArrayList<>();
2862
        }
2863

    
2864
        @Override
2865
        public void accept(Visitor visitor, VisitorFilter filter) {
2866
            boolean visitChildren = true;
2867
            if (filter==null || filter.accept(this)) {
2868
                visitor.visit(this);
2869
            } else {
2870
                visitChildren = !filter.skipChildren();
2871
            }
2872
            if(visitChildren){
2873
                if (this.table != null) {
2874
                    this.table.accept(visitor, filter);
2875
                }
2876
                for (InsertColumnBuilder column : columns) {
2877
                    column.accept(visitor, filter);
2878
                }
2879
            }
2880
        }
2881

    
2882
        @Override
2883
        public TableNameBuilder table() {
2884
            if (table == null) {
2885
                table = createTableNameBuilder();
2886
            }
2887
            return table;
2888
        }
2889

    
2890
        @Override
2891
        public InsertColumnBuilder column() {
2892
            InsertColumnBuilder column = createInsertColumnBuilder();
2893
            this.columns.add(column);
2894
            return column;
2895
        }
2896

    
2897
        @Override
2898
        public String toString() {
2899
            return this.toString(formatter());
2900
        }
2901

    
2902
        @Override
2903
        public String toString(Formatter<Value> formatter) {
2904
            if (formatter!=null && formatter.canApply(this)) {
2905
                return formatter.format(this);
2906
            }
2907
            /*
2908
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2909
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2910
             * output_expression [ AS output_name ] [, ...] ]
2911
             */
2912
            StringBuilder builderColumns = new StringBuilder();
2913
            StringBuilder builderValues = new StringBuilder();
2914

    
2915
            boolean first = true;
2916
            for (InsertColumnBuilder column : columns) {
2917
                if (first) {
2918
                    first = false;
2919
                } else {
2920
                    builderColumns.append(", ");
2921
                }
2922
                builderColumns.append(as_identifier(column.getName()));
2923
            }
2924
            first = true;
2925
            for (InsertColumnBuilder column : columns) {
2926
                if (first) {
2927
                    first = false;
2928
                } else {
2929
                    builderValues.append(", ");
2930
                }
2931
                builderValues.append(column.toString(formatter));
2932
            }
2933

    
2934
            String sql = MessageFormat.format(
2935
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2936
                    this.table.toString(formatter),
2937
                    builderColumns.toString(),
2938
                    builderValues.toString()
2939
            );
2940
            return sql;
2941

    
2942
        }
2943
    }
2944

    
2945
    public class UpdateTableStatisticsBuilderBase
2946
            extends AbstractStatement
2947
            implements UpdateTableStatisticsBuilder {
2948

    
2949
        protected TableNameBuilder table;
2950

    
2951
        @Override
2952
        public void accept(Visitor visitor, VisitorFilter filter) {
2953
            boolean visitChildren = true;
2954
            if (filter==null || filter.accept(this)) {
2955
                visitor.visit(this);
2956
            } else {
2957
                visitChildren = !filter.skipChildren();
2958
            }
2959
            if(visitChildren){
2960
                if (this.table != null) {
2961
                    this.table.accept(visitor, filter);
2962
                }
2963
            }
2964
        }
2965

    
2966
        @Override
2967
        public TableNameBuilder table() {
2968
            if (table == null) {
2969
                table = createTableNameBuilder();
2970
            }
2971
            return table;
2972
        }
2973

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

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

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

    
3005
        @Override
3006
        public List<String> toStrings(Formatter formatter) {
3007
            List<String> sqls = new ArrayList<>();
3008

    
3009
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
3010
                String sql = MessageFormat.format(
3011
                        STMT_UPDATE_TABLE_STATISTICS_table,
3012
                        table.toString(formatter)
3013
                );
3014
                if (!StringUtils.isEmpty(sql)) {
3015
                    sqls.add(sql);
3016
                }
3017
            }
3018
            return sqls;
3019
        }
3020
    }
3021

    
3022
    protected GeometryExpressionBuilder expressionBuilder;
3023

    
3024
    protected String defaultSchema;
3025
    protected boolean supportSchemas;
3026
    protected boolean hasSpatialFunctions;
3027
    protected GeometrySupportType geometrySupportType;
3028
    protected boolean allowAutomaticValues;
3029

    
3030
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
3031

    
3032
    protected String constant_true = "(1=1)";
3033
    protected String constant_false = "(1<>1)";
3034

    
3035
    protected String type_boolean = "BOOLEAN";
3036
    protected String type_byte = "TINYINT";
3037
    protected String type_bytearray = "BYTEA";
3038
    protected String type_geometry = "TEXT";
3039
    protected String type_char = "CHARACTER(1)";
3040
    protected String type_date = "DATE";
3041
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
3042
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
3043
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
3044
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
3045
    protected String type_int = "INT";
3046
    protected String type_long = "BIGINT";
3047
    protected String type_string = "TEXT";
3048
    protected String type_string_p = "VARCHAR({0,Number,#######})";
3049
    protected String type_time = "TIME";
3050
    protected String type_timestamp = "TIMESTAMP";
3051
    protected String type_version = "VARCHAR(30)";
3052
    protected String type_URI = "TEXT";
3053
    protected String type_URL = "TEXT";
3054
    protected String type_FILE = "TEXT";
3055
    protected String type_FOLDER = "TEXT";
3056

    
3057
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
3058
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
3059
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
3060
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
3061
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
3062
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
3063
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
3064
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
3065
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
3066
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
3067

    
3068
    public SQLBuilderBase() {
3069
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3070
        this.expressionBuilder.setProperty(PROP_SQLBUILDER, this);
3071

    
3072
        this.hasSpatialFunctions = false;
3073
        this.supportSchemas = true;
3074
        this.geometrySupportType = GeometrySupportType.WKT;
3075

    
3076
        this.defaultSchema = "public";
3077
        this.allowAutomaticValues = true;
3078

    
3079
    }
3080
    
3081
    @Override
3082
    public void setProperties(Class filter, final Object... values) {
3083
        this.expressionBuilder.setProperties(filter, values);
3084
        setProperties(this, filter, values);
3085
    }
3086
    
3087
    @Override
3088
    public void setProperties(Visitable visitable, Class filter, final Object... values) {
3089
        if(visitable == null){
3090
            return;
3091
        }
3092
        if(visitable instanceof PropertiesSupport){
3093
            for (int i = 0; i < values.length; i+=2) {
3094
                ((PropertiesSupport)visitable).setProperty((String) values[i], values[i+1]);
3095
            }
3096
        }
3097
        visitable.accept((Visitable v) -> {
3098
            if(v instanceof PropertiesSupport){
3099
                for (int i = 0; i < values.length; i+=2) {
3100
                    ((PropertiesSupport)v).setProperty((String) values[i], values[i+1]);
3101
                }
3102
            }
3103
        }, new ClassVisitorFilter(filter) );
3104
    }
3105

    
3106
    public String quote_for_identifiers() {
3107
        return "\"";
3108
    }
3109

    
3110
    public String quote_for_strings() {
3111
        return "'";
3112
    }
3113

    
3114
    @Override
3115
    public String as_identifier(String id) {
3116
        String quote = this.quote_for_identifiers();
3117
//        No se porque no esta disponible wrapIfMissing
3118
//        return StringUtils.wrapIfMissing(id,quote);
3119
        if (id.startsWith(quote)) {
3120
            return id;
3121
        }
3122
        return quote + id + quote;
3123

    
3124
    }
3125

    
3126
    @Override
3127
    public String as_string(String s) {
3128
        String quote = this.quote_for_strings();
3129
//        No se porque no esta disponible wrapIfMissing
3130
//        return StringUtils.wrapIfMissing(id,quote);
3131
        if (s.startsWith(quote)) {
3132
            return s;
3133
        }
3134
        return quote + s + quote;
3135

    
3136
    }
3137

    
3138
    @Override
3139
    public String as_string(byte[] data) {
3140
        return this.expressionBuilder.bytearray_0x(data);
3141
//        return this.expressionBuilder.bytearray_hex(data);
3142
//        return this.expressionBuilder.bytearray_x(data);
3143
    }
3144
    
3145
    @Override
3146
    public String as_string(boolean value) {
3147
        return value? "TRUE" : "FALSE";
3148
    }
3149

    
3150
    @Override
3151
    public String as_string(Number value) {
3152
        return Objects.toString(value);
3153
    }
3154
    
3155
    @Override
3156
    public String as_string(Object value) {
3157
        if( value == null ) {
3158
            return "NULL";
3159
        }
3160
        if( value instanceof CharSequence ) {
3161
            return as_string(value.toString());
3162
        }
3163
        if( value instanceof Number ) {
3164
            return as_string((Number)value);
3165
        }
3166
        if( value instanceof Boolean ) {
3167
            return as_string((boolean)value);
3168
        }
3169
        if( value instanceof byte[] ) {
3170
            return as_string((byte[])value);
3171
        }
3172
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
3173
    }
3174
    
3175
    @Override
3176
    public GeometryExpressionBuilder expression() {
3177
        return this.expressionBuilder;
3178
    }
3179

    
3180
    @Override
3181
    public boolean has_spatial_functions() {
3182
        return this.hasSpatialFunctions;
3183
    }
3184

    
3185
    @Override
3186
    public GeometrySupportType geometry_support_type() {
3187
        return this.geometrySupportType;
3188
    }
3189

    
3190
    protected GeometryExpressionBuilder createExpressionBuilder() {
3191
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3192
    }
3193

    
3194
    @Override
3195
    public Object srs_id(IProjection projection) {
3196
        String abrev = projection.getAbrev();
3197
        return abrev.split(":")[1].trim();
3198
    }
3199

    
3200
    @Override
3201
    public String default_schema() {
3202
        return this.defaultSchema;
3203
    }
3204

    
3205
    @Override
3206
    public boolean support_schemas() {
3207
        return this.supportSchemas;
3208
    }
3209

    
3210
    @Override
3211
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
3212
        switch (type) {
3213
            case DataTypes.BOOLEAN:
3214
                return type_boolean;
3215
            case DataTypes.CHAR:
3216
                return type_char;
3217

    
3218

    
3219
            case DataTypes.BYTE:
3220
                return type_byte;
3221
            case DataTypes.INT:
3222
                return type_int;
3223
            case DataTypes.LONG:
3224
                return type_long;
3225

    
3226
            case DataTypes.FLOAT:
3227
                return type_float;
3228
            case DataTypes.DOUBLE:
3229
                return type_double;
3230
            case DataTypes.DECIMAL:
3231
                if (precision < 1) {
3232
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
3233
                }
3234
                if (scale < 1) {
3235
                  return MessageFormat.format(type_decimal_p, precision);
3236
                }
3237
                return MessageFormat.format(type_decimal_ps, precision, scale);
3238

    
3239
                
3240
            case DataTypes.STRING:
3241
                if (size < 0) {
3242
                    return type_string;
3243
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3244
                    return MessageFormat.format(type_string_p, size);
3245
                }
3246
                return type_string;
3247

    
3248
                
3249
            case DataTypes.DATE:
3250
                return type_date;
3251
            case DataTypes.TIME:
3252
                return type_time;
3253
            case DataTypes.TIMESTAMP:
3254
                return type_timestamp;
3255

    
3256
            case DataTypes.BYTEARRAY:
3257
                return type_bytearray;
3258

    
3259
            case DataTypes.GEOMETRY:
3260
                return type_geometry;
3261

    
3262
            case DataTypes.VERSION:
3263
                return type_version;
3264
            case DataTypes.URI:
3265
                return type_URI;
3266
            case DataTypes.URL:
3267
                return type_URL;
3268
            case DataTypes.FILE:
3269
                return type_FILE;
3270
            case DataTypes.FOLDER:
3271
                return type_FOLDER;
3272
            default:
3273
                return null;
3274
        }
3275
    }
3276

    
3277
    @Override
3278
    public Object sqlgeometrytype(int type, int subtype) {
3279
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3280
        // identificadores numericos para el tipo y otros strings.
3281
        // Por defecto vamos a devolver strings.
3282
        if (sqlgeometrytypes == null) {
3283
            sqlgeometrytypes = new HashMap<>();
3284
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3285
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3286
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3287
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3288

    
3289
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3290
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3291
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3292
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3293

    
3294
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3295
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3296
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3297
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3298

    
3299
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3300
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3301
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3302
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3303

    
3304
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3305
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3306
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3307
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3308

    
3309
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3310
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3311
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3312
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3313

    
3314
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3315
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3316
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3317
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3318

    
3319
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3320
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3321
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3322
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3323

    
3324
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3325
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3326
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3327
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3328
        }
3329
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3330
    }
3331

    
3332
    @Override
3333
    public Object sqlgeometrydimension(int type, int subtype) {
3334
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3335
        // identificadores numericos para las dimensiones y otros strings.
3336
        // Por defecto vamos a devolver enteros.
3337
        switch (subtype) {
3338
            case Geometry.SUBTYPES.GEOM3D:
3339
                return 3;
3340
            case Geometry.SUBTYPES.GEOM2DM:
3341
                return 3;
3342
            case Geometry.SUBTYPES.GEOM3DM:
3343
                return 4;
3344
            case Geometry.SUBTYPES.GEOM2D:
3345
            default:
3346
                return 2;
3347
        }
3348
    }
3349

    
3350
    @Override
3351
    public SelectColumnBuilder column() {
3352
        return createSelectColumnBuilder();
3353
    }
3354

    
3355
    @Override
3356
    public TableNameBuilder createTableNameBuilder() {
3357
        return new TableNameBuilderBase();
3358
    }
3359

    
3360
    protected SelectColumnBuilder createSelectColumnBuilder() {
3361
        return new SelectColumnBuilderBase(this);
3362
    }
3363

    
3364
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3365
        return new UpdateColumnBuilderBase();
3366
    }
3367

    
3368
    protected InsertColumnBuilder createInsertColumnBuilder() {
3369
        return new InsertColumnBuilderBase();
3370
    }
3371

    
3372
    protected OrderByBuilder createOrderByBuilder() {
3373
        return new OrderByBuilderBase();
3374
    }
3375

    
3376
    protected FromBuilder createFromBuilder() {
3377
        return new FromBuilderBase();
3378
    }
3379

    
3380
    public SelectBuilder createSelectBuilder() {
3381
        return new SelectBuilderBase();
3382
    }
3383

    
3384
    protected UpdateBuilder createUpdateBuilder() {
3385
        return new UpdateBuilderBase();
3386
    }
3387

    
3388
    protected DeleteBuilder createDeleteBuilder() {
3389
        return new DeleteBuilderBase();
3390
    }
3391

    
3392
    protected GrantBuilder createGrantBuilder() {
3393
        return new GrantBuilderBase();
3394
    }
3395

    
3396
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3397
        return new GrantRoleBuilderBase(table, role);
3398
    }
3399

    
3400
    protected DropTableBuilder createDropTableBuilder() {
3401
        return new DropTableBuilderBase();
3402
    }
3403

    
3404
    protected CreateTableBuilder createCreateTableBuilder() {
3405
        return new CreateTableBuilderBase();
3406
    }
3407

    
3408
    protected AlterTableBuilder createAlterTableBuilder() {
3409
        return new AlterTableBuilderBase();
3410
    }
3411

    
3412
    protected InsertBuilder createInsertBuilder() {
3413
        return new InsertBuilderBase();
3414
    }
3415

    
3416
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3417
        return new UpdateTableStatisticsBuilderBase();
3418
    }
3419

    
3420
    protected CreateIndexBuilder createCreateIndexBuilder() {
3421
        return new CreateIndexBuilderBase();
3422
    }
3423

    
3424
    protected DropIndexBuilder createDropIndexBuilder() {
3425
        return new DropIndexBuilderBase();
3426
    }
3427

    
3428
    @Override
3429
    public SelectBuilder select() {
3430
        if (this.select == null) {
3431
            this.select = this.createSelectBuilder();
3432
        }
3433
        return this.select;
3434
    }
3435

    
3436
    @Override
3437
    public UpdateBuilder update() {
3438
        if (this.update == null) {
3439
            this.update = this.createUpdateBuilder();
3440
        }
3441
        return this.update;
3442
    }
3443

    
3444
    @Override
3445
    public UpdateTableStatisticsBuilder update_table_statistics() {
3446
        if (this.update_table_statistics == null) {
3447
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3448
        }
3449
        return this.update_table_statistics;
3450
    }
3451

    
3452
    @Override
3453
    public DropTableBuilder drop_table() {
3454
        if (this.drop_table == null) {
3455
            this.drop_table = this.createDropTableBuilder();
3456
        }
3457
        return this.drop_table;
3458
    }
3459

    
3460
    @Override
3461
    public CreateIndexBuilder create_index() {
3462
        if (this.create_index == null) {
3463
            this.create_index = this.createCreateIndexBuilder();
3464
        }
3465
        return this.create_index;
3466
    }
3467

    
3468
    @Override
3469
    public DropIndexBuilder drop_index() {
3470
        if (this.drop_index == null) {
3471
            this.drop_index = this.createDropIndexBuilder();
3472
        }
3473
        return this.drop_index;
3474
    }
3475

    
3476
    @Override
3477
    public DeleteBuilder delete() {
3478
        if (this.delete == null) {
3479
            this.delete = this.createDeleteBuilder();
3480
        }
3481
        return this.delete;
3482
    }
3483

    
3484
    @Override
3485
    public InsertBuilder insert() {
3486
        if (this.insert == null) {
3487
            this.insert = this.createInsertBuilder();
3488
        }
3489
        return this.insert;
3490
    }
3491

    
3492
    @Override
3493
    public TableNameBuilder table_name() {
3494
        if (this.table_name == null) {
3495
            this.table_name = this.createTableNameBuilder();
3496
        }
3497
        return this.table_name;
3498
    }
3499

    
3500
    
3501
    @Override
3502
    public AlterTableBuilder alter_table() {
3503
        if (this.alter_table == null) {
3504
            this.alter_table = this.createAlterTableBuilder();
3505
        }
3506
        return this.alter_table;
3507
    }
3508

    
3509
    @Override
3510
    public CreateTableBuilder create_table() {
3511
        if (this.create_table == null) {
3512
            this.create_table = this.createCreateTableBuilder();
3513
        }
3514
        return this.create_table;
3515
    }
3516

    
3517
    @Override
3518
    public GrantBuilder grant() {
3519
        if (this.grant == null) {
3520
            this.grant = this.createGrantBuilder();
3521
        }
3522
        return this.grant;
3523
    }
3524
    
3525
    @Override
3526
    public Column column(String name) {
3527
        ColumnBase col = new ColumnBase(null, name);
3528
        return col;
3529
    }
3530

    
3531
    @Override
3532
    public Column column(TableNameBuilder table, String name) {
3533
        ColumnBase col = new ColumnBase(table, name);
3534
        return col;
3535
    }
3536
    
3537
    public Column column_from(Variable variable) {
3538
        Column c = null;
3539
        if (variable instanceof Column) {
3540
            c = this.column(((Column) variable).table(), variable.name());
3541
        } else {
3542
            c = this.column(variable.name());
3543
        }
3544
        c.copyPropertiesFrom(variable);
3545
        return c;
3546

    
3547
    }
3548

    
3549
    public Column column_from(TableNameBuilder table, Variable variable) {
3550
        Column c = this.column(table, variable.name());
3551
        c.copyPropertiesFrom(variable);
3552
        return c;
3553
    }
3554
        
3555

    
3556
    
3557
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3558
        return new JoinBase(type, table, expression);
3559
    }
3560

    
3561
    @Override
3562
    public void accept(Visitor visitor, VisitorFilter filter) {
3563
        if (this.select != null) {
3564
            this.select.accept(visitor, filter);
3565
        }
3566
        if (this.update != null) {
3567
            this.update.accept(visitor, filter);
3568
        }
3569
        if (this.insert != null) {
3570
            this.insert.accept(visitor, filter);
3571
        }
3572
        if (this.delete != null) {
3573
            this.delete.accept(visitor, filter);
3574
        }
3575
        if (this.alter_table != null) {
3576
            this.alter_table.accept(visitor, filter);
3577
        }
3578
        if (this.create_table != null) {
3579
            this.create_table.accept(visitor, filter);
3580
        }
3581
        if (this.drop_table != null) {
3582
            this.drop_table.accept(visitor, filter);
3583
        }
3584
        if (this.table_name != null) {
3585
            this.table_name.accept(visitor, filter);
3586
        }
3587
    }
3588

    
3589
    @Override
3590
    public Formatter formatter() {
3591
        return expression().formatter();
3592
    }
3593

    
3594
    @Override
3595
    public String toString() {
3596
        return this.toString(formatter());
3597
    }
3598

    
3599
    @Override
3600
    public String toString(Formatter formatter) {
3601
        if (this.select != null) {
3602
            return this.select.toString(formatter);
3603
        }
3604
        if (this.update != null) {
3605
            return this.update.toString(formatter);
3606
        }
3607
        if (this.insert != null) {
3608
            return this.insert.toString(formatter);
3609
        }
3610
        if (this.delete != null) {
3611
            return this.delete.toString(formatter);
3612
        }
3613
        if (this.alter_table != null) {
3614
            return this.alter_table.toString(formatter);
3615
        }
3616
        if (this.create_table != null) {
3617
            return this.create_table.toString(formatter);
3618
        }
3619
        if (this.drop_table != null) {
3620
            return this.drop_table.toString(formatter);
3621
        }
3622
        if (this.update_table_statistics != null) {
3623
            return this.update_table_statistics.toString(formatter);
3624
        }
3625
        if (this.create_index != null) {
3626
            return this.create_index.toString(formatter);
3627
        }
3628
        if (this.drop_index != null) {
3629
            return this.drop_index.toString(formatter);
3630
        }
3631
        if (this.table_name != null) {
3632
            return this.table_name.toString(formatter);
3633
        }
3634
        return "";
3635
    }
3636

    
3637
    @Override
3638
    public CountBuilder count() {
3639
        return new CountBuilderBase();
3640
    }
3641

    
3642
    @Override
3643
    public List<Parameter> parameters() {
3644
        final List<Parameter> params = new ArrayList<>();
3645
        this.accept((Visitable value) -> {
3646
            params.add((Parameter) value);
3647
        }, new ClassVisitorFilter(Parameter.class));
3648
        return params;
3649
    }
3650

    
3651
    @Override
3652
    public List<Variable> variables() {
3653
        final List<Variable> vars = new ArrayList<>();
3654
        this.accept(new Visitor() {
3655
            @Override
3656
            public void visit(Visitable value) {
3657
                if (!vars.contains((Variable) value)) {
3658
                    vars.add((Variable) value);
3659
                }
3660
            }
3661
        }, new ClassVisitorFilter(Variable.class));
3662
        return vars;
3663
    }
3664

    
3665
    @Override
3666
    public List<String> parameters_names() {
3667
        List<String> params = new ArrayList<>();
3668
        for (Parameter param : parameters()) {
3669
            String s;
3670
            switch (param.type()) {
3671
                case PARAMETER_TYPE_CONSTANT:
3672
                    Object theValue = param.value();
3673
                    if (theValue == null) {
3674
                        s = "null";
3675
                    } else if (theValue instanceof String) {
3676
                        s = "'" + (String) theValue + "'";
3677
                    } else {
3678
                        s = theValue.toString();
3679
                    }
3680
                    break;
3681
                case PARAMETER_TYPE_VARIABLE:
3682
                default:
3683
                    s = "\"" + param.name() + "\"";
3684
            }
3685
            params.add(s);
3686
        }
3687
        return params;
3688
    }
3689

    
3690
    @Override
3691
    public List<String> variables_names() {
3692
        List<String> vars = new ArrayList<>();
3693
        for (Variable var : this.variables()) {
3694
            vars.add(var.name());
3695
        }
3696
        Collections.sort(vars);
3697
        return vars;
3698
    }    
3699
    
3700
    protected String[] aggregateFunctionNames = new String[] {
3701
        "MAX",
3702
        "MIN",
3703
        "COUNT",
3704
        "SUM"
3705
    };
3706
    
3707
    @Override
3708
    public boolean isAggregateFunction(String funcname) {
3709
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
3710
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
3711
                return true;
3712
            }
3713
        }
3714
        return false;
3715
    }
3716

    
3717
    @Override
3718
    public int getMaxRecomendedSQLLength() {
3719
        return DEFAULT_RECOMENDED_SQL_LENGTH;
3720
    }
3721
    
3722
    
3723
}