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

History | View | Annotate | Download (95.9 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 org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType;
20
import org.gvsig.expressionevaluator.ExpressionBuilder.Parameter;
21
import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
22
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
23
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
24
import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
25
import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
26
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
27
import org.gvsig.expressionevaluator.Formatter;
28
import org.gvsig.fmap.dal.DataStoreParameters;
29
import org.gvsig.fmap.dal.DataTypes;
30
import org.gvsig.fmap.dal.SQLBuilder;
31
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
32
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
33
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
34
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
35
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
36
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
37
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
38
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
41
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
42
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
43
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
44
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
45
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
46
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
47
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
48
import org.gvsig.fmap.geom.Geometry;
49
import org.slf4j.Logger;
50
import org.slf4j.LoggerFactory;
51

    
52
@SuppressWarnings("UseSpecificCatch")
53
public class SQLBuilderBase implements SQLBuilder {
54

    
55
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
56

    
57
    protected SelectBuilder select;
58
    protected UpdateBuilder update;
59
    protected InsertBuilder insert;
60
    protected DeleteBuilder delete;
61
    protected AlterTableBuilder alter_table;
62
    protected CreateTableBuilder create_table;
63
    protected GrantBuilder grant;
64
    protected DropTableBuilder drop_table;
65
    protected UpdateTableStatisticsBuilder update_table_statistics;
66
    protected CreateIndexBuilder create_index;
67
    protected TableNameBuilder table_name;
68

    
69
    protected abstract class AbstractStatementPart extends AbstractValue {
70

    
71
    }
72

    
73
    protected abstract class AbstractStatement extends AbstractStatementPart {
74

    
75
    }
76

    
77
    protected class ColumnDescriptorBase implements ColumnDescriptor {
78

    
79
        private String name;
80
        private int type;
81
        private int type_p;
82
        private int type_s;
83
        private boolean isPk;
84
        private boolean _allowNulls;
85
        private boolean _isAutomatic;
86
        private Object defaultValue;
87
        private int geom_type;
88
        private int geom_subtype;
89
        private Object geom_srsdbcode;
90
        private boolean _isIndexed;
91
        private DataStoreParameters parameters = null;
92

    
93
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
94
            this.name = name;
95
            this.type = type;
96
            this.type_p = -1;
97
            this.type_s = -1;
98
            this.isPk = false;
99
            this._allowNulls = true;
100
            this._isAutomatic = false;
101
            this.defaultValue = defaultValue;
102
            this.geom_type = Geometry.TYPES.GEOMETRY;
103
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
104
            this.geom_srsdbcode = null;
105
            this._isIndexed = false;
106
        }
107

    
108
        public ColumnDescriptorBase(String name, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
109
            this.name = name;
110
            this.type = type;
111
            this.type_p = type_p;
112
            this.type_s = type_s;
113
            this.isPk = isPk;
114
            this._allowNulls = allowNulls;
115
            this._isAutomatic = isAutomatic;
116
            this.defaultValue = defaultValue;
117
            this.geom_type = Geometry.TYPES.GEOMETRY;
118
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
119
            this.geom_srsdbcode = null;
120
            this._isIndexed = isIndexed;
121
        }
122

    
123
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
124
            this.name = name;
125
            this.type = DataTypes.GEOMETRY;
126
            this.type_p = 0;
127
            this.type_s = 0;
128
            this.isPk = false;
129
            this._allowNulls = allowNulls;
130
            this._isAutomatic = false;
131
            this.defaultValue = null;
132
            this.geom_type = geom_type;
133
            this.geom_subtype = geom_subtype;
134
            this.geom_srsdbcode = srs_id(proj);
135
            this._isIndexed = isIndexed;
136
        }
137

    
138
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
139
            this.name = name;
140
            this.type = DataTypes.GEOMETRY;
141
            this.type_p = 0;
142
            this.type_s = 0;
143
            this.isPk = false;
144
            this._allowNulls = allowNulls;
145
            this._isAutomatic = false;
146
            this.defaultValue = null;
147
            this.geom_type = geom_type;
148
            this.geom_subtype = geom_subtype;
149
            this.geom_srsdbcode = srsdbcode;
150
            this._isIndexed = isIndexed;
151
        }
152

    
153
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
154
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
155
            this.type_p = fad.getPrecision();
156
            this.type_s = fad.getSize();
157
            this.isPk = fad.isPrimaryKey();
158
            this._allowNulls = fad.allowNull();
159
            this._isAutomatic = fad.isAutomatic();
160
            this._isIndexed = fad.isIndexed();
161

    
162
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
163
                this.geom_type = fad.getGeomType().getType();
164
                this.geom_subtype = fad.getGeomType().getSubType();
165
                this.geom_srsdbcode = fad.getSRS();
166
            }
167
        }
168
    
169

    
170
        @Override
171
        public String getName() {
172
            return this.name;
173
        }
174

    
175
        @Override
176
        public void setName(String name) {
177
            this.name = name;
178
        }
179

    
180
        @Override
181
        public int getType() {
182
            return this.type;
183
        }
184

    
185
        @Override
186
        public void setType(int type) {
187
            this.type = type;
188
        }
189

    
190
        @Override
191
        public int getPrecision() {
192
            return type_p;
193
        }
194

    
195
        @Override
196
        public void setPrecision(int precision) {
197
            this.type_p = precision;
198
        }
199

    
200
        @Override
201
        public int getSize() {
202
            return type_s;
203
        }
204

    
205
        @Override
206
        public void setSize(int size) {
207
            this.type_s = size;
208
        }
209

    
210
        @Override
211
        public boolean isPrimaryKey() {
212
            return isPk;
213
        }
214

    
215
        @Override
216
        public void setIsPrimaryKey(boolean isPk) {
217
            this.isPk = isPk;
218
        }
219

    
220
        @Override
221
        public boolean allowNulls() {
222
            return _allowNulls;
223
        }
224

    
225
        @Override
226
        public void setAllowNulls(boolean allowNulls) {
227
            this._allowNulls = allowNulls;
228
        }
229

    
230
        @Override
231
        public boolean isAutomatic() {
232
            return _isAutomatic;
233
        }
234

    
235
        @Override
236
        public boolean isIndexed() {
237
            return _isIndexed;
238
        }
239

    
240
        @Override
241
        public void setIsAutomatic(boolean isAutomatic) {
242
            this._isAutomatic = isAutomatic;
243
        }
244

    
245
        @Override
246
        public Object getDefaultValue() {
247
            return defaultValue;
248
        }
249

    
250
        @Override
251
        public void setDefaultValue(Object defaultValue) {
252
            this.defaultValue = defaultValue;
253
        }
254

    
255
        @Override
256
        public int getGeometryType() {
257
            return geom_type;
258
        }
259

    
260
        @Override
261
        public void setGeometryType(int geom_type) {
262
            this.geom_type = geom_type;
263
        }
264

    
265
        @Override
266
        public int getGeometrySubtype() {
267
            return geom_subtype;
268
        }
269

    
270
        @Override
271
        public void setGeometrySubtype(int geom_subtype) {
272
            this.geom_subtype = geom_subtype;
273
        }
274

    
275
        @Override
276
        public Object getGeometrySRSId() {
277
            return geom_srsdbcode;
278
        }
279

    
280
        @Override
281
        public void setGeometrySRSId(Object geom_srsid) {
282
            this.geom_srsdbcode = geom_srsid;
283
        }
284

    
285
        @Override
286
        public boolean isGeometry() {
287
            return this.type == DataTypes.GEOMETRY;
288
        }
289

    
290
        private void setStoreParameters(DataStoreParameters parameters) {
291
            this.parameters = parameters;
292
        }
293

    
294
        @Override
295
        public DataStoreParameters getStoreParameters() {
296
            return this.parameters;
297
        }
298
    }
299
//
300
//    public class ColumnBase extends AbstractValue implements Column {
301
//
302
//        protected ColumnDescriptor descriptor;
303
//        protected String name;
304
//
305
//        public ColumnBase(ColumnDescriptor descriptor) {
306
//            this.name = descriptor.getName();
307
//            this.descriptor = descriptor;
308
//        }
309
//
310
//        public ColumnBase(String name) {
311
//            this.name = name;
312
//            this.descriptor = null;
313
//        }
314
//
315
//        @Override
316
//        public ColumnDescriptor getDescriptor() {
317
//            return descriptor;
318
//        }
319
//
320
//        @Override
321
//        public String name() {
322
//            return this.name;
323
//        }
324
//
325
//        @Override
326
//        public String toString() {
327
//            return this.toString(formatter());
328
//        }
329
//
330
//        @Override
331
//        public String toString(Formatter<Value> formatter) {
332
//            if (formatter!=null && formatter.canApply(this)) {
333
//                return formatter.format(this);
334
//            }
335
//            return as_identifier(this.name);
336
//        }
337
//
338
//        @Override
339
//        public int compareTo(ExpressionBuilder.Variable o) {
340
//            return this.name.compareTo(o.name());
341
//        }
342
//
343
//        @Override
344
//        public boolean equals(Object obj) {
345
//            if (!(obj instanceof ExpressionBuilder.Variable)) {
346
//                return false;
347
//            }
348
//            return this.name.equals(((ExpressionBuilder.Variable) obj).name());
349
//        }
350
//
351
//        @Override
352
//        public int hashCode() {
353
//            int hash = 7;
354
//            hash = 37 * hash + Objects.hashCode(this.name);
355
//            return hash;
356
//        }
357
//
358
//    }
359

    
360
    public class TableNameBuilderBase
361
            extends AbstractStatementPart
362
            implements TableNameBuilder {
363

    
364
        public String tableName;
365
        public String schemaName;
366
        private String databaseName;
367

    
368
        public TableNameBuilderBase() {
369
        }
370

    
371
        @Override
372
        public void accept(Visitor visitor, VisitorFilter filter) {
373
            if (filter.accept(this)) {
374
                visitor.visit(this);
375
            }
376
        }
377

    
378
        @Override
379
        public TableNameBuilder database(String name) {
380
            this.databaseName = name;
381
            return this;
382
        }
383

    
384
        @Override
385
        public TableNameBuilder schema(String name) {
386
            if (support_schemas()) {
387
                this.schemaName = name;
388
            }
389
            return this;
390
        }
391

    
392
        @Override
393
        public TableNameBuilder name(String name) {
394
            this.tableName = name;
395
            return this;
396
        }
397

    
398
        @Override
399
        public String getDatabase() {
400
            return this.databaseName;
401
        }
402

    
403
        @Override
404
        public String getSchema() {
405
            return this.schemaName;
406
        }
407

    
408
        @Override
409
        public String getName() {
410
            return this.tableName;
411
        }
412

    
413
        @Override
414
        public boolean has_schema() {
415
            if (!support_schemas()) {
416
                return false;
417
            }
418
            return !StringUtils.isEmpty(this.schemaName);
419
        }
420

    
421
        @Override
422
        public boolean has_database() {
423
            return !StringUtils.isEmpty(this.databaseName);
424
        }
425

    
426
        @Override
427
        public String toString() {
428
            return this.toString(formatter());
429
        }
430

    
431
        @Override
432
        public String toString(Formatter<Value> formatter) {
433
            if (formatter!=null && formatter.canApply(this)) {
434
                return formatter.format(this);
435
            }
436
            if (this.has_database()) {
437
                if (this.has_schema()) {
438
                    return as_identifier(this.databaseName) + "."
439
                            + as_identifier(this.schemaName) + "."
440
                            + as_identifier(this.tableName);
441
                }
442
            } else {
443
                if (this.has_schema()) {
444
                    return as_identifier(this.schemaName) + "."
445
                            + as_identifier(this.tableName);
446
                }
447
            }
448
            return as_identifier(this.tableName);
449
        }
450

    
451
        @Override
452
        public boolean equals(Object obj) {
453
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
454
                return false;
455
            }
456
            TableNameBuilder other = (TableNameBuilder) obj;
457
            if (this.has_database()) {
458
                if (this.has_schema()) {
459
                    return this.databaseName.equals(other.getDatabase()) &&
460
                           this.schemaName.equals(other.getSchema()) &&
461
                           this.tableName.equals(other.getName());
462
                }
463
            } else {
464
                if (this.has_schema()) {
465
                    return this.schemaName.equals(other.getSchema()) &&
466
                           this.tableName.equals(other.getName());
467
                }
468
            }
469
            return this.tableName.equals(other.getName());
470
        }
471
        
472

    
473
    }
474

    
475
    public class CountBuilderBase
476
            extends AbstractStatementPart
477
            implements CountBuilder {
478

    
479
        protected Value value;
480
        protected boolean distinct;
481
        protected boolean all;
482

    
483
        public CountBuilderBase() {
484
            this.value = null;
485
            this.distinct = false;
486
            this.all = false;
487
        }
488

    
489
        @Override
490
        public CountBuilder all() {
491
            this.all = true;
492
            return this;
493
        }
494

    
495
        @Override
496
        public CountBuilder column(Value value) {
497
            this.value = value;
498
            return this;
499
        }
500

    
501
        @Override
502
        public CountBuilder distinct() {
503
            this.distinct = true;
504
            return this;
505
        }
506

    
507
        @Override
508
        public String toString() {
509
            return this.toString(formatter());
510
        }
511

    
512
        @Override
513
        public String toString(Formatter formatter) {
514
            if (formatter!=null && formatter.canApply(this)) {
515
                return formatter.format(this);
516
            }
517
            if (this.all) {
518
                return "COUNT(*)";
519
            }
520
            if (this.distinct) {
521
                return MessageFormat.format(
522
                        "COUNT(DISTINCT {0})",
523
                        value.toString(formatter)
524
                );
525
            }
526
            return MessageFormat.format(
527
                    "COUNT({0})",
528
                    value.toString(formatter)
529
            );
530
        }
531

    
532
    }
533

    
534
    public class FromBuilderBase
535
            extends AbstractStatementPart
536
            implements FromBuilder {
537

    
538
        protected TableNameBuilder tableName = null;
539
        private String subquery = null;
540
        private String passthrough = null;
541

    
542
        @Override
543
        public TableNameBuilder table() {
544
            if (tableName == null) {
545
                this.tableName = createTableNameBuilder();
546
            }
547
            return this.tableName;
548
        }
549

    
550
        @Override
551
        public void accept(Visitor visitor, VisitorFilter filter) {
552
            if (filter.accept(this)) {
553
                visitor.visit(this);
554
            }
555
            if (this.tableName != null) {
556
                this.tableName.accept(visitor, filter);
557
            }
558
        }
559

    
560
        @Override
561
        public FromBuilder custom(String passthrough) {
562
            this.passthrough = passthrough;
563
            return this;
564
        }
565

    
566
        @Override
567
        public FromBuilder subquery(String subquery) {
568
            this.subquery = subquery;
569
            return this;
570
        }
571

    
572
        @Override
573
        public String toString() {
574
            return this.toString(formatter());
575
        }
576

    
577
        @Override
578
        public String toString(Formatter<Value> formatter) {
579
            if (formatter!=null && formatter.canApply(this)) {
580
                return formatter.format(this);
581
            }
582
            if (!StringUtils.isEmpty(passthrough)) {
583
                return passthrough;
584
            }
585
            if (!StringUtils.isEmpty(subquery)) {
586
                return "( " + this.subquery + ") as _subquery_alias_ ";
587
            }
588
            return this.tableName.toString(formatter);
589
        }
590

    
591
    }
592

    
593
    public class SelectColumnBuilderBase
594
            extends AbstractStatementPart
595
            implements SelectColumnBuilder {
596

    
597
        private Variable name = null;
598
        private String alias = null;
599
        private Value value = null;
600
        private boolean asGeometry = false;
601

    
602
        @Override
603
        public void accept(Visitor visitor, VisitorFilter filter) {
604
            if (filter.accept(this)) {
605
                visitor.visit(this);
606
            }
607
            if (this.name != null) {
608
                this.name.accept(visitor, filter);
609
            }
610
            if (this.value != null) {
611
                this.value.accept(visitor, filter);
612
            }
613
        }
614

    
615
        @Override
616
        public SelectColumnBuilder name(String name) {
617
            String quote = quote_for_identifiers();
618
            if (name.startsWith(quote)) {
619
                // Remove quotes
620
                name = name.substring(1, name.length() - 1);
621
            }
622
            this.name = expression().variable(name);
623
            this.value = null;
624
            this.asGeometry = false;
625
            return this;
626
        }
627

    
628
        @Override
629
        public SelectColumnBuilder all() {
630
            this.name = null;
631
            this.value = expression().custom("*");
632
            this.asGeometry = false;
633
            return this;
634
        }
635

    
636
        @Override
637
        public SelectColumnBuilder as_geometry() {
638
            this.asGeometry = true;
639
            return this;
640
        }
641

    
642
        @Override
643
        public SelectColumnBuilder value(Value value) {
644
            this.value = value;
645
            this.name = null;
646
            return this;
647
        }
648

    
649
        @Override
650
        public SelectColumnBuilder as(String alias) {
651
            this.alias = alias;
652
            return this;
653
        }
654

    
655
        @Override
656
        public String getName() {
657
            return this.name.name();
658
        }
659

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

    
665
        @Override
666
        public String getValue() {
667
            return this.alias;
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
            if (this.asGeometry) {
682
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
683
            } else {
684
                if (this.name != null) {
685
                    builder.append(this.name.toString(formatter));
686
                } else {
687
                    builder.append(this.value.toString(formatter));
688
                }
689
            }
690
            if (this.alias != null) {
691
                builder.append(" AS ");
692
                builder.append(as_identifier(this.alias));
693
            }
694
            return builder.toString();
695
        }
696
    }
697

    
698
    public class OrderByBuilderBase
699
            extends AbstractStatementPart
700
            implements OrderByBuilder {
701

    
702
        protected String value;
703
        protected String custom;
704
        protected boolean ascending;
705

    
706
        public OrderByBuilderBase() {
707
            this.ascending = true;
708
        }
709

    
710
        @Override
711
        public void accept(Visitor visitor, VisitorFilter filter) {
712
            if (filter.accept(this)) {
713
                visitor.visit(this);
714
            }
715
        }
716

    
717
        @Override
718
        public OrderByBuilder column(String name) {
719
            this.value = name;
720
            return this;
721
        }
722

    
723
        @Override
724
        public OrderByBuilder custom(String order) {
725
            this.custom = order;
726
            return this;
727
        }
728

    
729
        @Override
730
        public OrderByBuilder ascending() {
731
            this.ascending = true;
732
            return this;
733
        }
734

    
735
        @Override
736
        public OrderByBuilder ascending(boolean asc) {
737
            this.ascending = asc;
738
            return this;
739
        }
740

    
741
        @Override
742
        public OrderByBuilder descending() {
743
            this.ascending = false;
744
            return this;
745
        }
746

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

    
752
        @Override
753
        public String toString(Formatter<Value> formatter) {
754
            if (formatter!=null && formatter.canApply(this)) {
755
                return formatter.format(this);
756
            }
757
            if (!StringUtils.isEmpty(this.custom)) {
758
                return this.custom;
759
            }
760
            if (this.ascending) {
761
                return as_identifier(this.value) + " ASC";
762
            }
763
            return as_identifier(this.value) + " DESC";
764
        }
765
    }
766

    
767
    public class SelectBuilderBase
768
            extends AbstractStatement
769
            implements SelectBuilder {
770

    
771
        protected FromBuilder from;
772
        protected ExpressionBuilder where;
773
        protected long limit = -1;
774
        protected long offset = -1;
775
        protected List<SelectColumnBuilder> columns;
776
        protected List<OrderByBuilder> order_by;
777
        protected boolean distinct;
778
        protected List<Variable> groupColumn;
779

    
780
        public SelectBuilderBase() {
781
            this.columns = new ArrayList<>();
782
            this.distinct = false;
783
        }
784

    
785
        @Override
786
        public SelectBuilder group_by(Variable... columns) {
787
            if( this.groupColumn==null ) {
788
                this.groupColumn = new ArrayList<>();
789
            }
790
            for (Variable column : columns) {
791
                this.groupColumn.add(column);
792
            }
793
            return this;
794
        }
795

    
796
        @Override
797
        public void accept(Visitor visitor, VisitorFilter filter) {
798
            if (filter.accept(this)) {
799
                visitor.visit(this);
800
            }
801
            for (SelectColumnBuilder column : columns) {
802
                column.accept(visitor, filter);
803
            }
804
            if (this.has_from()) {
805
                this.from.accept(visitor, filter);
806
            }
807
            if (this.has_where()) {
808
                this.where.accept(visitor, filter);
809
            }
810
            if (this.has_order_by()) {
811
                for (OrderByBuilder order : order_by) {
812
                    order.accept(visitor, filter);
813
                }
814
            }
815
        }
816

    
817
        @Override
818
        public SelectBuilder distinct() {
819
            this.distinct = true;
820
            return this;
821
        }
822

    
823
        @Override
824
        public SelectColumnBuilder column() {
825
            SelectColumnBuilder builder = createSelectColumnBuilder();
826
            this.columns.add(builder);
827
            return builder;
828
        }
829

    
830
        @Override
831
        public boolean has_column(String name) {
832
            for (SelectColumnBuilder column : columns) {
833
                if (name.equals(column.getName())) {
834
                    return true;
835
                }
836
            }
837
            return false;
838
        }
839

    
840
        @Override
841
        public FromBuilder from() {
842
            if (this.from == null) {
843
                this.from = createFromBuilder();
844
            }
845
            return this.from;
846
        }
847

    
848
        @Override
849
        public boolean has_from() {
850
            return this.from != null;
851
        }
852

    
853
        @Override
854
        public ExpressionBuilder where() {
855
            if (this.where == null) {
856
                this.where = createExpressionBuilder();
857
            }
858
            return this.where;
859
        }
860

    
861
        @Override
862
        public boolean has_where() {
863
            if (this.where == null) {
864
                return false;
865
            }
866
            return this.where.value() != null;
867
        }
868

    
869
        @Override
870
        public SelectBuilder limit(long limit) {
871
            this.limit = limit;
872
            return this;
873
        }
874

    
875
        @Override
876
        public SelectBuilder limit(Long limit) {
877
            if (limit == null) {
878
                this.limit = 0;
879
            } else {
880
                this.limit = limit;
881
            }
882
            return this;
883
        }
884

    
885
        @Override
886
        public boolean has_limit() {
887
            return this.limit > 0;
888
        }
889

    
890
        @Override
891
        public SelectBuilder offset(long offset) {
892
            this.offset = offset;
893
            return this;
894
        }
895

    
896
        @Override
897
        public boolean has_offset() {
898
            return this.offset > 0;
899
        }
900

    
901
        @Override
902
        public OrderByBuilder order_by() {
903
            if (this.order_by == null) {
904
                this.order_by = new ArrayList<>();
905
            }
906
            OrderByBuilder order = createOrderByBuilder();
907
            this.order_by.add(order);
908
            return order;
909
        }
910

    
911
        @Override
912
        public boolean has_order_by() {
913
            if (this.order_by == null) {
914
                return false;
915
            }
916
            return !this.order_by.isEmpty();
917
        }
918
        
919
        @Override
920
        public boolean has_group_by() {
921
            if (this.groupColumn == null) {
922
                return false;
923
            }
924
            return !this.groupColumn.isEmpty();
925
        }
926
        
927
        protected boolean isValid(StringBuilder message) {
928
            if (message == null) {
929
                message = new StringBuilder();
930
            }
931
            if (this.has_offset() && !this.has_order_by()) {
932
                // Algunos gestores de BBDD requieren que se especifique un
933
                // orden para poder usar OFFSET. Como eso parece buena idea para
934
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
935
                // siempre.
936
                message.append("Can't use OFFSET without an ORDER BY.");
937
                return false;
938
            }
939
            return true;
940
        }
941

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

    
947
        @Override
948
        public String toString(Formatter<Value> formatter) {
949
            if (formatter!=null && formatter.canApply(this)) {
950
                return formatter.format(this);
951
            }
952
            StringBuilder builder = new StringBuilder();
953
            if (!this.isValid(builder)) {
954
                throw new IllegalStateException(builder.toString());
955
            }
956
            builder.append("SELECT ");
957
            if (this.distinct) {
958
                builder.append("DISTINCT ");
959
            }
960
            boolean first = true;
961
            for (SelectColumnBuilder column : columns) {
962
                if (first) {
963
                    first = false;
964
                } else {
965
                    builder.append(", ");
966
                }
967
                builder.append(column.toString(formatter));
968
            }
969

    
970
            if (this.has_from()) {
971
                builder.append(" FROM ");
972
                builder.append(this.from.toString(formatter));
973
            }
974
            if( this.has_group_by() ) {
975
                builder.append(" GROUP BY ");
976
                builder.append(this.groupColumn.get(0).name());
977
                for (int i = 1; i < groupColumn.size(); i++) {
978
                    builder.append(", ");
979
                    builder.append(this.groupColumn.get(i).name());
980
                }
981
            }
982
            if (this.has_where()) {
983
                builder.append(" WHERE ");
984
                builder.append(this.where.toString(formatter));
985
            }
986

    
987
            if (this.has_order_by()) {
988
                builder.append(" ORDER BY ");
989
                first = true;
990
                for (OrderByBuilder item : this.order_by) {
991
                    if (first) {
992
                        first = false;
993
                    } else {
994
                        builder.append(", ");
995
                    }
996
                    builder.append(item.toString(formatter));
997
                }
998
            }
999

    
1000
            if (this.has_limit()) {
1001
                builder.append(" LIMIT ");
1002
                builder.append(this.limit);
1003
            }
1004
            if (this.has_offset()) {
1005
                builder.append(" OFFSET ");
1006
                builder.append(this.offset);
1007
            }
1008
            return builder.toString();
1009

    
1010
        }
1011
    }
1012

    
1013
    public class DropTableBuilderBase
1014
            extends AbstractStatement
1015
            implements DropTableBuilder {
1016

    
1017
        protected TableNameBuilder table;
1018

    
1019
        @Override
1020
        public TableNameBuilder table() {
1021
            if (table == null) {
1022
                table = createTableNameBuilder();
1023
            }
1024
            return table;
1025
        }
1026

    
1027
        @Override
1028
        public void accept(Visitor visitor, VisitorFilter filter) {
1029
            if (filter.accept(this)) {
1030
                visitor.visit(this);
1031
            }
1032
            this.table.accept(visitor, filter);
1033
        }
1034

    
1035
        @Override
1036
        public String toString() {
1037
            return this.toString(formatter());
1038
        }
1039

    
1040
        @Override
1041
        public String toString(Formatter<Value> formatter) {
1042
            if (formatter!=null && formatter.canApply(this)) {
1043
                return formatter.format(this);
1044
            }
1045
            StringBuilder builder = new StringBuilder();
1046
            boolean first = true;
1047
            for (String sql : toStrings(formatter)) {
1048
                if (StringUtils.isEmpty(sql)) {
1049
                    continue;
1050
                }
1051
                if (first) {
1052
                    first = false;
1053
                } else {
1054
                    builder.append("; ");
1055
                }
1056
                builder.append(sql);
1057
            }
1058
            return builder.toString();
1059
        }
1060

    
1061
        @Override
1062
        public List<String> toStrings() {
1063
            return this.toStrings(formatter());
1064
        }
1065

    
1066
        @Override
1067
        public List<String> toStrings(Formatter formatter) {
1068
            List<String> sqls = new ArrayList<>();
1069

    
1070
            sqls.add(
1071
                    MessageFormat.format(
1072
                            STMT_DROP_TABLE_table,
1073
                            this.table.toString(formatter)
1074
                    )
1075
            );
1076
            String sql;
1077
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1078
                if (this.table.has_schema()) {
1079
                    sql = MessageFormat.format(
1080
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1081
                            as_string(this.table.getSchema()),
1082
                            as_string(this.table.getName())
1083
                    );
1084
                } else {
1085
                    sql = MessageFormat.format(
1086
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1087
                            as_identifier(this.table.getName())
1088
                    );
1089
                }
1090
                if (!StringUtils.isEmpty(sql)) {
1091
                    sqls.add(sql);
1092
                }
1093
            }
1094
            return sqls;
1095
        }
1096
    }
1097

    
1098
    public class GrantRoleBuilderBase
1099
            extends AbstractStatementPart
1100
            implements GrantRoleBuilder {
1101

    
1102
        protected TableNameBuilder table;
1103
        protected String role;
1104
        protected Set<Privilege> privileges;
1105

    
1106
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1107
            this.table = table;
1108
            this.role = role;
1109
            this.privileges = new HashSet<>();
1110
        }
1111

    
1112
        @Override
1113
        public GrantRoleBuilder privilege(Privilege privilege) {
1114
            privileges.add(privilege);
1115
            return this;
1116
        }
1117

    
1118
        @Override
1119
        public GrantRoleBuilder select() {
1120
            privileges.add(Privilege.SELECT);
1121
            return this;
1122
        }
1123

    
1124
        @Override
1125
        public GrantRoleBuilder update() {
1126
            privileges.add(Privilege.UPDATE);
1127
            return this;
1128
        }
1129

    
1130
        @Override
1131
        public GrantRoleBuilder insert() {
1132
            privileges.add(Privilege.INSERT);
1133
            return this;
1134
        }
1135

    
1136
        @Override
1137
        public GrantRoleBuilder delete() {
1138
            privileges.add(Privilege.DELETE);
1139
            return this;
1140
        }
1141

    
1142
        @Override
1143
        public GrantRoleBuilder truncate() {
1144
            privileges.add(Privilege.TRUNCATE);
1145
            return this;
1146
        }
1147

    
1148
        @Override
1149
        public GrantRoleBuilder reference() {
1150
            privileges.add(Privilege.REFERENCE);
1151
            return this;
1152
        }
1153

    
1154
        @Override
1155
        public GrantRoleBuilder trigger() {
1156
            privileges.add(Privilege.TRIGGER);
1157
            return this;
1158
        }
1159

    
1160
        @Override
1161
        public GrantRoleBuilder all() {
1162
            privileges.add(Privilege.ALL);
1163
            return this;
1164
        }
1165

    
1166
        protected String getPrivilegeName(Privilege privilege) {
1167
            switch (privilege) {
1168
                case DELETE:
1169
                    return "DELETE";
1170
                case INSERT:
1171
                    return "INSERT";
1172
                case REFERENCE:
1173
                    return "REFERENCE";
1174
                case SELECT:
1175
                    return "SELECT";
1176
                case TRIGGER:
1177
                    return "TRIGGER";
1178
                case TRUNCATE:
1179
                    return "TRUNCATE";
1180
                case UPDATE:
1181
                    return "UPDATE";
1182
                case ALL:
1183
                default:
1184
                    return "ALL";
1185
            }
1186
        }
1187

    
1188
        @Override
1189
        public String toString() {
1190
            return this.toString(formatter());
1191
        }
1192

    
1193
        @Override
1194
        public String toString(Formatter<Value> formatter) {
1195
            if (formatter!=null && formatter.canApply(this)) {
1196
                return formatter.format(this);
1197
            }
1198
            StringBuilder builder = new StringBuilder();
1199
            boolean first = true;
1200
            for (Privilege privilege : privileges) {
1201
                if (first) {
1202
                    first = false;
1203
                } else {
1204
                    builder.append(", ");
1205
                }
1206
                builder.append(this.getPrivilegeName(privilege));
1207
            }
1208
            String sql = MessageFormat.format(
1209
                    STMT_GRANT_privileges_ON_table_TO_role,
1210
                    builder.toString(),
1211
                    table.toString(formatter),
1212
                    role
1213
            );
1214
            return sql;
1215
        }
1216
    }
1217

    
1218
    public class GrantBuilderBase
1219
            extends AbstractStatement
1220
            implements GrantBuilder {
1221

    
1222
        protected TableNameBuilder table;
1223
        protected Map<String, GrantRoleBuilder> roles;
1224

    
1225
        public GrantBuilderBase() {
1226
            this.roles = new HashMap<>();
1227
        }
1228

    
1229
        @Override
1230
        public TableNameBuilder table() {
1231
            if (table == null) {
1232
                table = createTableNameBuilder();
1233
            }
1234
            return table;
1235
        }
1236

    
1237
        @Override
1238
        public void accept(Visitor visitor, VisitorFilter filter) {
1239
            if (filter.accept(this)) {
1240
                visitor.visit(this);
1241
            }
1242
            if (this.table != null) {
1243
                this.table.accept(visitor, filter);
1244
            }
1245
        }
1246

    
1247
        @Override
1248
        public GrantRoleBuilder role(String role) {
1249
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1250
            if (roleBuilder == null) {
1251
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1252
                this.roles.put(role, roleBuilder);
1253
            }
1254
            return roleBuilder;
1255
        }
1256

    
1257
        @Override
1258
        public String toString() {
1259
            return this.toString(formatter());
1260
        }
1261

    
1262
        @Override
1263
        public String toString(Formatter<Value> formatter) {
1264
            if (formatter!=null && formatter.canApply(this)) {
1265
                return formatter.format(this);
1266
            }
1267
            StringBuilder builder = new StringBuilder();
1268
            boolean first = true;
1269
            for (String sql : toStrings(formatter)) {
1270
                if (StringUtils.isEmpty(sql)) {
1271
                    continue;
1272
                }
1273
                if (first) {
1274
                    first = false;
1275
                } else {
1276
                    builder.append("; ");
1277
                }
1278
                builder.append(sql);
1279
            }
1280
            return builder.toString();
1281
        }
1282

    
1283
        @Override
1284
        public List<String> toStrings() {
1285
            return this.toStrings(formatter());
1286
        }
1287

    
1288
        @Override
1289
        public List<String> toStrings(Formatter formatter) {
1290
            List<String> sqls = new ArrayList<>();
1291
            for (GrantRoleBuilder role : roles.values()) {
1292
                sqls.add(role.toString(formatter));
1293
            }
1294
            return sqls;
1295
        }
1296
    }
1297

    
1298
    public class UpdateColumnBuilderBase
1299
            extends InsertColumnBuilderBase
1300
            implements UpdateColumnBuilder {
1301

    
1302
        public UpdateColumnBuilderBase() {
1303
            super();
1304
        }
1305

    
1306
        @Override
1307
        public UpdateColumnBuilder name(String name) {
1308
            return (UpdateColumnBuilder) super.name(name);
1309
        }
1310

    
1311
        @Override
1312
        public UpdateColumnBuilder with_value(Value value) {
1313
            return (UpdateColumnBuilder) super.with_value(value);
1314
        }
1315

    
1316
    }
1317

    
1318
    public class UpdateBuilderBase
1319
            extends AbstractStatement
1320
            implements UpdateBuilder {
1321

    
1322
        protected ExpressionBuilder where;
1323
        protected List<UpdateColumnBuilder> columns;
1324
        protected TableNameBuilder table;
1325

    
1326
        public UpdateBuilderBase() {
1327
            this.columns = new ArrayList<>();
1328
        }
1329

    
1330
        @Override
1331
        public void accept(Visitor visitor, VisitorFilter filter) {
1332
            if (filter.accept(this)) {
1333
                visitor.visit(this);
1334
            }
1335
            if (this.table != null) {
1336
                this.table.accept(visitor, filter);
1337
            }
1338
            for (UpdateColumnBuilder column : columns) {
1339
                column.accept(visitor, filter);
1340
            }
1341
            if (this.has_where()) {
1342
                this.where.accept(visitor, filter);
1343
            }
1344
        }
1345

    
1346
        @Override
1347
        public ExpressionBuilder where() {
1348
            if (this.where == null) {
1349
                this.where = createExpressionBuilder();
1350
            }
1351
            return this.where;
1352
        }
1353

    
1354
        @Override
1355
        public TableNameBuilder table() {
1356
            if (table == null) {
1357
                table = createTableNameBuilder();
1358
            }
1359
            return table;
1360
        }
1361

    
1362
        @Override
1363
        public UpdateColumnBuilder column() {
1364
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1365
            this.columns.add(column);
1366
            return column;
1367
        }
1368

    
1369
        @Override
1370
        public boolean has_where() {
1371
            return this.where != null;
1372
        }
1373

    
1374
        @Override
1375
        public String toString() {
1376
            return this.toString(formatter());
1377
        }
1378

    
1379
        @Override
1380
        public String toString(Formatter<Value> formatter) {
1381
            if (formatter!=null && formatter.canApply(this)) {
1382
                return formatter.format(this);
1383
            }
1384
            /*
1385
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1386
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1387
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1388
             * output_expression [ AS output_name ] [, ...] ]
1389
             */
1390
            StringBuilder columnsAndValues = new StringBuilder();
1391

    
1392
            boolean first = true;
1393
            for (UpdateColumnBuilder column : columns) {
1394
                if (first) {
1395
                    first = false;
1396
                } else {
1397
                    columnsAndValues.append(", ");
1398
                }
1399
                columnsAndValues.append(as_identifier(column.getName()));
1400
                columnsAndValues.append(" = ");
1401
                columnsAndValues.append(column.getValue().toString(formatter));
1402
            }
1403

    
1404
            String sql;
1405
            if (this.has_where()) {
1406
                sql = MessageFormat.format(
1407
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1408
                        this.table.toString(formatter),
1409
                        columnsAndValues.toString(),
1410
                        this.where.toString(formatter)
1411
                );
1412
            } else {
1413
                sql = MessageFormat.format(
1414
                        STMT_UPDATE_table_SET_columnsAndValues,
1415
                        this.table.toString(formatter),
1416
                        columnsAndValues.toString()
1417
                );
1418
            }
1419
            return sql;
1420
        }
1421
    }
1422

    
1423
    public class DeleteBuilderBase
1424
            extends AbstractStatement
1425
            implements DeleteBuilder {
1426

    
1427
        protected ExpressionBuilder where;
1428
        protected TableNameBuilder table;
1429

    
1430
        public DeleteBuilderBase() {
1431
        }
1432

    
1433
        @Override
1434
        public void accept(Visitor visitor, VisitorFilter filter) {
1435
            if (filter.accept(this)) {
1436
                visitor.visit(this);
1437
            }
1438
            if (this.table != null) {
1439
                this.table.accept(visitor, filter);
1440
            }
1441
            if (this.has_where()) {
1442
                this.where.accept(visitor, filter);
1443
            }
1444
        }
1445

    
1446
        @Override
1447
        public ExpressionBuilder where() {
1448
            if (this.where == null) {
1449
                this.where = createExpressionBuilder();
1450
            }
1451
            return this.where;
1452
        }
1453

    
1454
        @Override
1455
        public TableNameBuilder table() {
1456
            if (table == null) {
1457
                table = createTableNameBuilder();
1458
            }
1459
            return table;
1460
        }
1461

    
1462
        @Override
1463
        public boolean has_where() {
1464
            return this.where != null;
1465
        }
1466

    
1467
        @Override
1468
        public String toString() {
1469
            return this.toString(formatter());
1470
        }
1471

    
1472
        @Override
1473
        public String toString(Formatter<Value> formatter) {
1474
            if (formatter!=null && formatter.canApply(this)) {
1475
                return formatter.format(this);
1476
            }
1477
            /*
1478
             * DELETE FROM table_name
1479
             * WHERE some_column=some_value; 
1480
             */
1481
            String sql;
1482
            if (this.has_where()) {
1483
                sql = MessageFormat.format(
1484
                        STMT_DELETE_FROM_table_WHERE_expresion,
1485
                        this.table.toString(formatter),
1486
                        this.where.toString(formatter)
1487
                );
1488
            } else {
1489
                sql = MessageFormat.format(
1490
                        STMT_DELETE_FROM_table,
1491
                        this.table.toString(formatter)
1492
                );
1493
            }
1494
            return sql;
1495
        }
1496
    }
1497

    
1498
    public class CreateIndexBuilderBase
1499
            extends AbstractStatement
1500
            implements CreateIndexBuilder {
1501

    
1502
        protected boolean ifNotExist = false;
1503
        protected boolean isUnique = false;
1504
        protected String indexName;
1505
        protected boolean isSpatial = false;
1506
        protected TableNameBuilder table;
1507
        protected final List<String> columns;
1508

    
1509
        public CreateIndexBuilderBase() {
1510
            this.columns = new ArrayList<>();
1511
        }
1512

    
1513
        @Override
1514
        public CreateIndexBuilder unique() {
1515
            this.isUnique = true;
1516
            return this;
1517
        }
1518

    
1519
        @Override
1520
        public CreateIndexBuilder if_not_exist() {
1521
            this.ifNotExist = true;
1522
            return this;
1523
        }
1524

    
1525
        @Override
1526
        public CreateIndexBuilder name(String name) {
1527
            this.indexName = name;
1528
            return this;
1529
        }
1530

    
1531
        @Override
1532
        public CreateIndexBuilder spatial() {
1533
            this.isSpatial = true;
1534
            return this;
1535
        }
1536

    
1537
        @Override
1538
        public CreateIndexBuilder column(String name) {
1539
            this.columns.add(name);
1540
            return this;
1541
        }
1542

    
1543
        @Override
1544
        public TableNameBuilder table() {
1545
            if (table == null) {
1546
                table = createTableNameBuilder();
1547
            }
1548
            return table;
1549
        }
1550

    
1551
        @Override
1552
        public void accept(Visitor visitor, VisitorFilter filter) {
1553
            if (filter.accept(this)) {
1554
                visitor.visit(this);
1555
            }
1556
            if (this.table != null) {
1557
                this.table.accept(visitor, filter);
1558
            }
1559
        }
1560

    
1561
        @Override
1562
        public String toString() {
1563
            return this.toString(formatter());
1564
        }
1565

    
1566
        @Override
1567
        public String toString(Formatter<Value> formatter) {
1568
            if (formatter!=null && formatter.canApply(this)) {
1569
                return formatter.format(this);
1570
            }
1571
            StringBuilder builder = new StringBuilder();
1572
            boolean first = true;
1573
            for (String sql : toStrings(formatter)) {
1574
                if (StringUtils.isEmpty(sql)) {
1575
                    continue;
1576
                }
1577
                if (first) {
1578
                    first = false;
1579
                } else {
1580
                    builder.append("; ");
1581
                }
1582
                builder.append(sql);
1583
            }
1584
            return builder.toString();
1585
        }
1586

    
1587
        @Override
1588
        public List<String> toStrings() {
1589
            return this.toStrings(formatter());
1590
        }
1591

    
1592
        @Override
1593
        public List<String> toStrings(Formatter formatter) {
1594
            StringBuilder builder = new StringBuilder();
1595
            builder.append("CREATE ");
1596
            if (this.isUnique) {
1597
                builder.append("UNIQUE ");
1598
            }
1599
            builder.append("INDEX ");
1600
            if (this.ifNotExist) {
1601
                builder.append("IF NOT EXISTS ");
1602
            }
1603
            builder.append(as_identifier(this.indexName));
1604
            builder.append(" ON ");
1605
            builder.append(this.table.toString(formatter));
1606
            if (this.isSpatial) {
1607
                builder.append(" USING GIST ");
1608
            }
1609
            builder.append(" ( ");
1610
            boolean is_first_column = true;
1611
            for (String column : this.columns) {
1612
                if (is_first_column) {
1613
                    is_first_column = false;
1614
                } else {
1615
                    builder.append(", ");
1616
                }
1617
                builder.append(column);
1618
            }
1619
            builder.append(" )");
1620

    
1621
            List<String> sqls = new ArrayList<>();
1622
            sqls.add(builder.toString());
1623
            return sqls;
1624
        }
1625

    
1626
    }
1627

    
1628
    public class AlterTableBuilderBase
1629
            extends AbstractStatement
1630
            implements AlterTableBuilder {
1631

    
1632
        protected TableNameBuilder table;
1633
        protected List<String> drops;
1634
        protected List<ColumnDescriptor> adds;
1635
        protected List<ColumnDescriptor> alters;
1636
        protected List<Pair<String, String>> renames;
1637

    
1638
        public AlterTableBuilderBase() {
1639
            this.drops = new ArrayList<>();
1640
            this.adds = new ArrayList<>();
1641
            this.alters = new ArrayList<>();
1642
            this.renames = new ArrayList<>();
1643
        }
1644

    
1645
        @Override
1646
        public boolean isEmpty() {
1647
            return this.drops.isEmpty()
1648
                    && this.adds.isEmpty()
1649
                    && this.alters.isEmpty()
1650
                    && this.renames.isEmpty();
1651
        }
1652

    
1653
        @Override
1654
        public void accept(Visitor visitor, VisitorFilter filter) {
1655
            if (filter.accept(this)) {
1656
                visitor.visit(this);
1657
            }
1658
            if (this.table != null) {
1659
                this.table.accept(visitor, filter);
1660
            }
1661
        }
1662

    
1663
        @Override
1664
        public TableNameBuilder table() {
1665
            if (table == null) {
1666
                table = createTableNameBuilder();
1667
            }
1668
            return table;
1669
        }
1670

    
1671
        @Override
1672
        public AlterTableBuilder drop_column(String columnName) {
1673
            this.drops.add(columnName);
1674
            return this;
1675
        }
1676

    
1677
        @Override
1678
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
1679
            this.adds.add(new ColumnDescriptorBase(fad));
1680
            return this;
1681
        }
1682

    
1683
        @Override
1684
        public AlterTableBuilder add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1685
            if (isPk || isAutomatic) {
1686
                allowNulls = false;
1687
            }
1688
            this.adds.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1689
            return this;
1690
        }
1691

    
1692
        @Override
1693
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1694
            if (StringUtils.isEmpty(columnName)) {
1695
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1696
            }
1697
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1698
            return this;
1699
        }
1700

    
1701
        @Override
1702
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1703
            if (StringUtils.isEmpty(columnName)) {
1704
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1705
            }
1706
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1707
            return this;
1708
        }
1709

    
1710
        @Override
1711
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
1712
            this.alters.add(new ColumnDescriptorBase(fad));
1713
            return this;
1714
        }
1715

    
1716
        @Override
1717
        public AlterTableBuilder alter_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1718
            if (isPk || isAutomatic) {
1719
                allowNulls = false;
1720
            }
1721
            this.alters.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1722
            return this;
1723
        }
1724

    
1725
        @Override
1726
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1727
            if (StringUtils.isEmpty(columnName)) {
1728
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1729
            }
1730
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1731
            return this;
1732
        }
1733

    
1734
        @Override
1735
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1736
            if (StringUtils.isEmpty(columnName)) {
1737
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1738
            }
1739
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1740
            return this;
1741
        }
1742

    
1743
        @Override
1744
        public AlterTableBuilder rename_column(String source, String target) {
1745
            this.renames.add(new ImmutablePair(source, target));
1746
            return this;
1747
        }
1748

    
1749
        @Override
1750
        public String toString() {
1751
            return this.toString(formatter());
1752
        }
1753

    
1754
        @Override
1755
        public String toString(Formatter<Value> formatter) {
1756
            if (formatter!=null && formatter.canApply(this)) {
1757
                return formatter.format(this);
1758
            }
1759
            StringBuilder builder = new StringBuilder();
1760
            boolean first = true;
1761
            for (String sql : toStrings(formatter)) {
1762
                if (StringUtils.isEmpty(sql)) {
1763
                    continue;
1764
                }
1765
                if (first) {
1766
                    first = false;
1767
                } else {
1768
                    builder.append("; ");
1769
                }
1770
                builder.append(sql);
1771
            }
1772
            return builder.toString();
1773
        }
1774

    
1775
        @Override
1776
        public List<String> toStrings() {
1777
            return this.toStrings(formatter());
1778
        }
1779

    
1780
        @Override
1781
        public List<String> toStrings(Formatter formatter) {
1782
            List<String> sqls = new ArrayList<>();
1783
            if (this.isEmpty()) {
1784
                return sqls;
1785
            }
1786
            for (String column : drops) {
1787
                StringBuilder builder = new StringBuilder();
1788
                builder.append("ALTER TABLE ");
1789
                builder.append(this.table.toString(formatter));
1790
                builder.append(" DROP COLUMN IF EXISTS ");
1791
                builder.append(as_identifier(column));
1792
                sqls.add(builder.toString());
1793
            }
1794
            for (ColumnDescriptor column : adds) {
1795
                StringBuilder builder = new StringBuilder();
1796
                builder.append("ALTER TABLE ");
1797
                builder.append(this.table.toString(formatter));
1798
                builder.append(" ADD COLUMN ");
1799
                builder.append(as_identifier(column.getName()));
1800
                builder.append(" ");
1801
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1802
                    builder.append(" SERIAL");
1803
                } else {
1804
                    builder.append(
1805
                            sqltype(
1806
                                    column.getType(),
1807
                                    column.getPrecision(),
1808
                                    column.getSize(),
1809
                                    column.getGeometryType(),
1810
                                    column.getGeometrySubtype()
1811
                            )
1812
                    );
1813
                }
1814
                if (column.getDefaultValue() == null) {
1815
                    if (column.allowNulls()) {
1816
                        builder.append(" DEFAULT NULL");
1817
                    }
1818
                } else {
1819
                    builder.append(" DEFAULT '");
1820
                    builder.append(Objects.toString(column.getDefaultValue(),""));
1821
                    builder.append("'");
1822
                }
1823
                if (column.allowNulls()) {
1824
                    builder.append(" NULL");
1825
                } else {
1826
                    builder.append(" NOT NULL");
1827
                }
1828
                if (column.isPrimaryKey()) {
1829
                    builder.append(" PRIMARY KEY");
1830
                }
1831
                sqls.add(builder.toString());
1832
            }
1833
            for (ColumnDescriptor column : alters) {
1834
                StringBuilder builder = new StringBuilder();
1835
                builder.append("ALTER TABLE ");
1836
                builder.append(this.table.toString(formatter));
1837
                builder.append(" ALTER COLUMN ");
1838
                builder.append(as_identifier(column.getName()));
1839
                builder.append(" SET DATA TYPE ");
1840
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
1841
                    builder.append(" SERIAL");
1842
                } else {
1843
                    builder.append(
1844
                            sqltype(
1845
                                    column.getType(),
1846
                                    column.getPrecision(),
1847
                                    column.getSize(),
1848
                                    column.getGeometryType(),
1849
                                    column.getGeometrySubtype()
1850
                            )
1851
                    );
1852
                }
1853
                if (column.getDefaultValue() == null) {
1854
                    if (column.allowNulls()) {
1855
                        builder.append(" DEFAULT NULL");
1856
                    } else {
1857
                        builder.append(" DROP DEFAULT");
1858
                    }
1859
                } else {
1860
                    builder.append(" DEFAULT '");
1861
                    builder.append(column.getDefaultValue().toString());
1862
                    builder.append("'");
1863
                }
1864
                sqls.add(builder.toString());
1865
            }
1866
            for (Pair<String, String> pair : renames) {
1867
                StringBuilder builder = new StringBuilder();
1868
                builder.append("ALTER TABLE ");
1869
                builder.append(this.table.toString(formatter));
1870
                builder.append(" RENAME COLUMN ");
1871
                builder.append(as_identifier(pair.getLeft()));
1872
                builder.append(" TO ");
1873
                builder.append(as_identifier(pair.getRight()));
1874
                sqls.add(builder.toString());
1875
            }
1876
            return sqls;
1877
        }
1878

    
1879
    }
1880

    
1881
    public class CreateTableBuilderBase
1882
            extends AbstractStatement
1883
            implements CreateTableBuilder {
1884

    
1885
        protected TableNameBuilder table;
1886
        protected List<ColumnDescriptor> columns;
1887

    
1888
        public CreateTableBuilderBase() {
1889
            this.columns = new ArrayList<>();
1890
        }
1891

    
1892
        @Override
1893
        public void accept(Visitor visitor, VisitorFilter filter) {
1894
            if (filter.accept(this)) {
1895
                visitor.visit(this);
1896
            }
1897
            if (this.table != null) {
1898
                this.table.accept(visitor, filter);
1899
            }
1900
        }
1901

    
1902
        @Override
1903
        public TableNameBuilder table() {
1904
            if (table == null) {
1905
                table = createTableNameBuilder();
1906
            }
1907
            return table;
1908
        }
1909

    
1910
        @Override
1911
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
1912
            this.columns.add(new ColumnDescriptorBase(fad));
1913
            return this;
1914
        }
1915

    
1916
        @Override
1917
        public CreateTableBuilderBase add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1918
            if (StringUtils.isEmpty(columnName)) {
1919
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1920
            }
1921
            if (isPk || isAutomatic) {
1922
                allowNulls = false;
1923
            }
1924
            this.columns.add(new ColumnDescriptorBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1925
            return this;
1926
        }
1927

    
1928
        @Override
1929
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1930
            if (StringUtils.isEmpty(columnName)) {
1931
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1932
            }
1933
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1934
            return this;
1935
        }
1936

    
1937
        @Override
1938
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1939
            if (StringUtils.isEmpty(columnName)) {
1940
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1941
            }
1942
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1943
            return this;
1944
        }
1945

    
1946
        @Override
1947
        public ColumnDescriptor getColumnDescriptor(String columnName) {
1948
            if (StringUtils.isEmpty(columnName)) {
1949
                return null;
1950
            }
1951
            for (ColumnDescriptor column : columns) {
1952
                if (columnName.equals(column.getName())) {
1953
                    return column;
1954
                }
1955
            }
1956
            return null;
1957
        }
1958

    
1959
        @Override
1960
        public String toString() {
1961
            return this.toString(formatter());
1962
        }
1963

    
1964
        @Override
1965
        public String toString(Formatter<Value> formatter) {
1966
            if (formatter!=null && formatter.canApply(this)) {
1967
                return formatter.format(this);
1968
            }
1969
            StringBuilder builder = new StringBuilder();
1970
            boolean first = true;
1971
            for (String sql : toStrings(formatter)) {
1972
                if (StringUtils.isEmpty(sql)) {
1973
                    continue;
1974
                }
1975
                if (first) {
1976
                    first = false;
1977
                } else {
1978
                    builder.append("; ");
1979
                }
1980
                builder.append(sql);
1981
            }
1982
            return builder.toString();
1983
        }
1984

    
1985
        @Override
1986
        public List<String> toStrings() {
1987
            return this.toStrings(formatter());
1988
        }
1989

    
1990
        @Override
1991
        public List<String> toStrings(Formatter formatter) {
1992
            List<String> sqls = new ArrayList<>();
1993
            /**
1994
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
1995
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
1996
             * column_constraint [ ... ] ] | table_constraint | LIKE
1997
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
1998
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
1999
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2000
             *
2001
             * where column_constraint is:
2002
             *
2003
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2004
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2005
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2006
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2007
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2008
             *
2009
             * and table_constraint is:
2010
             *
2011
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2012
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2013
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2014
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2015
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2016
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2017
             */
2018
            StringBuilder builder = new StringBuilder();
2019

    
2020
            builder.append("CREATE TABLE ");
2021
            builder.append(this.table.toString(formatter));
2022
            builder.append(" (");
2023
            boolean first = true;
2024
            for (ColumnDescriptor column : columns) {
2025
                if (first) {
2026
                    first = false;
2027
                } else {
2028
                    builder.append(", ");
2029
                }
2030
                builder.append(as_identifier(column.getName()));
2031
                builder.append(" ");
2032
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2033
                    builder.append("SERIAL");
2034
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2035
                    builder.append("BIGSERIAL");
2036
                } else {
2037
                    builder.append(sqltype(
2038
                            column.getType(),
2039
                            column.getPrecision(),
2040
                            column.getSize(),
2041
                            column.getGeometryType(),
2042
                            column.getGeometrySubtype()
2043
                    )
2044
                    );
2045
                }
2046
                if (column.getDefaultValue() == null) {
2047
                    if (column.allowNulls()) {
2048
                        builder.append(" DEFAULT NULL");
2049
                    }
2050
                } else {
2051
                    builder.append(" DEFAULT '");
2052
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2053
                    builder.append("'");
2054
                }
2055
                if (column.allowNulls()) {
2056
                    builder.append(" NULL");
2057
                } else {
2058
                    builder.append(" NOT NULL");
2059
                }
2060
                if (column.isPrimaryKey()) {
2061
                    builder.append(" PRIMARY KEY");
2062
                }
2063
            }
2064
            builder.append(" )");
2065
            sqls.add(builder.toString());
2066
            return sqls;
2067
        }
2068
    }
2069

    
2070
    public class InsertColumnBuilderBase
2071
            extends AbstractStatement
2072
            implements InsertColumnBuilder {
2073

    
2074
        protected Variable name;
2075
        protected Value value;
2076

    
2077
        public InsertColumnBuilderBase() {
2078
        }
2079

    
2080
        @Override
2081
        public void accept(Visitor visitor, VisitorFilter filter) {
2082
            if (filter.accept(this)) {
2083
                visitor.visit(this);
2084
            }
2085
            if (this.name != null) {
2086
                this.name.accept(visitor, filter);
2087
            }
2088
            if (this.value != null) {
2089
                this.value.accept(visitor, filter);
2090
            }
2091
        }
2092

    
2093
        @Override
2094
        public InsertColumnBuilder name(String name) {
2095
            this.name = expression().variable(name);
2096
            return this;
2097
        }
2098

    
2099
        @Override
2100
        public InsertColumnBuilder with_value(Value value) {
2101
            this.value = value;
2102
            return this;
2103
        }
2104

    
2105
        @Override
2106
        public String getName() {
2107
            return this.name.name();
2108
        }
2109

    
2110
        @Override
2111
        public Value getValue() {
2112
            return this.value;
2113
        }
2114

    
2115
        @Override
2116
        public String toString() {
2117
            return this.toString(formatter());
2118
        }
2119

    
2120
        @Override
2121
        public String toString(Formatter<Value> formatter) {
2122
            if (formatter!=null && formatter.canApply(this)) {
2123
                return formatter.format(this);
2124
            }
2125
            return this.value.toString(formatter);
2126
        }
2127
    }
2128

    
2129
    public class InsertBuilderBase
2130
            extends AbstractStatement
2131
            implements InsertBuilder {
2132

    
2133
        protected List<InsertColumnBuilder> columns;
2134
        protected TableNameBuilder table;
2135

    
2136
        public InsertBuilderBase() {
2137
            this.columns = new ArrayList<>();
2138
        }
2139

    
2140
        @Override
2141
        public void accept(Visitor visitor, VisitorFilter filter) {
2142
            if (filter.accept(this)) {
2143
                visitor.visit(this);
2144
            }
2145
            if (this.table != null) {
2146
                this.table.accept(visitor, filter);
2147
            }
2148
            for (InsertColumnBuilder column : columns) {
2149
                column.accept(visitor, filter);
2150
            }
2151
        }
2152

    
2153
        @Override
2154
        public TableNameBuilder table() {
2155
            if (table == null) {
2156
                table = createTableNameBuilder();
2157
            }
2158
            return table;
2159
        }
2160

    
2161
        @Override
2162
        public InsertColumnBuilder column() {
2163
            InsertColumnBuilder column = createInsertColumnBuilder();
2164
            this.columns.add(column);
2165
            return column;
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
            /*
2179
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2180
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2181
             * output_expression [ AS output_name ] [, ...] ]
2182
             */
2183
            StringBuilder builderColumns = new StringBuilder();
2184
            StringBuilder builderValues = new StringBuilder();
2185

    
2186
            boolean first = true;
2187
            for (InsertColumnBuilder column : columns) {
2188
                if (first) {
2189
                    first = false;
2190
                } else {
2191
                    builderColumns.append(", ");
2192
                }
2193
                builderColumns.append(as_identifier(column.getName()));
2194
            }
2195
            first = true;
2196
            for (InsertColumnBuilder column : columns) {
2197
                if (first) {
2198
                    first = false;
2199
                } else {
2200
                    builderValues.append(", ");
2201
                }
2202
                builderValues.append(column.toString(formatter));
2203
            }
2204

    
2205
            String sql = MessageFormat.format(
2206
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2207
                    this.table.toString(formatter),
2208
                    builderColumns.toString(),
2209
                    builderValues.toString()
2210
            );
2211
            return sql;
2212

    
2213
        }
2214
    }
2215

    
2216
    public class UpdateTableStatisticsBuilderBase
2217
            extends AbstractStatement
2218
            implements UpdateTableStatisticsBuilder {
2219

    
2220
        protected TableNameBuilder table;
2221

    
2222
        @Override
2223
        public void accept(Visitor visitor, VisitorFilter filter) {
2224
            if (filter.accept(this)) {
2225
                visitor.visit(this);
2226
            }
2227
            if (this.table != null) {
2228
                this.table.accept(visitor, filter);
2229
            }
2230
        }
2231

    
2232
        @Override
2233
        public TableNameBuilder table() {
2234
            if (table == null) {
2235
                table = createTableNameBuilder();
2236
            }
2237
            return table;
2238
        }
2239

    
2240
        @Override
2241
        public String toString() {
2242
            return this.toString(formatter());
2243
        }
2244

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

    
2266
        @Override
2267
        public List<String> toStrings() {
2268
            return this.toStrings(formatter());
2269
        }
2270

    
2271
        @Override
2272
        public List<String> toStrings(Formatter formatter) {
2273
            List<String> sqls = new ArrayList<>();
2274

    
2275
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2276
                String sql = MessageFormat.format(
2277
                        STMT_UPDATE_TABLE_STATISTICS_table,
2278
                        table.toString(formatter)
2279
                );
2280
                if (!StringUtils.isEmpty(sql)) {
2281
                    sqls.add(sql);
2282
                }
2283
            }
2284
            return sqls;
2285
        }
2286
    }
2287

    
2288
    protected ExpressionBuilder expressionBuilder;
2289

    
2290
    protected String defaultSchema;
2291
    protected boolean supportSchemas;
2292
    protected boolean hasSpatialFunctions;
2293
    protected GeometrySupportType geometrySupportType;
2294
    protected boolean allowAutomaticValues;
2295

    
2296
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2297

    
2298
    protected String constant_true = "(1=1)";
2299
    protected String constant_false = "(1<>1)";
2300

    
2301
    protected String type_boolean = "BOOLEAN";
2302
    protected String type_byte = "TINYINT";
2303
    protected String type_bytearray = "BYTEA";
2304
    protected String type_geometry = "TEXT";
2305
    protected String type_char = "CHARACTER(1)";
2306
    protected String type_date = "DATE";
2307
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2308
    protected String type_numeric_p = "NUMERIC({0,Number,#######})";
2309
    protected String type_numeric_ps = "NUMERIC({0,Number,#######},{1,Number,#######})";
2310
    protected String type_bigdecimal = "NUMERIC({0,Number,#######},{1,Number,#######})";
2311
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2312
    protected String type_int = "INT";
2313
    protected String type_long = "BIGINT";
2314
    protected String type_string = "TEXT";
2315
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2316
    protected String type_time = "TIME";
2317
    protected String type_timestamp = "TIMESTAMP";
2318
    protected String type_version = "VARCHAR(30)";
2319
    protected String type_URI = "TEXT";
2320
    protected String type_URL = "TEXT";
2321
    protected String type_FILE = "TEXT";
2322
    protected String type_FOLDER = "TEXT";
2323

    
2324
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2325
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2326
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2327
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2328
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2329
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2330
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2331
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2332
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2333
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2334

    
2335
    public SQLBuilderBase() {
2336
        this.expressionBuilder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2337

    
2338
        this.hasSpatialFunctions = false;
2339
        this.supportSchemas = true;
2340
        this.geometrySupportType = GeometrySupportType.WKT;
2341

    
2342
        this.defaultSchema = "public";
2343
        this.allowAutomaticValues = true;
2344

    
2345
    }
2346
    
2347
    @Override
2348
    public void setProperties(Class filter, final Object... values) {
2349
        this.accept(new Visitor() {
2350
            @Override
2351
            public void visit(Visitable v) {
2352
                for (int i = 0; i < values.length; i+=2) {
2353
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2354
                }
2355
            }
2356
        }, new ClassVisitorFilter(filter) );
2357
    }
2358

    
2359
    public String quote_for_identifiers() {
2360
        return "\"";
2361
    }
2362

    
2363
    public String quote_for_strings() {
2364
        return "'";
2365
    }
2366

    
2367
    @Override
2368
    public String as_identifier(String id) {
2369
        String quote = this.quote_for_identifiers();
2370
//        No se porque no esta disponible wrapIfMissing
2371
//        return StringUtils.wrapIfMissing(id,quote);
2372
        if (id.startsWith(quote)) {
2373
            return id;
2374
        }
2375
        return quote + id + quote;
2376

    
2377
    }
2378

    
2379
    @Override
2380
    public String as_string(String s) {
2381
        String quote = this.quote_for_strings();
2382
//        No se porque no esta disponible wrapIfMissing
2383
//        return StringUtils.wrapIfMissing(id,quote);
2384
        if (s.startsWith(quote)) {
2385
            return s;
2386
        }
2387
        return quote + s + quote;
2388

    
2389
    }
2390

    
2391
    @Override
2392
    public String as_string(byte[] data) {
2393
        return this.expressionBuilder.bytearray_0x(data);
2394
//        return this.expressionBuilder.bytearray_hex(data);
2395
//        return this.expressionBuilder.bytearray_x(data);
2396
    }
2397
    
2398
    @Override
2399
    public String as_string(boolean value) {
2400
        return value? "TRUE" : "FALSE";
2401
    }
2402

    
2403
    @Override
2404
    public String as_string(Number value) {
2405
        return Objects.toString(value);
2406
    }
2407
    
2408
    @Override
2409
    public String as_string(Object value) {
2410
        if( value == null ) {
2411
            return "NULL";
2412
        }
2413
        if( value instanceof CharSequence ) {
2414
            return as_string(value.toString());
2415
        }
2416
        if( value instanceof Number ) {
2417
            return as_string((Number)value);
2418
        }
2419
        if( value instanceof Boolean ) {
2420
            return as_string((boolean)value);
2421
        }
2422
        if( value instanceof byte[] ) {
2423
            return as_string((byte[])value);
2424
        }
2425
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2426
    }
2427
    
2428
    @Override
2429
    public ExpressionBuilder expression() {
2430
        return this.expressionBuilder;
2431
    }
2432

    
2433
    @Override
2434
    public boolean has_spatial_functions() {
2435
        return this.hasSpatialFunctions;
2436
    }
2437

    
2438
    @Override
2439
    public GeometrySupportType geometry_support_type() {
2440
        return this.geometrySupportType;
2441
    }
2442

    
2443
    protected ExpressionBuilder createExpressionBuilder() {
2444
        return ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2445
    }
2446

    
2447
    @Override
2448
    public Object srs_id(IProjection projection) {
2449
        String abrev = projection.getAbrev();
2450
        return abrev.split(":")[1].trim();
2451
    }
2452

    
2453
    @Override
2454
    public String default_schema() {
2455
        return this.defaultSchema;
2456
    }
2457

    
2458
    @Override
2459
    public boolean support_schemas() {
2460
        return this.supportSchemas;
2461
    }
2462

    
2463
    @Override
2464
    public String sqltype(int type, int p, int s, int geomType, int geomSubtype) {
2465
        switch (type) {
2466
            case DataTypes.BOOLEAN:
2467
                return type_boolean;
2468
            case DataTypes.BYTE:
2469
                return type_byte;
2470
            case DataTypes.BYTEARRAY:
2471
                return type_bytearray;
2472
            case DataTypes.GEOMETRY:
2473
                return type_geometry;
2474
            case DataTypes.CHAR:
2475
                return type_char;
2476
            case DataTypes.DATE:
2477
                return type_date;
2478
            case DataTypes.DOUBLE:
2479
                // FIXME: Si cargamos la capa "country" al exportarla a
2480
                // SQLServer falla por:
2481
                //  Error de desbordamiento aritm?tico al convertir float al tipo de datos numeric.
2482
                // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
2483
                // Algeria intenta asignarle un valor de 2320972.0 y falla.
2484
                // Habria que repasar el proveedor de shape.
2485

    
2486
//                if (p > 1) {
2487
//                    if (s < 0) {
2488
//                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
2489
//                    }
2490
//                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
2491
//                }
2492
                return MessageFormat.format(type_double, p, s);
2493
            case DataTypes.BIGDECIMAL:
2494
                if (p < 1) {
2495
                    p = 20;
2496
                }
2497
                if (s < 0) {
2498
                    s = 10;
2499
                }
2500
                return MessageFormat.format(type_bigdecimal, p, s);
2501
            case DataTypes.FLOAT:
2502
                return MessageFormat.format(type_float, p, s);
2503
            case DataTypes.INT:
2504
                return MessageFormat.format(type_int, p, s);
2505
            case DataTypes.LONG:
2506
                return MessageFormat.format(type_long, p, s);
2507
            case DataTypes.STRING:
2508
                if (p < 0) {
2509
                    return type_string;
2510
                } else if (p < 4096) {
2511
                    return MessageFormat.format(type_string_p, p);
2512
                }
2513
                return type_string;
2514
            case DataTypes.TIME:
2515
                return type_time;
2516
            case DataTypes.TIMESTAMP:
2517
                return type_timestamp;
2518
            case DataTypes.VERSION:
2519
                return type_version;
2520
            case DataTypes.URI:
2521
                return type_URI;
2522
            case DataTypes.URL:
2523
                return type_URL;
2524
            case DataTypes.FILE:
2525
                return type_FILE;
2526
            case DataTypes.FOLDER:
2527
                return type_FOLDER;
2528
            default:
2529
                return null;
2530
        }
2531
    }
2532

    
2533
    @Override
2534
    public Object sqlgeometrytype(int type, int subtype) {
2535
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2536
        // identificadores numericos para el tipo y otros strings.
2537
        // Por defecto vamos a devolver strings.
2538
        if (sqlgeometrytypes == null) {
2539
            sqlgeometrytypes = new HashMap<>();
2540
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2541
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2542
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2543
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2544

    
2545
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2546
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2547
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2548
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2549

    
2550
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2551
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2552
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2553
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2554

    
2555
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2556
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2557
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2558
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2559

    
2560
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2561
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2562
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2563
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2564

    
2565
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2566
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2567
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2568
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2569

    
2570
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2571
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2572
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2573
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2574

    
2575
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2576
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2577
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2578
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2579

    
2580
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2581
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2582
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2583
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2584
        }
2585
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
2586
    }
2587

    
2588
    @Override
2589
    public Object sqlgeometrydimension(int type, int subtype) {
2590
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2591
        // identificadores numericos para las dimensiones y otros strings.
2592
        // Por defecto vamos a devolver enteros.
2593
        switch (subtype) {
2594
            case Geometry.SUBTYPES.GEOM3D:
2595
                return 3;
2596
            case Geometry.SUBTYPES.GEOM2DM:
2597
                return 3;
2598
            case Geometry.SUBTYPES.GEOM3DM:
2599
                return 4;
2600
            case Geometry.SUBTYPES.GEOM2D:
2601
            default:
2602
                return 2;
2603
        }
2604
    }
2605

    
2606
    @Override
2607
    public TableNameBuilder createTableNameBuilder() {
2608
        return new TableNameBuilderBase();
2609
    }
2610

    
2611
    protected SelectColumnBuilder createSelectColumnBuilder() {
2612
        return new SelectColumnBuilderBase();
2613
    }
2614

    
2615
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2616
        return new UpdateColumnBuilderBase();
2617
    }
2618

    
2619
    protected InsertColumnBuilder createInsertColumnBuilder() {
2620
        return new InsertColumnBuilderBase();
2621
    }
2622

    
2623
    protected OrderByBuilder createOrderByBuilder() {
2624
        return new OrderByBuilderBase();
2625
    }
2626

    
2627
    protected FromBuilder createFromBuilder() {
2628
        return new FromBuilderBase();
2629
    }
2630

    
2631
    protected SelectBuilder createSelectBuilder() {
2632
        return new SelectBuilderBase();
2633
    }
2634

    
2635
    protected UpdateBuilder createUpdateBuilder() {
2636
        return new UpdateBuilderBase();
2637
    }
2638

    
2639
    protected DeleteBuilder createDeleteBuilder() {
2640
        return new DeleteBuilderBase();
2641
    }
2642

    
2643
    protected GrantBuilder createGrantBuilder() {
2644
        return new GrantBuilderBase();
2645
    }
2646

    
2647
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2648
        return new GrantRoleBuilderBase(table, role);
2649
    }
2650

    
2651
    protected DropTableBuilder createDropTableBuilder() {
2652
        return new DropTableBuilderBase();
2653
    }
2654

    
2655
    protected CreateTableBuilder createCreateTableBuilder() {
2656
        return new CreateTableBuilderBase();
2657
    }
2658

    
2659
    protected AlterTableBuilder createAlterTableBuilder() {
2660
        return new AlterTableBuilderBase();
2661
    }
2662

    
2663
    protected InsertBuilder createInsertBuilder() {
2664
        return new InsertBuilderBase();
2665
    }
2666

    
2667
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2668
        return new UpdateTableStatisticsBuilderBase();
2669
    }
2670

    
2671
    protected CreateIndexBuilder createCreateIndexBuilder() {
2672
        return new CreateIndexBuilderBase();
2673
    }
2674

    
2675
    @Override
2676
    public SelectBuilder select() {
2677
        if (this.select == null) {
2678
            this.select = this.createSelectBuilder();
2679
        }
2680
        return this.select;
2681
    }
2682

    
2683
    @Override
2684
    public UpdateBuilder update() {
2685
        if (this.update == null) {
2686
            this.update = this.createUpdateBuilder();
2687
        }
2688
        return this.update;
2689
    }
2690

    
2691
    @Override
2692
    public UpdateTableStatisticsBuilder update_table_statistics() {
2693
        if (this.update_table_statistics == null) {
2694
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2695
        }
2696
        return this.update_table_statistics;
2697
    }
2698

    
2699
    @Override
2700
    public DropTableBuilder drop_table() {
2701
        if (this.drop_table == null) {
2702
            this.drop_table = this.createDropTableBuilder();
2703
        }
2704
        return this.drop_table;
2705
    }
2706

    
2707
    @Override
2708
    public CreateIndexBuilder create_index() {
2709
        if (this.create_index == null) {
2710
            this.create_index = this.createCreateIndexBuilder();
2711
        }
2712
        return this.create_index;
2713
    }
2714

    
2715
    @Override
2716
    public DeleteBuilder delete() {
2717
        if (this.delete == null) {
2718
            this.delete = this.createDeleteBuilder();
2719
        }
2720
        return this.delete;
2721
    }
2722

    
2723
    @Override
2724
    public InsertBuilder insert() {
2725
        if (this.insert == null) {
2726
            this.insert = this.createInsertBuilder();
2727
        }
2728
        return this.insert;
2729
    }
2730

    
2731
    @Override
2732
    public TableNameBuilder table_name() {
2733
        if (this.table_name == null) {
2734
            this.table_name = this.createTableNameBuilder();
2735
        }
2736
        return this.table_name;
2737
    }
2738

    
2739
    
2740
    @Override
2741
    public AlterTableBuilder alter_table() {
2742
        if (this.alter_table == null) {
2743
            this.alter_table = this.createAlterTableBuilder();
2744
        }
2745
        return this.alter_table;
2746
    }
2747

    
2748
    @Override
2749
    public CreateTableBuilder create_table() {
2750
        if (this.create_table == null) {
2751
            this.create_table = this.createCreateTableBuilder();
2752
        }
2753
        return this.create_table;
2754
    }
2755

    
2756
    @Override
2757
    public GrantBuilder grant() {
2758
        if (this.grant == null) {
2759
            this.grant = this.createGrantBuilder();
2760
        }
2761
        return this.grant;
2762
    }
2763

    
2764
    public void accept(Visitor visitor, VisitorFilter filter) {
2765
        if (this.select != null) {
2766
            this.select.accept(visitor, filter);
2767
        }
2768
        if (this.update != null) {
2769
            this.update.accept(visitor, filter);
2770
        }
2771
        if (this.insert != null) {
2772
            this.insert.accept(visitor, filter);
2773
        }
2774
        if (this.delete != null) {
2775
            this.delete.accept(visitor, filter);
2776
        }
2777
        if (this.alter_table != null) {
2778
            this.alter_table.accept(visitor, filter);
2779
        }
2780
        if (this.create_table != null) {
2781
            this.create_table.accept(visitor, filter);
2782
        }
2783
        if (this.drop_table != null) {
2784
            this.drop_table.accept(visitor, filter);
2785
        }
2786
        if (this.table_name != null) {
2787
            this.table_name.accept(visitor, filter);
2788
        }
2789
    }
2790

    
2791
    protected Formatter formatter() {
2792
        return ExpressionBuilder.EMPTY_FORMATTER;
2793
    }
2794

    
2795
    @Override
2796
    public String toString() {
2797
        return this.toString(formatter());
2798
    }
2799

    
2800
    @Override
2801
    public String toString(Formatter formatter) {
2802
        if (this.select != null) {
2803
            return this.select.toString(formatter);
2804
        }
2805
        if (this.update != null) {
2806
            return this.update.toString(formatter);
2807
        }
2808
        if (this.insert != null) {
2809
            return this.insert.toString(formatter);
2810
        }
2811
        if (this.delete != null) {
2812
            return this.delete.toString(formatter);
2813
        }
2814
        if (this.alter_table != null) {
2815
            return this.alter_table.toString(formatter);
2816
        }
2817
        if (this.create_table != null) {
2818
            return this.create_table.toString(formatter);
2819
        }
2820
        if (this.drop_table != null) {
2821
            return this.drop_table.toString(formatter);
2822
        }
2823
        if (this.update_table_statistics != null) {
2824
            return this.update_table_statistics.toString(formatter);
2825
        }
2826
        if (this.table_name != null) {
2827
            return this.table_name.toString(formatter);
2828
        }
2829
        return "";
2830
    }
2831

    
2832
    @Override
2833
    public CountBuilder count() {
2834
        return new CountBuilderBase();
2835
    }
2836

    
2837
    @Override
2838
    public List<Parameter> parameters() {
2839
        final List<Parameter> params = new ArrayList<>();
2840
        this.accept(new Visitor() {
2841
            @Override
2842
            public void visit(Visitable value) {
2843
                params.add((Parameter) value);
2844
            }
2845
        }, new ClassVisitorFilter(Parameter.class));
2846
        return params;
2847
    }
2848

    
2849
    @Override
2850
    public List<Variable> variables() {
2851
        final List<Variable> vars = new ArrayList<>();
2852
        this.accept(new Visitor() {
2853
            @Override
2854
            public void visit(Visitable value) {
2855
                if (!vars.contains((Variable) value)) {
2856
                    vars.add((Variable) value);
2857
                }
2858
            }
2859
        }, new ClassVisitorFilter(Variable.class));
2860
        return vars;
2861
    }
2862

    
2863
    @Override
2864
    public List<String> parameters_names() {
2865
        List<String> params = new ArrayList<>();
2866
        for (Parameter param : parameters()) {
2867
            String s;
2868
            switch (param.type()) {
2869
                case Constant:
2870
                    Object theValue = param.value();
2871
                    if (theValue == null) {
2872
                        s = "null";
2873
                    } else if (theValue instanceof String) {
2874
                        s = "'" + (String) theValue + "'";
2875
                    } else {
2876
                        s = theValue.toString();
2877
                    }
2878
                    break;
2879
                case Geometry:
2880
                case Variable:
2881
                default:
2882
                    s = "\"" + param.name() + "\"";
2883
            }
2884
            params.add(s);
2885
        }
2886
        return params;
2887
    }
2888

    
2889
    @Override
2890
    public List<String> variables_names() {
2891
        List<String> vars = new ArrayList<>();
2892
        for (Variable var : this.variables()) {
2893
            vars.add(var.name());
2894
        }
2895
        Collections.sort(vars);
2896
        return vars;
2897
    }
2898
}