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

History | View | Annotate | Download (112 KB)

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

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

    
57
@SuppressWarnings("UseSpecificCatch")
58
public class SQLBuilderBase implements SQLBuilder {
59

    
60
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
61

    
62
    protected SelectBuilder select;
63
    protected UpdateBuilder update;
64
    protected InsertBuilder insert;
65
    protected DeleteBuilder delete;
66
    protected AlterTableBuilder alter_table;
67
    protected CreateTableBuilder create_table;
68
    protected GrantBuilder grant;
69
    protected DropTableBuilder drop_table;
70
    protected UpdateTableStatisticsBuilder update_table_statistics;
71
    protected CreateIndexBuilder create_index;
72
    protected DropIndexBuilder drop_index;
73
    protected TableNameBuilder table_name;
74

    
75
    protected abstract class AbstractStatementPart extends AbstractValue {
76
        
77
    }
78

    
79
    protected abstract class AbstractStatement extends AbstractStatementPart {
80
        @Override
81
        public Value clone() throws CloneNotSupportedException {
82
            throw new CloneNotSupportedException();
83
        }
84
    }
85

    
86
    protected class ColumnDescriptorBase implements ColumnDescriptor {
87

    
88
        private String name;
89
        private int type;
90
        private int size;
91
        private int precision;
92
        private int scale;
93
        private boolean isPk;
94
        private boolean _allowNulls;
95
        private boolean _isAutomatic;
96
        private Object defaultValue;
97
        private int geom_type;
98
        private int geom_subtype;
99
        private Object geom_srsdbcode;
100
        private boolean _isIndexed;
101
        private DataStoreParameters parameters = null;
102

    
103
        public ColumnDescriptorBase(String name, int type, Object defaultValue) {
104
            this.name = name;
105
            this.type = type;
106
            this.size = -1;
107
            this.precision = -1;
108
            this.scale = -1;
109
            this.isPk = false;
110
            this._allowNulls = true;
111
            this._isAutomatic = false;
112
            this.defaultValue = defaultValue;
113
            this.geom_type = Geometry.TYPES.GEOMETRY;
114
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
115
            this.geom_srsdbcode = null;
116
            this._isIndexed = false;
117
        }
118

    
119
        public ColumnDescriptorBase(String name, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
120
            this.name = name;
121
            this.type = type;
122
            this.size = size;
123
            this.precision = precision;
124
            this.scale = scale;
125
            this.isPk = isPk;
126
            this._allowNulls = allowNulls;
127
            this._isAutomatic = isAutomatic;
128
            this.defaultValue = defaultValue;
129
            this.geom_type = Geometry.TYPES.GEOMETRY;
130
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
131
            this.geom_srsdbcode = null;
132
            this._isIndexed = isIndexed;
133
        }
134

    
135
        public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
136
            this.name = name;
137
            this.type = DataTypes.GEOMETRY;
138
            this.size = 0;
139
            this.precision = 0;
140
            this.scale = 0;
141
            this.isPk = false;
142
            this._allowNulls = allowNulls;
143
            this._isAutomatic = false;
144
            this.defaultValue = null;
145
            this.geom_type = geom_type;
146
            this.geom_subtype = geom_subtype;
147
            this.geom_srsdbcode = srs_id(proj);
148
            this._isIndexed = isIndexed;
149
        }
150

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

    
167
        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
168
            this(fad.getName(), fad.getType(), fad.getDefaultValue());
169
            this.precision = fad.getPrecision();
170
            this.size = fad.getSize();
171
            this.scale = fad.getScale();
172
            this.isPk = fad.isPrimaryKey();
173
            this._allowNulls = fad.allowNull();
174
            this._isAutomatic = fad.isAutomatic();
175
            this._isIndexed = fad.isIndexed();
176

    
177
            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
178
                this.geom_type = fad.getGeomType().getType();
179
                this.geom_subtype = fad.getGeomType().getSubType();
180
                this.geom_srsdbcode = fad.getSRS();
181
            }
182
        }
183
    
184

    
185
        @Override
186
        public String getName() {
187
            return this.name;
188
        }
189

    
190
        @Override
191
        public void setName(String name) {
192
            this.name = name;
193
        }
194

    
195
        @Override
196
        public int getType() {
197
            return this.type;
198
        }
199

    
200
        @Override
201
        public void setType(int type) {
202
            this.type = type;
203
        }
204

    
205
        @Override
206
        public int getPrecision() {
207
            return precision;
208
        }
209

    
210
        @Override
211
        public void setPrecision(int precision) {
212
            this.precision = precision;
213
        }
214

    
215
        @Override
216
        public int getScale() {
217
            return scale;
218
        }
219

    
220
        @Override
221
        public void setScale(int scale) {
222
            this.scale = scale;
223
        }
224

    
225
        @Override
226
        public int getSize() {
227
            return size;
228
        }
229

    
230
        @Override
231
        public void setSize(int size) {
232
            this.size = size;
233
        }
234

    
235
        @Override
236
        public boolean isPrimaryKey() {
237
            return isPk;
238
        }
239

    
240
        @Override
241
        public void setIsPrimaryKey(boolean isPk) {
242
            this.isPk = isPk;
243
        }
244

    
245
        @Override
246
        public boolean allowNulls() {
247
            return _allowNulls;
248
        }
249

    
250
        @Override
251
        public void setAllowNulls(boolean allowNulls) {
252
            this._allowNulls = allowNulls;
253
        }
254

    
255
        @Override
256
        public boolean isAutomatic() {
257
            return _isAutomatic;
258
        }
259

    
260
        @Override
261
        public boolean isIndexed() {
262
            return _isIndexed;
263
        }
264

    
265
        @Override
266
        public void setIsAutomatic(boolean isAutomatic) {
267
            this._isAutomatic = isAutomatic;
268
        }
269

    
270
        @Override
271
        public Object getDefaultValue() {
272
            return defaultValue;
273
        }
274

    
275
        @Override
276
        public void setDefaultValue(Object defaultValue) {
277
            this.defaultValue = defaultValue;
278
        }
279

    
280
        @Override
281
        public int getGeometryType() {
282
            return geom_type;
283
        }
284

    
285
        @Override
286
        public void setGeometryType(int geom_type) {
287
            this.geom_type = geom_type;
288
        }
289

    
290
        @Override
291
        public int getGeometrySubtype() {
292
            return geom_subtype;
293
        }
294

    
295
        @Override
296
        public void setGeometrySubtype(int geom_subtype) {
297
            this.geom_subtype = geom_subtype;
298
        }
299

    
300
        @Override
301
        public Object getGeometrySRSId() {
302
            return geom_srsdbcode;
303
        }
304

    
305
        @Override
306
        public void setGeometrySRSId(Object geom_srsid) {
307
            this.geom_srsdbcode = geom_srsid;
308
        }
309

    
310
        @Override
311
        public boolean isGeometry() {
312
            return this.type == DataTypes.GEOMETRY;
313
        }
314

    
315
        private void setStoreParameters(DataStoreParameters parameters) {
316
            this.parameters = parameters;
317
        }
318

    
319
        @Override
320
        public DataStoreParameters getStoreParameters() {
321
            return this.parameters;
322
        }
323
    }
324

    
325
    public class ColumnBase extends AbstractValue implements Column {
326

    
327
        private final String name;
328
        private TableNameBuilder table;
329

    
330
        public ColumnBase(TableNameBuilder table, String name) {
331
            this.name = name;
332
            this.table = table;
333
        }
334
        
335
        @Override
336
        public ColumnBase clone() throws CloneNotSupportedException {
337
            ColumnBase other = (ColumnBase) super.clone();
338
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
339
            return other;
340
        }
341

    
342

    
343
        @Override
344
        public String name() {
345
            return this.name;
346
        }
347

    
348
        @Override
349
        public TableNameBuilder table() {
350
            return this.table;
351
        }
352

    
353
        @Override
354
        public TableNameBuilder table(TableNameBuilder table) {
355
            this.table = table;
356
            return this.table;
357
        }
358

    
359
        @Override
360
        public String toString() {
361
            return this.toString(formatter());
362
        }
363
        
364
        @Override
365
        public String toString(Formatter<Value> formatter) {
366
            if( formatter!=null && formatter.canApply(this) ) {
367
                return formatter.format(this);
368
            }
369
            if( this.table==null ) {
370
                return as_identifier(this.name);
371
            }
372
            return this.table.toString(formatter) + "." + as_identifier(this.name);
373
        }
374

    
375
        @Override
376
        public int compareTo(Variable o) {
377
            return this.name.compareTo(o.name());
378
        }
379

    
380
        @Override
381
        public boolean equals(Object obj) {
382
            if (!(obj instanceof Variable)) {
383
                return false;
384
            }
385
            return StringUtils.equals(this.toString(), ((Variable) obj).toString());
386
        }
387

    
388
        @Override
389
        public int hashCode() {
390
            int hash = 7;
391
            hash = 37 * hash + Objects.hashCode(this.toString());
392
            return hash;
393
        }
394
    }
395

    
396
    public class TableNameBuilderBase
397
            extends AbstractStatementPart
398
            implements TableNameBuilder {
399

    
400
        public String tableName;
401
        public String schemaName;
402
        private String databaseName;
403

    
404
        public TableNameBuilderBase() {
405
        }
406
        
407
        @Override
408
        public void accept(Visitor visitor, VisitorFilter filter) {
409
            if (filter==null || filter.accept(this)) {
410
                visitor.visit(this);
411
            }
412
        }
413

    
414
        @Override
415
        public TableNameBuilder database(String name) {
416
            this.databaseName = name;
417
            return this;
418
        }
419

    
420
        @Override
421
        public TableNameBuilder schema(String name) {
422
            if (support_schemas()) {
423
                this.schemaName = name;
424
            }
425
            return this;
426
        }
427

    
428
        @Override
429
        public TableNameBuilder name(String name) {
430
            this.tableName = name;
431
            return this;
432
        }
433

    
434
        @Override
435
        public String getDatabase() {
436
            return this.databaseName;
437
        }
438

    
439
        @Override
440
        public String getSchema() {
441
            return this.schemaName;
442
        }
443

    
444
        @Override
445
        public String getName() {
446
            return this.tableName;
447
        }
448

    
449
        @Override
450
        public boolean has_schema() {
451
            if (!support_schemas()) {
452
                return false;
453
            }
454
            return !StringUtils.isEmpty(this.schemaName);
455
        }
456

    
457
        @Override
458
        public boolean has_database() {
459
            return !StringUtils.isEmpty(this.databaseName);
460
        }
461

    
462
        @Override
463
        public String toString() {
464
            return this.toString(formatter());
465
        }
466

    
467
        @Override
468
        public String toString(Formatter<Value> formatter) {
469
            if (formatter!=null && formatter.canApply(this)) {
470
                return formatter.format(this);
471
            }
472
            if (this.has_database()) {
473
                if (this.has_schema()) {
474
                    return as_identifier(this.databaseName) + "."
475
                            + as_identifier(this.schemaName) + "."
476
                            + as_identifier(this.tableName);
477
                }
478
            } else {
479
                if (this.has_schema()) {
480
                    return as_identifier(this.schemaName) + "."
481
                            + as_identifier(this.tableName);
482
                }
483
            }
484
            return as_identifier(this.tableName);
485
        }
486

    
487
        @Override
488
        public boolean equals(Object obj) {
489
            if( obj==null || !(obj instanceof TableNameBuilder) ) {
490
                return false;
491
            }
492
            TableNameBuilder other = (TableNameBuilder) obj;
493
            
494
            if (this.has_database() != other.has_database()) {
495
                return false;
496
            }
497
            String thisSchema = null;
498
            String otherSchema = null;
499
            if(support_schemas()) {
500
                thisSchema = this.schemaName;
501
                if (StringUtils.isBlank(thisSchema)) {
502
                    thisSchema = default_schema();
503
                }
504
                otherSchema = other.getSchema();
505
                if (StringUtils.isBlank(otherSchema)) {
506
                    otherSchema = default_schema();
507
                }
508
            }
509
            if (this.has_database()) {
510
                    return StringUtils.equals(this.databaseName,other.getDatabase()) &&
511
                           StringUtils.equals(thisSchema, otherSchema) &&
512
                           StringUtils.equals(this.tableName,other.getName());
513
            } else {
514
                    return StringUtils.equals(thisSchema, otherSchema) &&
515
                           StringUtils.equals(this.tableName,other.getName());
516
            }
517
        }
518

    
519
        @Override
520
        public int hashCode() {
521
            int hash = 7;
522
            hash = 37 * hash + Objects.hashCode(this.toString());
523
            return hash;
524
        }
525

    
526
    }
527

    
528
    public class CountBuilderBase
529
            extends AbstractStatementPart
530
            implements CountBuilder {
531

    
532
        protected Value value;
533
        protected boolean distinct;
534
        protected boolean all;
535

    
536
        public CountBuilderBase() {
537
            this.value = null;
538
            this.distinct = false;
539
            this.all = false;
540
        }
541
        
542
        @Override
543
        public CountBuilderBase clone() throws CloneNotSupportedException {
544
            CountBuilderBase other = (CountBuilderBase) super.clone();
545
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
546
            return other;
547
        }
548
        
549
        @Override
550
        public CountBuilder all() {
551
            this.all = true;
552
            return this;
553
        }
554

    
555
        @Override
556
        public CountBuilder column(Value value) {
557
            this.value = value;
558
            return this;
559
        }
560

    
561
        @Override
562
        public CountBuilder distinct() {
563
            this.distinct = true;
564
            return this;
565
        }
566

    
567
        @Override
568
        public String toString() {
569
            return this.toString(formatter());
570
        }
571

    
572
        @Override
573
        public String toString(Formatter formatter) {
574
            if (formatter!=null && formatter.canApply(this)) {
575
                return formatter.format(this);
576
            }
577
            if (this.all) {
578
                return "COUNT(*)";
579
            }
580
            if (this.distinct) {
581
                return MessageFormat.format(
582
                        "COUNT(DISTINCT {0})",
583
                        value.toString(formatter)
584
                );
585
            }
586
            return MessageFormat.format(
587
                    "COUNT({0})",
588
                    value.toString(formatter)
589
            );
590
        }
591

    
592
    }
593

    
594
    protected class JoinBase 
595
            extends AbstractStatementPart
596
            implements StatementPart 
597
        {
598
        protected String type;
599
        protected TableNameBuilder table;
600
        protected Value expression;
601
        
602
        public JoinBase(String type, TableNameBuilder table, Value expression) {
603
            this.type = type;
604
            this.table = table;
605
            this.expression = expression;
606
        }
607
        
608
        @Override
609
        public JoinBase clone() throws CloneNotSupportedException {
610
            JoinBase other = (JoinBase) super.clone();
611
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
612
            other.expression = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(expression);
613
            return other;
614
        }
615

    
616
        @Override
617
        public String toString() {
618
            return this.toString(formatter());
619
        }
620

    
621
        @Override
622
        public String toString(Formatter<Value> formatter) {
623
            if (formatter!=null && formatter.canApply(this)) {
624
                return formatter.format(this);
625
            }
626
            StringBuilder builder = new StringBuilder();
627
            // INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
628
            builder.append(this.type.toUpperCase());
629
            builder.append(" JOIN ");
630
            builder.append(this.table.toString(formatter));
631
            builder.append(" ON ");
632
            builder.append(this.expression.toString(formatter));
633
            return builder.toString();
634
        }
635
        
636
        
637
    }
638
    
639
    public class FromBuilderBase
640
            extends AbstractStatementPart
641
            implements FromBuilder {
642

    
643
        protected TableNameBuilder tableName;
644
        protected String subquery;
645
        protected String passthrough;
646
        protected List<JoinBase> joins;
647

    
648
        public FromBuilderBase() {
649
            this.tableName = null;
650
            this.subquery = null;
651
            this.passthrough = null;
652
            this.joins = null;
653
        }
654
        
655
        @Override
656
        public FromBuilderBase clone() throws CloneNotSupportedException {
657
            FromBuilderBase other = (FromBuilderBase) super.clone();
658
            other.tableName = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(tableName);
659
            if (joins!=null) {
660
                for (int i = 0; i < joins.size(); i++) {
661
                    other.joins.set(i, (JoinBase) joins.get(i).clone());
662
                }
663
            }
664
            return other;
665
        }
666

    
667
        @Override
668
        public FromBuilder left_join(TableNameBuilder table, Value expression) {
669
            JoinBase join = createJoin("LEFT", table, expression);
670
            if( this.joins==null ) {
671
                this.joins = new ArrayList<>();
672
            }
673
            this.joins.add(join);
674
            return this;
675
        }
676
        
677
        @Override
678
        public TableNameBuilder table() {
679
            if (tableName == null) {
680
                this.tableName = createTableNameBuilder();
681
            }
682
            return this.tableName;
683
        }
684

    
685
        @Override
686
        public void accept(Visitor visitor, VisitorFilter filter) {
687
            if (filter==null || filter.accept(this)) {
688
                visitor.visit(this);
689
            }
690
            if (this.tableName != null) {
691
                this.tableName.accept(visitor, filter);
692
            }
693
        }
694

    
695
        @Override
696
        public FromBuilder custom(String passthrough) {
697
            this.passthrough = passthrough;
698
            return this;
699
        }
700

    
701
        @Override
702
        public FromBuilder subquery(String subquery) {
703
            this.subquery = subquery;
704
            return this;
705
        }
706

    
707
        @Override
708
        public String toString() {
709
            return this.toString(formatter());
710
        }
711

    
712
        @Override
713
        public String toString(Formatter<Value> formatter) {
714
            if (formatter!=null && formatter.canApply(this)) {
715
                return formatter.format(this);
716
            }
717
            if (!StringUtils.isEmpty(passthrough)) {
718
                return passthrough;
719
            }
720
            if (!StringUtils.isEmpty(subquery)) {
721
                return "( " + this.subquery + ") as _subquery_alias_ ";
722
            }
723
            if( this.joins==null || this.joins.isEmpty() ) {
724
                return this.tableName.toString(formatter);
725
            }
726
            StringBuilder builder = new StringBuilder();
727
            builder.append(this.tableName.toString(formatter));
728
            for (JoinBase join : this.joins) {
729
                builder.append(" ");
730
                builder.append(join.toString(formatter));
731
            }
732
            return builder.toString();
733
        }
734

    
735
    }
736

    
737
    public class SelectColumnBuilderBase
738
            extends AbstractStatementPart
739
            implements SelectColumnBuilder {
740

    
741
        protected Variable name = null;
742
        protected String alias = null;
743
        protected Value value = null;
744
        protected boolean asGeometry = false;
745
        protected TableNameBuilder table;
746
        
747
        @Override
748
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
749
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
750
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
751
            other.name = (Variable) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
752
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
753
            return other;
754
        }
755

    
756
        @Override
757
        public void accept(Visitor visitor, VisitorFilter filter) {
758
            if (filter==null || filter.accept(this)) {
759
                visitor.visit(this);
760
            }
761
            if (this.name != null) {
762
                this.name.accept(visitor, filter);
763
            }
764
            if (this.value != null) {
765
                this.value.accept(visitor, filter);
766
            }
767
        }
768

    
769
        @Override
770
        public void replace(Value target, Value replacement) {
771
            if (this.name!=null ) {
772
                if( this.name == target) {
773
                    this.name = (Variable) replacement;
774
                }
775
            }
776
            if( this.value!=null ) {
777
                if (this.value == target) {
778
                    this.value = replacement;
779
                } else {
780
                    this.value.replace(target, replacement);
781
                }
782
            }
783
        }
784

    
785
        @Override
786
        public SelectColumnBuilder name(String name) {
787
            return this.name(null, name);
788
        }
789

    
790
        @Override
791
        public SelectColumnBuilder name(TableNameBuilder table, String name) {
792
            String quote = quote_for_identifiers();
793
            if (name.startsWith(quote)) {
794
                // Remove quotes
795
                name = name.substring(1, name.length() - 1);
796
            }
797
            this.name = expression().variable(name);
798
            this.table = table;
799
            this.value = null;
800
            this.asGeometry = false;
801
            return this;
802
        }
803

    
804
        @Override
805
        public SelectColumnBuilder all() {
806
            this.name = null;
807
            this.value = expression().custom("*");
808
            this.asGeometry = false;
809
            return this;
810
        }
811

    
812
        @Override
813
        public SelectColumnBuilder as_geometry() {
814
            this.asGeometry = true;
815
            return this;
816
        }
817

    
818
        @Override
819
        public SelectColumnBuilder value(Value value) {
820
            this.value = value;
821
            this.name = null;
822
            return this;
823
        }
824

    
825
        @Override
826
        public SelectColumnBuilder as(String alias) {
827
            this.alias = alias;
828
            return this;
829
        }
830

    
831
        @Override
832
        public String getName() {
833
            if (this.name==null) {
834
                return null;
835
            }
836
            return this.name.name();
837
        }
838

    
839
        @Override
840
        public String getAlias() {
841
            return this.alias;
842
        }
843

    
844
        @Override
845
        public String getValue() {
846
            return this.alias;
847
        }
848

    
849
        @Override
850
        public String toString() {
851
            return this.toString(formatter());
852
        }
853

    
854
        @Override
855
        public String toString(Formatter<Value> formatter) {
856
            if (formatter!=null && formatter.canApply(this)) {
857
                return formatter.format(this);
858
            }
859
            StringBuilder builder = new StringBuilder();
860
            if (this.asGeometry) {
861
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
862
            } else {
863
                if (this.name != null) {
864
                    if( this.table==null ) {
865
                        builder.append(this.name.toString(formatter));
866
                    } else {
867
                        builder.append(this.table.toString(formatter));
868
                        builder.append(".");
869
                        builder.append(this.name.toString(formatter));
870
                    }
871
                } else {
872
                    builder.append(this.value.toString(formatter));
873
                }
874
            }
875
            if (this.alias != null) {
876
                builder.append(" AS ");
877
                builder.append(as_identifier(this.alias));
878
            }
879
            return builder.toString();
880
        }
881
        public boolean isGeometry() {
882
            return this.asGeometry;
883
        }
884
        
885
        public TableNameBuilder getTable() {
886
            return this.table;
887
        }
888
    }
889

    
890
    public class OrderByBuilderBase
891
            extends AbstractStatementPart
892
            implements OrderByBuilder {
893

    
894
        protected Value value;
895
        protected String custom;
896
        protected boolean ascending;
897

    
898
        public OrderByBuilderBase() {
899
            this.ascending = true;
900
        }
901
        
902
        @Override
903
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
904
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
905
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
906
            return other;
907
        }
908
        
909
        @Override
910
        public void accept(Visitor visitor, VisitorFilter filter) {
911
            if (filter==null || filter.accept(this)) {
912
                visitor.visit(this);
913
            }
914
            if (this.value!=null) {
915
                this.value.accept(visitor, filter);
916
            }
917
        }
918

    
919
        @Override
920
        public OrderByBuilder column(String name) {
921
            this.value = expression().variable(name);
922
            return this;
923
        }
924
        
925
        @Override
926
        public boolean isColumn(String name) {
927
            if(this.value instanceof ExpressionBuilder.Variable){
928
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
929
            }
930
            return false;
931
        }
932
        
933
        @Override
934
        public boolean isColumn(Value value) {
935
            if(value instanceof ExpressionBuilder.Variable){
936
                return isColumn(((ExpressionBuilder.Variable)value).name());
937
            }
938
            return this.value == value;
939
        }
940
        
941
        @Override
942
        public OrderByBuilder value(Value expression) {
943
            this.value = expression;
944
            return this;
945
        }
946
        
947
        @Override
948
        public OrderByBuilder custom(String order) {
949
            this.custom = order;
950
            return this;
951
        }
952

    
953
        @Override
954
        public OrderByBuilder ascending() {
955
            this.ascending = true;
956
            return this;
957
        }
958

    
959
        @Override
960
        public OrderByBuilder ascending(boolean asc) {
961
            this.ascending = asc;
962
            return this;
963
        }
964

    
965
        @Override
966
        public OrderByBuilder descending() {
967
            this.ascending = false;
968
            return this;
969
        }
970

    
971
        @Override
972
        public String toString() {
973
            return this.toString(formatter());
974
        }
975

    
976
        @Override
977
        public String toString(Formatter<Value> formatter) {
978
            if (formatter!=null && formatter.canApply(this)) {
979
                return formatter.format(this);
980
            }
981
            if (!StringUtils.isEmpty(this.custom)) {
982
                return this.custom;
983
            }
984
            if (this.ascending) {
985
                return this.value.toString(formatter) + " ASC NULLS LAST";
986
            }
987
            return this.value.toString(formatter) + " DESC NULLS FIRST";
988
        }
989
    }
990

    
991
    public class SelectBuilderBase
992
            extends AbstractStatement
993
            implements SelectBuilder {
994

    
995
        protected FromBuilder from;
996
        protected GeometryExpressionBuilder where;
997
        protected long limit = -1;
998
        protected long offset = -1;
999
        protected List<SelectColumnBuilder> columns;
1000
        protected List<OrderByBuilder> order_by;
1001
        protected boolean distinct;
1002
        protected List<Value> groupColumn;
1003
        protected boolean check_order_and_offset = true;
1004

    
1005
        public SelectBuilderBase() {
1006
            this.columns = new ArrayList<>();
1007
            this.distinct = false;
1008
        }
1009
        @Override
1010
        public List<Value> getGroups() {
1011
            return this.groupColumn;
1012
        }
1013
        
1014
        public List<SelectColumnBuilder> getColumns() {
1015
            return Collections.unmodifiableList(this.columns);
1016
    }
1017
        
1018
        public void remove_column(String columnName) {
1019
            SelectColumnBuilder found = null;
1020
            for (SelectColumnBuilder column : columns) {
1021
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1022
                    found = column;
1023
                    break;
1024
                }
1025
                    
1026
            }
1027
            if(found!=null) {
1028
                columns.remove(found);
1029
            }
1030
        }
1031

    
1032
        @Override
1033
        public SelectBuilder group_by(Value... columns) {
1034
            if( this.groupColumn==null ) {
1035
                this.groupColumn = new ArrayList<>();
1036
            }
1037
            for (Value column : columns) {
1038
                this.groupColumn.add(column);
1039
            }
1040
            return this;
1041
        }
1042

    
1043
        @Override
1044
        public void accept(Visitor visitor, VisitorFilter filter) {
1045
            if (filter==null || filter.accept(this)) {
1046
                visitor.visit(this);
1047
            }
1048
            for (SelectColumnBuilder column : columns) {
1049
                column.accept(visitor, filter);
1050
            }
1051
            if (this.has_from()) {
1052
                this.from.accept(visitor, filter);
1053
            }
1054
            if (this.has_where()) {
1055
                this.where.accept(visitor, filter);
1056
            }
1057
            if (this.has_order_by()) {
1058
                for (OrderByBuilder order : order_by) {
1059
                    order.accept(visitor, filter);
1060
                }
1061
            }
1062
            if (this.has_group_by()) {
1063
                for (Value group : groupColumn) {
1064
                    group.accept(visitor, filter);
1065
                }
1066
            }
1067
        }
1068

    
1069
        @Override
1070
        public void replace(Value target, Value replacement) {
1071
            if( this.columns!=null ) {
1072
                for (int i = 0; i < columns.size(); i++) {
1073
                    SelectColumnBuilder column = columns.get(i);
1074
                    if( column == target ) {
1075
                        columns.set(i, (SelectColumnBuilder) replacement);
1076
                    } else {
1077
                        column.replace(target, replacement);
1078
                    }
1079
                }
1080
            }
1081
            if (this.has_from()) {
1082
                if( this.from == target ) {
1083
                    this.from = (FromBuilder) replacement;
1084
                } else {
1085
                    this.from.replace(target, replacement);
1086
                }
1087
            }
1088
            if (this.has_where()) {
1089
                if( this.where == target ) {
1090
                    this.where = (GeometryExpressionBuilder) replacement;
1091
                } else if( this.where.value() == target ) {
1092
                    this.where.value(replacement);
1093
                } else {
1094
                    this.where.value().replace(target, replacement);
1095
                }
1096
            }
1097
            if (this.has_order_by()) {
1098
                for (int i = 0; i < order_by.size(); i++) {
1099
                    OrderByBuilder order = order_by.get(i);
1100
                    if( order == target ) {
1101
                        order_by.set(i, (OrderByBuilder) replacement);
1102
                    } else {
1103
                        order.replace(target, replacement);
1104
                    }
1105
                }
1106
            }
1107
            if (this.has_group_by()) {
1108
                for (int i = 0; i < groupColumn.size(); i++) {
1109
                    Value group = groupColumn.get(i);
1110
                    if( group == target ) {
1111
                        groupColumn.set(i, replacement);
1112
                    } else {
1113
                        group.replace(target, replacement);
1114
                    }
1115
                }
1116
            }
1117
        }
1118

    
1119
        @Override
1120
        public SelectBuilder distinct() {
1121
            this.distinct = true;
1122
            return this;
1123
        }
1124

    
1125
        @Override
1126
        public SelectColumnBuilder column() {
1127
            SelectColumnBuilder builder = createSelectColumnBuilder();
1128
            this.columns.add(builder);
1129
            return builder;
1130
        }
1131

    
1132
        @Override
1133
        public SelectBuilder remove_all_columns() {
1134
            this.columns = new ArrayList<>();
1135
            return this;
1136
        }
1137
        
1138
        @Override
1139
        public boolean has_column(String name) {
1140
            for (SelectColumnBuilder column : columns) {
1141
                if (StringUtils.equals(name, column.getName())) {
1142
                    return true;
1143
                }
1144
                if (StringUtils.equals(name, column.getAlias())) {
1145
                    return true;
1146
                }
1147
            }
1148
            return false;
1149
        }
1150

    
1151
        @Override
1152
        public FromBuilder from() {
1153
            if (this.from == null) {
1154
                this.from = createFromBuilder();
1155
            }
1156
            return this.from;
1157
        }
1158

    
1159
        @Override
1160
        public boolean has_from() {
1161
            return this.from != null;
1162
        }
1163

    
1164
        @Override
1165
        public GeometryExpressionBuilder where() {
1166
            if (this.where == null) {
1167
                this.where = createExpressionBuilder();
1168
            }
1169
            return this.where;
1170
        }
1171

    
1172
        @Override
1173
        public boolean has_where() {
1174
            if (this.where == null) {
1175
                return false;
1176
            }
1177
            return this.where.value() != null;
1178
        }
1179

    
1180
        @Override
1181
        public SelectBuilder limit(long limit) {
1182
            this.limit = limit;
1183
            return this;
1184
        }
1185

    
1186
        @Override
1187
        public SelectBuilder limit(Long limit) {
1188
            if (limit == null) {
1189
                this.limit = 0;
1190
            } else {
1191
                this.limit = limit;
1192
            }
1193
            return this;
1194
        }
1195

    
1196
        @Override
1197
        public boolean has_limit() {
1198
            return this.limit > 0;
1199
        }
1200

    
1201
        @Override
1202
        public SelectBuilder offset(long offset) {
1203
            this.offset = offset;
1204
            return this;
1205
        }
1206

    
1207
        @Override
1208
        public boolean has_offset() {
1209
            return this.offset > 0;
1210
        }
1211

    
1212
        @Override
1213
        public OrderByBuilder order_by() {
1214
            if (this.order_by == null) {
1215
                this.order_by = new ArrayList<>();
1216
            }
1217
            OrderByBuilder order = createOrderByBuilder();
1218
            this.order_by.add(order);
1219
            return order;
1220
        }
1221
        
1222
        public OrderByBuilder getOrderBy(Value column) {
1223
            if(this.order_by == null){
1224
                return null;
1225
            }
1226
            for (OrderByBuilder orderByBuilder : this.order_by) {
1227
                if(orderByBuilder.isColumn(column)){
1228
                    return orderByBuilder;
1229
                }
1230
            }
1231
            return null;
1232
        }
1233
        
1234
        public OrderByBuilder getOrderBy(String column) {
1235
            if(this.order_by == null){
1236
                return null;
1237
            }
1238
            for (OrderByBuilder orderByBuilder : this.order_by) {
1239
                if(orderByBuilder.isColumn(column)){
1240
                    return orderByBuilder;
1241
                }
1242
            }
1243
            return null;
1244
        }
1245

    
1246
        @Override
1247
        public boolean has_order_by() {
1248
            if (this.order_by == null) {
1249
                return false;
1250
            }
1251
            return !this.order_by.isEmpty();
1252
        }
1253
        
1254
        @Override
1255
        public boolean has_group_by() {
1256
            if (this.groupColumn == null) {
1257
                return false;
1258
            }
1259
            return !this.groupColumn.isEmpty();
1260
        }
1261
        
1262
        @Override
1263
        public void disable_check_order_and_offset() {
1264
          this.check_order_and_offset = false;
1265
        }
1266
        
1267
        protected boolean isValid(StringBuilder message) {
1268
            if (message == null) {
1269
                message = new StringBuilder();
1270
            }
1271
            if( this.check_order_and_offset ) {
1272
              if (this.has_offset() && !this.has_order_by()) {
1273
                  // Algunos gestores de BBDD requieren que se especifique un
1274
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1275
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1276
                  // siempre.
1277
                  message.append("Can't use OFFSET without an ORDER BY.");
1278
                  return false;
1279
              }
1280
            }
1281
            return true;
1282
        }
1283

    
1284
        @Override
1285
        public String toString() {
1286
            return this.toString(formatter());
1287
        }
1288

    
1289
        @Override
1290
        public String toString(Formatter<Value> formatter) {
1291
            if (formatter!=null && formatter.canApply(this)) {
1292
                return formatter.format(this);
1293
            }
1294
            StringBuilder builder = new StringBuilder();
1295
            if (!this.isValid(builder)) {
1296
                throw new IllegalStateException(builder.toString());
1297
            }
1298
            builder.append("SELECT ");
1299
            if (this.distinct) {
1300
                builder.append("DISTINCT ");
1301
            }
1302
            boolean first = true;
1303
            for (SelectColumnBuilder column : columns) {
1304
                if (first) {
1305
                    first = false;
1306
                } else {
1307
                    builder.append(", ");
1308
                }
1309
                builder.append(column.toString(formatter));
1310
            }
1311

    
1312
            if (this.has_from()) {
1313
                builder.append(" FROM ");
1314
                builder.append(this.from.toString(formatter));
1315
            }
1316
            if (this.has_where()) {
1317
                builder.append(" WHERE ");
1318
                builder.append(this.where.toString(formatter));
1319
            }
1320
            if( this.has_group_by() ) {
1321
                builder.append(" GROUP BY ");
1322
                builder.append(this.groupColumn.get(0).toString(formatter));
1323
                for (int i = 1; i < groupColumn.size(); i++) {
1324
                    builder.append(", ");
1325
                    builder.append(this.groupColumn.get(i).toString(formatter));
1326
                }
1327
            }
1328
            if (this.has_order_by()) {
1329
                builder.append(" ORDER BY ");
1330
                first = true;
1331
                for (OrderByBuilder item : this.order_by) {
1332
                    if (first) {
1333
                        first = false;
1334
                    } else {
1335
                        builder.append(", ");
1336
                    }
1337
                    builder.append(item.toString(formatter));
1338
                }
1339
            }
1340

    
1341
            if (this.has_limit()) {
1342
                builder.append(" LIMIT ");
1343
                builder.append(this.limit);
1344
            }
1345
            if (this.has_offset()) {
1346
                builder.append(" OFFSET ");
1347
                builder.append(this.offset);
1348
            }
1349
            return builder.toString();
1350

    
1351
        }
1352
    }
1353

    
1354
    public class DropTableBuilderBase
1355
            extends AbstractStatement
1356
            implements DropTableBuilder {
1357

    
1358
        protected TableNameBuilder table;
1359

    
1360
        @Override
1361
        public TableNameBuilder table() {
1362
            if (table == null) {
1363
                table = createTableNameBuilder();
1364
            }
1365
            return table;
1366
        }
1367

    
1368
        @Override
1369
        public void accept(Visitor visitor, VisitorFilter filter) {
1370
            if (filter==null || filter.accept(this)) {
1371
                visitor.visit(this);
1372
            }
1373
            this.table.accept(visitor, filter);
1374
        }
1375

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

    
1381
        @Override
1382
        public String toString(Formatter<Value> formatter) {
1383
            if (formatter!=null && formatter.canApply(this)) {
1384
                return formatter.format(this);
1385
            }
1386
            StringBuilder builder = new StringBuilder();
1387
            boolean first = true;
1388
            for (String sql : toStrings(formatter)) {
1389
                if (StringUtils.isEmpty(sql)) {
1390
                    continue;
1391
                }
1392
                if (first) {
1393
                    first = false;
1394
                } else {
1395
                    builder.append("; ");
1396
                }
1397
                builder.append(sql);
1398
            }
1399
            return builder.toString();
1400
        }
1401

    
1402
        @Override
1403
        public List<String> toStrings() {
1404
            return this.toStrings(formatter());
1405
        }
1406

    
1407
        @Override
1408
        public List<String> toStrings(Formatter formatter) {
1409
            List<String> sqls = new ArrayList<>();
1410

    
1411
            sqls.add(
1412
                    MessageFormat.format(
1413
                            STMT_DROP_TABLE_table,
1414
                            this.table.toString(formatter)
1415
                    )
1416
            );
1417
            String sql;
1418
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1419
                if (this.table.has_schema()) {
1420
                    sql = MessageFormat.format(
1421
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1422
                            as_string(this.table.getSchema()),
1423
                            as_string(this.table.getName())
1424
                    );
1425
                } else {
1426
                    sql = MessageFormat.format(
1427
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1428
                            as_identifier(this.table.getName())
1429
                    );
1430
                }
1431
                if (!StringUtils.isEmpty(sql)) {
1432
                    sqls.add(sql);
1433
                }
1434
            }
1435
            return sqls;
1436
        }
1437
    }
1438

    
1439
    public class GrantRoleBuilderBase
1440
            extends AbstractStatementPart
1441
            implements GrantRoleBuilder {
1442

    
1443
        protected TableNameBuilder table;
1444
        protected String role;
1445
        protected Set<Privilege> privileges;
1446

    
1447
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1448
            this.table = table;
1449
            this.role = role;
1450
            this.privileges = new HashSet<>();
1451
        }
1452
        
1453
        @Override
1454
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1455
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1456
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1457
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1458
            
1459
            return other;
1460
        }
1461

    
1462
        @Override
1463
        public GrantRoleBuilder privilege(Privilege privilege) {
1464
            privileges.add(privilege);
1465
            return this;
1466
        }
1467

    
1468
        @Override
1469
        public GrantRoleBuilder select() {
1470
            privileges.add(Privilege.SELECT);
1471
            return this;
1472
        }
1473

    
1474
        @Override
1475
        public GrantRoleBuilder update() {
1476
            privileges.add(Privilege.UPDATE);
1477
            return this;
1478
        }
1479

    
1480
        @Override
1481
        public GrantRoleBuilder insert() {
1482
            privileges.add(Privilege.INSERT);
1483
            return this;
1484
        }
1485

    
1486
        @Override
1487
        public GrantRoleBuilder delete() {
1488
            privileges.add(Privilege.DELETE);
1489
            return this;
1490
        }
1491

    
1492
        @Override
1493
        public GrantRoleBuilder truncate() {
1494
            privileges.add(Privilege.TRUNCATE);
1495
            return this;
1496
        }
1497

    
1498
        @Override
1499
        public GrantRoleBuilder reference() {
1500
            privileges.add(Privilege.REFERENCE);
1501
            return this;
1502
        }
1503

    
1504
        @Override
1505
        public GrantRoleBuilder trigger() {
1506
            privileges.add(Privilege.TRIGGER);
1507
            return this;
1508
        }
1509

    
1510
        @Override
1511
        public GrantRoleBuilder all() {
1512
            privileges.add(Privilege.ALL);
1513
            return this;
1514
        }
1515

    
1516
        protected String getPrivilegeName(Privilege privilege) {
1517
            switch (privilege) {
1518
                case DELETE:
1519
                    return "DELETE";
1520
                case INSERT:
1521
                    return "INSERT";
1522
                case REFERENCE:
1523
                    return "REFERENCE";
1524
                case SELECT:
1525
                    return "SELECT";
1526
                case TRIGGER:
1527
                    return "TRIGGER";
1528
                case TRUNCATE:
1529
                    return "TRUNCATE";
1530
                case UPDATE:
1531
                    return "UPDATE";
1532
                case ALL:
1533
                default:
1534
                    return "ALL";
1535
            }
1536
        }
1537

    
1538
        @Override
1539
        public String toString() {
1540
            return this.toString(formatter());
1541
        }
1542

    
1543
        @Override
1544
        public String toString(Formatter<Value> formatter) {
1545
            if (formatter!=null && formatter.canApply(this)) {
1546
                return formatter.format(this);
1547
            }
1548
            StringBuilder builder = new StringBuilder();
1549
            boolean first = true;
1550
            for (Privilege privilege : privileges) {
1551
                if (first) {
1552
                    first = false;
1553
                } else {
1554
                    builder.append(", ");
1555
                }
1556
                builder.append(this.getPrivilegeName(privilege));
1557
            }
1558
            String sql = MessageFormat.format(
1559
                    STMT_GRANT_privileges_ON_table_TO_role,
1560
                    builder.toString(),
1561
                    table.toString(formatter),
1562
                    role
1563
            );
1564
            return sql;
1565
        }
1566
    }
1567

    
1568
    public class GrantBuilderBase
1569
            extends AbstractStatement
1570
            implements GrantBuilder {
1571

    
1572
        protected TableNameBuilder table;
1573
        protected Map<String, GrantRoleBuilder> roles;
1574

    
1575
        public GrantBuilderBase() {
1576
            this.roles = new HashMap<>();
1577
        }
1578

    
1579
        @Override
1580
        public TableNameBuilder table() {
1581
            if (table == null) {
1582
                table = createTableNameBuilder();
1583
            }
1584
            return table;
1585
        }
1586

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

    
1597
        @Override
1598
        public GrantRoleBuilder role(String role) {
1599
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1600
            if (roleBuilder == null) {
1601
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1602
                this.roles.put(role, roleBuilder);
1603
            }
1604
            return roleBuilder;
1605
        }
1606

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

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

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

    
1638
        @Override
1639
        public List<String> toStrings(Formatter formatter) {
1640
            List<String> sqls = new ArrayList<>();
1641
            for (GrantRoleBuilder role : roles.values()) {
1642
                sqls.add(role.toString(formatter));
1643
            }
1644
            return sqls;
1645
        }
1646
    }
1647

    
1648
    public class UpdateColumnBuilderBase
1649
            extends InsertColumnBuilderBase
1650
            implements UpdateColumnBuilder {
1651

    
1652
        public UpdateColumnBuilderBase() {
1653
            super();
1654
        }
1655

    
1656
        @Override
1657
        public UpdateColumnBuilder name(String name) {
1658
            return (UpdateColumnBuilder) super.name(name);
1659
        }
1660

    
1661
        @Override
1662
        public UpdateColumnBuilder with_value(Value value) {
1663
            return (UpdateColumnBuilder) super.with_value(value);
1664
        }
1665

    
1666
    }
1667

    
1668
    public class UpdateBuilderBase
1669
            extends AbstractStatement
1670
            implements UpdateBuilder {
1671

    
1672
        protected GeometryExpressionBuilder where;
1673
        protected List<UpdateColumnBuilder> columns;
1674
        protected TableNameBuilder table;
1675

    
1676
        public UpdateBuilderBase() {
1677
            this.columns = new ArrayList<>();
1678
        }
1679

    
1680
        @Override
1681
        public void accept(Visitor visitor, VisitorFilter filter) {
1682
            if (filter==null || filter.accept(this)) {
1683
                visitor.visit(this);
1684
            }
1685
            if (this.table != null) {
1686
                this.table.accept(visitor, filter);
1687
            }
1688
            for (UpdateColumnBuilder column : columns) {
1689
                column.accept(visitor, filter);
1690
            }
1691
            if (this.has_where()) {
1692
                this.where.accept(visitor, filter);
1693
            }
1694
        }
1695

    
1696
        @Override
1697
        public GeometryExpressionBuilder where() {
1698
            if (this.where == null) {
1699
                this.where = createExpressionBuilder();
1700
            }
1701
            return this.where;
1702
        }
1703

    
1704
        @Override
1705
        public TableNameBuilder table() {
1706
            if (table == null) {
1707
                table = createTableNameBuilder();
1708
            }
1709
            return table;
1710
        }
1711

    
1712
        @Override
1713
        public UpdateColumnBuilder column() {
1714
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1715
            this.columns.add(column);
1716
            return column;
1717
        }
1718

    
1719
        @Override
1720
        public boolean has_where() {
1721
            return this.where != null;
1722
        }
1723

    
1724
        @Override
1725
        public String toString() {
1726
            return this.toString(formatter());
1727
        }
1728

    
1729
        @Override
1730
        public String toString(Formatter<Value> formatter) {
1731
            if (formatter!=null && formatter.canApply(this)) {
1732
                return formatter.format(this);
1733
            }
1734
            /*
1735
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1736
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1737
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1738
             * output_expression [ AS output_name ] [, ...] ]
1739
             */
1740
            StringBuilder columnsAndValues = new StringBuilder();
1741

    
1742
            boolean first = true;
1743
            for (UpdateColumnBuilder column : columns) {
1744
                if (first) {
1745
                    first = false;
1746
                } else {
1747
                    columnsAndValues.append(", ");
1748
                }
1749
                columnsAndValues.append(as_identifier(column.getName()));
1750
                columnsAndValues.append(" = ");
1751
                columnsAndValues.append(column.getValue().toString(formatter));
1752
            }
1753

    
1754
            String sql;
1755
            if (this.has_where()) {
1756
                sql = MessageFormat.format(
1757
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1758
                        this.table.toString(formatter),
1759
                        columnsAndValues.toString(),
1760
                        this.where.toString(formatter)
1761
                );
1762
            } else {
1763
                sql = MessageFormat.format(
1764
                        STMT_UPDATE_table_SET_columnsAndValues,
1765
                        this.table.toString(formatter),
1766
                        columnsAndValues.toString()
1767
                );
1768
            }
1769
            return sql;
1770
        }
1771
    }
1772

    
1773
    public class DeleteBuilderBase
1774
            extends AbstractStatement
1775
            implements DeleteBuilder {
1776

    
1777
        protected GeometryExpressionBuilder where;
1778
        protected TableNameBuilder table;
1779

    
1780
        public DeleteBuilderBase() {
1781
        }
1782

    
1783
        @Override
1784
        public void accept(Visitor visitor, VisitorFilter filter) {
1785
            if (filter==null || filter.accept(this)) {
1786
                visitor.visit(this);
1787
            }
1788
            if (this.table != null) {
1789
                this.table.accept(visitor, filter);
1790
            }
1791
            if (this.has_where()) {
1792
                this.where.accept(visitor, filter);
1793
            }
1794
        }
1795

    
1796
        @Override
1797
        public GeometryExpressionBuilder where() {
1798
            if (this.where == null) {
1799
                this.where = createExpressionBuilder();
1800
            }
1801
            return this.where;
1802
        }
1803

    
1804
        @Override
1805
        public TableNameBuilder table() {
1806
            if (table == null) {
1807
                table = createTableNameBuilder();
1808
            }
1809
            return table;
1810
        }
1811

    
1812
        @Override
1813
        public boolean has_where() {
1814
            return this.where != null;
1815
        }
1816

    
1817
        @Override
1818
        public String toString() {
1819
            return this.toString(formatter());
1820
        }
1821

    
1822
        @Override
1823
        public String toString(Formatter<Value> formatter) {
1824
            if (formatter!=null && formatter.canApply(this)) {
1825
                return formatter.format(this);
1826
            }
1827
            /*
1828
             * DELETE FROM table_name
1829
             * WHERE some_column=some_value; 
1830
             */
1831
            String sql;
1832
            if (this.has_where()) {
1833
                sql = MessageFormat.format(
1834
                        STMT_DELETE_FROM_table_WHERE_expresion,
1835
                        this.table.toString(formatter),
1836
                        this.where.toString(formatter)
1837
                );
1838
            } else {
1839
                sql = MessageFormat.format(
1840
                        STMT_DELETE_FROM_table,
1841
                        this.table.toString(formatter)
1842
                );
1843
            }
1844
            return sql;
1845
        }
1846
    }
1847

    
1848
    public class CreateIndexBuilderBase
1849
            extends AbstractStatement
1850
            implements CreateIndexBuilder {
1851

    
1852
        protected boolean ifNotExist = false;
1853
        protected boolean isUnique = false;
1854
        protected String indexName;
1855
        protected boolean isSpatial = false;
1856
        protected TableNameBuilder table;
1857
        protected final List<String> columns;
1858

    
1859
        public CreateIndexBuilderBase() {
1860
            this.columns = new ArrayList<>();
1861
        }
1862

    
1863
        @Override
1864
        public CreateIndexBuilder unique() {
1865
            this.isUnique = true;
1866
            return this;
1867
        }
1868

    
1869
        @Override
1870
        public CreateIndexBuilder if_not_exist() {
1871
            this.ifNotExist = true;
1872
            return this;
1873
        }
1874

    
1875
        @Override
1876
        public CreateIndexBuilder name(String name) {
1877
            this.indexName = name;
1878
            return this;
1879
        }
1880

    
1881
        @Override
1882
        public CreateIndexBuilder name(String tableName, String columnName) {
1883
            this.indexName = tableName + "_IDX_" + columnName;
1884
            return this;
1885
        }
1886

    
1887
        @Override
1888
        public CreateIndexBuilder spatial() {
1889
            this.isSpatial = true;
1890
            return this;
1891
        }
1892

    
1893
        @Override
1894
        public CreateIndexBuilder column(String name) {
1895
            this.columns.add(name);
1896
            return this;
1897
        }
1898

    
1899
        @Override
1900
        public TableNameBuilder table() {
1901
            if (table == null) {
1902
                table = createTableNameBuilder();
1903
            }
1904
            return table;
1905
        }
1906

    
1907
        @Override
1908
        public void accept(Visitor visitor, VisitorFilter filter) {
1909
            if (filter==null || filter.accept(this)) {
1910
                visitor.visit(this);
1911
            }
1912
            if (this.table != null) {
1913
                this.table.accept(visitor, filter);
1914
            }
1915
        }
1916

    
1917
        @Override
1918
        public String toString() {
1919
            return this.toString(formatter());
1920
        }
1921

    
1922
        @Override
1923
        public String toString(Formatter<Value> formatter) {
1924
            if (formatter!=null && formatter.canApply(this)) {
1925
                return formatter.format(this);
1926
            }
1927
            StringBuilder builder = new StringBuilder();
1928
            boolean first = true;
1929
            for (String sql : toStrings(formatter)) {
1930
                if (StringUtils.isEmpty(sql)) {
1931
                    continue;
1932
                }
1933
                if (first) {
1934
                    first = false;
1935
                } else {
1936
                    builder.append("; ");
1937
                }
1938
                builder.append(sql);
1939
            }
1940
            return builder.toString();
1941
        }
1942

    
1943
        @Override
1944
        public List<String> toStrings() {
1945
            return this.toStrings(formatter());
1946
        }
1947

    
1948
        @Override
1949
        public List<String> toStrings(Formatter formatter) {
1950
            StringBuilder builder = new StringBuilder();
1951
            builder.append("CREATE ");
1952
            if (this.isUnique) {
1953
                builder.append("UNIQUE ");
1954
            }
1955
            builder.append("INDEX ");
1956
            if (this.ifNotExist) {
1957
                builder.append("IF NOT EXISTS ");
1958
            }
1959
            builder.append(as_identifier(this.indexName));
1960
            builder.append(" ON ");
1961
            builder.append(this.table.toString(formatter));
1962
            if (this.isSpatial) {
1963
                builder.append(" USING GIST ");
1964
            }
1965
            builder.append(" ( ");
1966
            boolean is_first_column = true;
1967
            for (String column : this.columns) {
1968
                if (is_first_column) {
1969
                    is_first_column = false;
1970
                } else {
1971
                    builder.append(", ");
1972
                }
1973
                builder.append(column);
1974
            }
1975
            builder.append(" )");
1976

    
1977
            List<String> sqls = new ArrayList<>();
1978
            sqls.add(builder.toString());
1979
            return sqls;
1980
        }
1981

    
1982
    }
1983

    
1984
    public class DropIndexBuilderBase
1985
            extends AbstractStatement
1986
            implements DropIndexBuilder {
1987

    
1988
        protected boolean ifNotExist = false;
1989
        protected String indexName;
1990

    
1991
        public DropIndexBuilderBase() {
1992
        }
1993

    
1994
        @Override
1995
        public DropIndexBuilder if_not_exist() {
1996
            this.ifNotExist = true;
1997
            return this;
1998
        }
1999

    
2000
        @Override
2001
        public DropIndexBuilder name(String name) {
2002
            this.indexName = name;
2003
            return this;
2004
        }
2005

    
2006
        @Override
2007
        public DropIndexBuilder name(String tableName, String columnName) {
2008
            this.indexName = tableName + "_IDX_" + columnName;
2009
            return this;
2010
        }
2011

    
2012
        @Override
2013
        public String toString() {
2014
            return this.toString(formatter());
2015
        }
2016

    
2017
        @Override
2018
        public String toString(Formatter<Value> formatter) {
2019
            if (formatter!=null && formatter.canApply(this)) {
2020
                return formatter.format(this);
2021
            }
2022
            StringBuilder builder = new StringBuilder();
2023
            boolean first = true;
2024
            for (String sql : toStrings(formatter)) {
2025
                if (StringUtils.isEmpty(sql)) {
2026
                    continue;
2027
                }
2028
                if (first) {
2029
                    first = false;
2030
                } else {
2031
                    builder.append("; ");
2032
                }
2033
                builder.append(sql);
2034
            }
2035
            return builder.toString();
2036
        }
2037

    
2038
        @Override
2039
        public List<String> toStrings() {
2040
            return this.toStrings(formatter());
2041
        }
2042

    
2043
        @Override
2044
        public List<String> toStrings(Formatter formatter) {
2045
            StringBuilder builder = new StringBuilder();
2046
            builder.append("DROP INDEX ");
2047
            if (this.ifNotExist) {
2048
                builder.append("IF NOT EXISTS ");
2049
            }
2050
            builder.append(as_identifier(this.indexName));
2051
            List<String> sqls = new ArrayList<>();
2052
            sqls.add(builder.toString());
2053
            return sqls;
2054
        }
2055

    
2056
    }
2057

    
2058
    public class AlterTableBuilderBase
2059
            extends AbstractStatement
2060
            implements AlterTableBuilder {
2061

    
2062
        protected TableNameBuilder table;
2063
        protected List<String> drops;
2064
        protected List<ColumnDescriptor> adds;
2065
        protected List<ColumnDescriptor> alters;
2066
        protected List<Pair<String, String>> renames;
2067
        protected String drop_primary_key_column;
2068

    
2069
        public AlterTableBuilderBase() {
2070
            this.drops = new ArrayList<>();
2071
            this.adds = new ArrayList<>();
2072
            this.alters = new ArrayList<>();
2073
            this.renames = new ArrayList<>();
2074
        }
2075

    
2076
        @Override
2077
        public boolean isEmpty() {
2078
            return this.drops.isEmpty()
2079
                    && this.adds.isEmpty()
2080
                    && this.alters.isEmpty()
2081
                    && this.renames.isEmpty();
2082
        }
2083

    
2084
        @Override
2085
        public void accept(Visitor visitor, VisitorFilter filter) {
2086
            if (filter==null || filter.accept(this)) {
2087
                visitor.visit(this);
2088
            }
2089
            if (this.table != null) {
2090
                this.table.accept(visitor, filter);
2091
            }
2092
        }
2093

    
2094
        @Override
2095
        public TableNameBuilder table() {
2096
            if (table == null) {
2097
                table = createTableNameBuilder();
2098
            }
2099
            return table;
2100
        }
2101

    
2102
        @Override
2103
        public AlterTableBuilder drop_column(String columnName) {
2104
            this.drops.add(columnName);
2105
            return this;
2106
        }
2107

    
2108
        @Override
2109
        public AlterTableBuilder drop_primary_key(String columnName) {
2110
            this.drop_primary_key_column = columnName;
2111
            return this;
2112
        }
2113

    
2114
        @Override
2115
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2116
            this.adds.add(new ColumnDescriptorBase(fad));
2117
            return this;
2118
        }
2119

    
2120
        @Override
2121
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2122
            if (isPk || isAutomatic) {
2123
                allowNulls = false;
2124
            }
2125
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2126
            return this;
2127
        }
2128

    
2129
        @Override
2130
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2131
            if (StringUtils.isEmpty(columnName)) {
2132
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2133
            }
2134
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2135
            return this;
2136
        }
2137

    
2138
        @Override
2139
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2140
            if (StringUtils.isEmpty(columnName)) {
2141
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2142
            }
2143
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2144
            return this;
2145
        }
2146

    
2147
        @Override
2148
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2149
            this.alters.add(new ColumnDescriptorBase(fad));
2150
            return this;
2151
        }
2152

    
2153
        @Override
2154
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2155
            if (isPk || isAutomatic) {
2156
                allowNulls = false;
2157
            }
2158
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2159
            return this;
2160
        }
2161

    
2162
        @Override
2163
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2164
            if (StringUtils.isEmpty(columnName)) {
2165
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2166
            }
2167
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2168
            return this;
2169
        }
2170

    
2171
        @Override
2172
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2173
            if (StringUtils.isEmpty(columnName)) {
2174
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2175
            }
2176
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2177
            return this;
2178
        }
2179

    
2180
        @Override
2181
        public AlterTableBuilder rename_column(String source, String target) {
2182
            this.renames.add(new ImmutablePair(source, target));
2183
            return this;
2184
        }
2185

    
2186
        protected String getConstrainName(String constrainType, String columnName) {
2187
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2188
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2189
            return constraint_name;
2190
        }
2191

    
2192
        @Override
2193
        public String toString() {
2194
            return this.toString(formatter());
2195
        }
2196

    
2197
        @Override
2198
        public String toString(Formatter<Value> formatter) {
2199
            if (formatter!=null && formatter.canApply(this)) {
2200
                return formatter.format(this);
2201
            }
2202
            StringBuilder builder = new StringBuilder();
2203
            boolean first = true;
2204
            for (String sql : toStrings(formatter)) {
2205
                if (StringUtils.isEmpty(sql)) {
2206
                    continue;
2207
                }
2208
                if (first) {
2209
                    first = false;
2210
                } else {
2211
                    builder.append("; ");
2212
                }
2213
                builder.append(sql);
2214
            }
2215
            return builder.toString();
2216
        }
2217

    
2218
        @Override
2219
        public List<String> toStrings() {
2220
            return this.toStrings(formatter());
2221
        }
2222

    
2223
        @Override
2224
        public List<String> toStrings(Formatter formatter) {
2225
            List<String> sqls = new ArrayList<>();
2226
            if (this.isEmpty()) {
2227
                return sqls;
2228
            }
2229
            for (String column : drops) {
2230
                StringBuilder builder = new StringBuilder();
2231
                builder.append("ALTER TABLE ");
2232
                builder.append(this.table.toString(formatter));
2233
                builder.append(" DROP COLUMN IF EXISTS ");
2234
                builder.append(as_identifier(column));
2235
                sqls.add(builder.toString());
2236
            }
2237
            for (ColumnDescriptor column : adds) {
2238
                StringBuilder builder = new StringBuilder();
2239
                builder.append("ALTER TABLE ");
2240
                builder.append(this.table.toString(formatter));
2241
                builder.append(" ADD COLUMN ");
2242
                builder.append(as_identifier(column.getName()));
2243
                builder.append(" ");
2244
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2245
                    builder.append(" SERIAL");
2246
                } else {
2247
                    builder.append(
2248
                            sqltype(
2249
                                    column.getType(),
2250
                                    column.getSize(),
2251
                                    column.getPrecision(),
2252
                                    column.getScale(),
2253
                                    column.getGeometryType(),
2254
                                    column.getGeometrySubtype()
2255
                            )
2256
                    );
2257
                }
2258
                if (column.getDefaultValue() == null) {
2259
                    if (column.allowNulls()) {
2260
                        builder.append(" DEFAULT NULL");
2261
                    }
2262
                } else {
2263
                    builder.append(" DEFAULT '");
2264
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2265
                    builder.append("'");
2266
                }
2267
                if (column.allowNulls()) {
2268
                    builder.append(" NULL");
2269
                } else {
2270
                    builder.append(" NOT NULL");
2271
                }
2272
                if (column.isPrimaryKey()) {
2273
                    builder.append(" PRIMARY KEY");
2274
                }
2275
                sqls.add(builder.toString());
2276
            }
2277
            for (ColumnDescriptor column : alters) {
2278
                StringBuilder builder = new StringBuilder();
2279
                builder.append("ALTER TABLE ");
2280
                builder.append(this.table.toString(formatter));
2281
                builder.append(" ALTER COLUMN ");
2282
                builder.append(as_identifier(column.getName()));
2283
                builder.append(" SET DATA TYPE ");
2284
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2285
                    builder.append(" SERIAL");
2286
                } else {
2287
                    builder.append(
2288
                            sqltype(
2289
                                    column.getType(),
2290
                                    column.getSize(),
2291
                                    column.getPrecision(),
2292
                                    column.getScale(),
2293
                                    column.getGeometryType(),
2294
                                    column.getGeometrySubtype()
2295
                            )
2296
                    );
2297
                }
2298
                if (column.getDefaultValue() == null) {
2299
                    if (column.allowNulls()) {
2300
                        builder.append(" DEFAULT NULL");
2301
                    } else {
2302
                        builder.append(" DROP DEFAULT");
2303
                    }
2304
                } else {
2305
                    builder.append(" DEFAULT '");
2306
                    builder.append(column.getDefaultValue().toString());
2307
                    builder.append("'");
2308
                }
2309
                sqls.add(builder.toString());
2310
            }
2311
            for (Pair<String, String> pair : renames) {
2312
                StringBuilder builder = new StringBuilder();
2313
                builder.append("ALTER TABLE ");
2314
                builder.append(this.table.toString(formatter));
2315
                builder.append(" RENAME COLUMN ");
2316
                builder.append(as_identifier(pair.getLeft()));
2317
                builder.append(" TO ");
2318
                builder.append(as_identifier(pair.getRight()));
2319
                sqls.add(builder.toString());
2320
            }
2321
            return sqls;
2322
        }
2323

    
2324
    }
2325

    
2326
    public class CreateTableBuilderBase
2327
            extends AbstractStatement
2328
            implements CreateTableBuilder {
2329

    
2330
        protected TableNameBuilder table;
2331
        protected List<ColumnDescriptor> columns;
2332

    
2333
        public CreateTableBuilderBase() {
2334
            this.columns = new ArrayList<>();
2335
        }
2336

    
2337
        @Override
2338
        public void accept(Visitor visitor, VisitorFilter filter) {
2339
            if (filter==null || filter.accept(this)) {
2340
                visitor.visit(this);
2341
            }
2342
            if (this.table != null) {
2343
                this.table.accept(visitor, filter);
2344
            }
2345
        }
2346

    
2347
        @Override
2348
        public TableNameBuilder table() {
2349
            if (table == null) {
2350
                table = createTableNameBuilder();
2351
            }
2352
            return table;
2353
        }
2354

    
2355
        @Override
2356
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2357
            this.columns.add(new ColumnDescriptorBase(fad));
2358
            return this;
2359
        }
2360

    
2361
        @Override
2362
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2363
            if (StringUtils.isEmpty(columnName)) {
2364
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2365
            }
2366
            if (isPk || isAutomatic) {
2367
                allowNulls = false;
2368
            }
2369
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2370
            return this;
2371
        }
2372

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

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

    
2391
        @Override
2392
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2393
            if (StringUtils.isEmpty(columnName)) {
2394
                return null;
2395
            }
2396
            for (ColumnDescriptor column : columns) {
2397
                if (columnName.equals(column.getName())) {
2398
                    return column;
2399
                }
2400
            }
2401
            return null;
2402
        }
2403

    
2404
        @Override
2405
        public String toString() {
2406
            return this.toString(formatter());
2407
        }
2408

    
2409
        @Override
2410
        public String toString(Formatter<Value> formatter) {
2411
            if (formatter!=null && formatter.canApply(this)) {
2412
                return formatter.format(this);
2413
            }
2414
            StringBuilder builder = new StringBuilder();
2415
            boolean first = true;
2416
            for (String sql : toStrings(formatter)) {
2417
                if (StringUtils.isEmpty(sql)) {
2418
                    continue;
2419
                }
2420
                if (first) {
2421
                    first = false;
2422
                } else {
2423
                    builder.append("; ");
2424
                }
2425
                builder.append(sql);
2426
            }
2427
            return builder.toString();
2428
        }
2429

    
2430
        @Override
2431
        public List<String> toStrings() {
2432
            return this.toStrings(formatter());
2433
        }
2434

    
2435
        @Override
2436
        public List<String> toStrings(Formatter formatter) {
2437
            List<String> sqls = new ArrayList<>();
2438
            /**
2439
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2440
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2441
             * column_constraint [ ... ] ] | table_constraint | LIKE
2442
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2443
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2444
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2445
             *
2446
             * where column_constraint is:
2447
             *
2448
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2449
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2450
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2451
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2452
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2453
             *
2454
             * and table_constraint is:
2455
             *
2456
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2457
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2458
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2459
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2460
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2461
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2462
             */
2463
            StringBuilder builder = new StringBuilder();
2464

    
2465
            builder.append("CREATE TABLE ");
2466
            builder.append(this.table.toString(formatter));
2467
            builder.append(" (");
2468
            boolean first = true;
2469
            for (ColumnDescriptor column : columns) {
2470
                if (first) {
2471
                    first = false;
2472
                } else {
2473
                    builder.append(", ");
2474
                }
2475
                builder.append(as_identifier(column.getName()));
2476
                builder.append(" ");
2477
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2478
                    builder.append("SERIAL");
2479
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2480
                    builder.append("BIGSERIAL");
2481
                } else {
2482
                    builder.append(sqltype(
2483
                            column.getType(),
2484
                            column.getSize(),
2485
                            column.getPrecision(),
2486
                            column.getScale(),
2487
                            column.getGeometryType(),
2488
                            column.getGeometrySubtype()
2489
                    )
2490
                    );
2491
                }
2492
                if (column.getDefaultValue() == null) {
2493
                    if (column.allowNulls()) {
2494
                        builder.append(" DEFAULT NULL");
2495
                    }
2496
                } else {
2497
                    builder.append(" DEFAULT '");
2498
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2499
                    builder.append("'");
2500
                }
2501
                if (column.allowNulls()) {
2502
                    builder.append(" NULL");
2503
                } else {
2504
                    builder.append(" NOT NULL");
2505
                }
2506
                if (column.isPrimaryKey()) {
2507
                    builder.append(" PRIMARY KEY");
2508
                }
2509
            }
2510
            builder.append(" )");
2511
            sqls.add(builder.toString());
2512
            return sqls;
2513
        }
2514
    }
2515

    
2516
    public class InsertColumnBuilderBase
2517
            extends AbstractStatement
2518
            implements InsertColumnBuilder {
2519

    
2520
        protected Variable name;
2521
        protected Value value;
2522

    
2523
        public InsertColumnBuilderBase() {
2524
        }
2525

    
2526
        @Override
2527
        public void accept(Visitor visitor, VisitorFilter filter) {
2528
            if (filter==null || filter.accept(this)) {
2529
                visitor.visit(this);
2530
            }
2531
            if (this.name != null) {
2532
                this.name.accept(visitor, filter);
2533
            }
2534
            if (this.value != null) {
2535
                this.value.accept(visitor, filter);
2536
            }
2537
        }
2538

    
2539
        @Override
2540
        public InsertColumnBuilder name(String name) {
2541
            this.name = expression().variable(name);
2542
            return this;
2543
        }
2544

    
2545
        @Override
2546
        public InsertColumnBuilder with_value(Value value) {
2547
            this.value = value;
2548
            return this;
2549
        }
2550

    
2551
        @Override
2552
        public String getName() {
2553
            return this.name.name();
2554
        }
2555

    
2556
        @Override
2557
        public Value getValue() {
2558
            return this.value;
2559
        }
2560

    
2561
        @Override
2562
        public String toString() {
2563
            return this.toString(formatter());
2564
        }
2565

    
2566
        @Override
2567
        public String toString(Formatter<Value> formatter) {
2568
            if (formatter!=null && formatter.canApply(this)) {
2569
                return formatter.format(this);
2570
            }
2571
            return this.value.toString(formatter);
2572
        }
2573
    }
2574

    
2575
    public class InsertBuilderBase
2576
            extends AbstractStatement
2577
            implements InsertBuilder {
2578

    
2579
        protected List<InsertColumnBuilder> columns;
2580
        protected TableNameBuilder table;
2581

    
2582
        public InsertBuilderBase() {
2583
            this.columns = new ArrayList<>();
2584
        }
2585

    
2586
        @Override
2587
        public void accept(Visitor visitor, VisitorFilter filter) {
2588
            if (filter==null || filter.accept(this)) {
2589
                visitor.visit(this);
2590
            }
2591
            if (this.table != null) {
2592
                this.table.accept(visitor, filter);
2593
            }
2594
            for (InsertColumnBuilder column : columns) {
2595
                column.accept(visitor, filter);
2596
            }
2597
        }
2598

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

    
2607
        @Override
2608
        public InsertColumnBuilder column() {
2609
            InsertColumnBuilder column = createInsertColumnBuilder();
2610
            this.columns.add(column);
2611
            return column;
2612
        }
2613

    
2614
        @Override
2615
        public String toString() {
2616
            return this.toString(formatter());
2617
        }
2618

    
2619
        @Override
2620
        public String toString(Formatter<Value> formatter) {
2621
            if (formatter!=null && formatter.canApply(this)) {
2622
                return formatter.format(this);
2623
            }
2624
            /*
2625
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2626
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2627
             * output_expression [ AS output_name ] [, ...] ]
2628
             */
2629
            StringBuilder builderColumns = new StringBuilder();
2630
            StringBuilder builderValues = new StringBuilder();
2631

    
2632
            boolean first = true;
2633
            for (InsertColumnBuilder column : columns) {
2634
                if (first) {
2635
                    first = false;
2636
                } else {
2637
                    builderColumns.append(", ");
2638
                }
2639
                builderColumns.append(as_identifier(column.getName()));
2640
            }
2641
            first = true;
2642
            for (InsertColumnBuilder column : columns) {
2643
                if (first) {
2644
                    first = false;
2645
                } else {
2646
                    builderValues.append(", ");
2647
                }
2648
                builderValues.append(column.toString(formatter));
2649
            }
2650

    
2651
            String sql = MessageFormat.format(
2652
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2653
                    this.table.toString(formatter),
2654
                    builderColumns.toString(),
2655
                    builderValues.toString()
2656
            );
2657
            return sql;
2658

    
2659
        }
2660
    }
2661

    
2662
    public class UpdateTableStatisticsBuilderBase
2663
            extends AbstractStatement
2664
            implements UpdateTableStatisticsBuilder {
2665

    
2666
        protected TableNameBuilder table;
2667

    
2668
        @Override
2669
        public void accept(Visitor visitor, VisitorFilter filter) {
2670
            if (filter==null || filter.accept(this)) {
2671
                visitor.visit(this);
2672
            }
2673
            if (this.table != null) {
2674
                this.table.accept(visitor, filter);
2675
            }
2676
        }
2677

    
2678
        @Override
2679
        public TableNameBuilder table() {
2680
            if (table == null) {
2681
                table = createTableNameBuilder();
2682
            }
2683
            return table;
2684
        }
2685

    
2686
        @Override
2687
        public String toString() {
2688
            return this.toString(formatter());
2689
        }
2690

    
2691
        @Override
2692
        public String toString(Formatter<Value> formatter) {
2693
            if (formatter!=null && formatter.canApply(this)) {
2694
                return formatter.format(this);
2695
            }
2696
            StringBuilder builder = new StringBuilder();
2697
            boolean first = true;
2698
            for (String sql : toStrings(formatter)) {
2699
                if (StringUtils.isEmpty(sql)) {
2700
                    continue;
2701
                }
2702
                if (first) {
2703
                    first = false;
2704
                } else {
2705
                    builder.append("; ");
2706
                }
2707
                builder.append(sql);
2708
            }
2709
            return builder.toString();
2710
        }
2711

    
2712
        @Override
2713
        public List<String> toStrings() {
2714
            return this.toStrings(formatter());
2715
        }
2716

    
2717
        @Override
2718
        public List<String> toStrings(Formatter formatter) {
2719
            List<String> sqls = new ArrayList<>();
2720

    
2721
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2722
                String sql = MessageFormat.format(
2723
                        STMT_UPDATE_TABLE_STATISTICS_table,
2724
                        table.toString(formatter)
2725
                );
2726
                if (!StringUtils.isEmpty(sql)) {
2727
                    sqls.add(sql);
2728
                }
2729
            }
2730
            return sqls;
2731
        }
2732
    }
2733

    
2734
    protected GeometryExpressionBuilder expressionBuilder;
2735

    
2736
    protected String defaultSchema;
2737
    protected boolean supportSchemas;
2738
    protected boolean hasSpatialFunctions;
2739
    protected GeometrySupportType geometrySupportType;
2740
    protected boolean allowAutomaticValues;
2741

    
2742
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2743

    
2744
    protected String constant_true = "(1=1)";
2745
    protected String constant_false = "(1<>1)";
2746

    
2747
    protected String type_boolean = "BOOLEAN";
2748
    protected String type_byte = "TINYINT";
2749
    protected String type_bytearray = "BYTEA";
2750
    protected String type_geometry = "TEXT";
2751
    protected String type_char = "CHARACTER(1)";
2752
    protected String type_date = "DATE";
2753
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2754
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2755
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2756
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2757
    protected String type_int = "INT";
2758
    protected String type_long = "BIGINT";
2759
    protected String type_string = "TEXT";
2760
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2761
    protected String type_time = "TIME";
2762
    protected String type_timestamp = "TIMESTAMP";
2763
    protected String type_version = "VARCHAR(30)";
2764
    protected String type_URI = "TEXT";
2765
    protected String type_URL = "TEXT";
2766
    protected String type_FILE = "TEXT";
2767
    protected String type_FOLDER = "TEXT";
2768

    
2769
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2770
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2771
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2772
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2773
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2774
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2775
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2776
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2777
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2778
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2779

    
2780
    public SQLBuilderBase() {
2781
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2782

    
2783
        this.hasSpatialFunctions = false;
2784
        this.supportSchemas = true;
2785
        this.geometrySupportType = GeometrySupportType.WKT;
2786

    
2787
        this.defaultSchema = "public";
2788
        this.allowAutomaticValues = true;
2789

    
2790
    }
2791
    
2792
    @Override
2793
    public void setProperties(Class filter, final Object... values) {
2794
        this.expressionBuilder.setProperties(filter, values);
2795
        this.accept(new Visitor() {
2796
            @Override
2797
            public void visit(Visitable v) {
2798
                for (int i = 0; i < values.length; i+=2) {
2799
                    ((Value)v).setProperty((String) values[i], values[i+1]);
2800
                }
2801
            }
2802
        }, new ClassVisitorFilter(filter) );
2803
    }
2804

    
2805
    public String quote_for_identifiers() {
2806
        return "\"";
2807
    }
2808

    
2809
    public String quote_for_strings() {
2810
        return "'";
2811
    }
2812

    
2813
    @Override
2814
    public String as_identifier(String id) {
2815
        String quote = this.quote_for_identifiers();
2816
//        No se porque no esta disponible wrapIfMissing
2817
//        return StringUtils.wrapIfMissing(id,quote);
2818
        if (id.startsWith(quote)) {
2819
            return id;
2820
        }
2821
        return quote + id + quote;
2822

    
2823
    }
2824

    
2825
    @Override
2826
    public String as_string(String s) {
2827
        String quote = this.quote_for_strings();
2828
//        No se porque no esta disponible wrapIfMissing
2829
//        return StringUtils.wrapIfMissing(id,quote);
2830
        if (s.startsWith(quote)) {
2831
            return s;
2832
        }
2833
        return quote + s + quote;
2834

    
2835
    }
2836

    
2837
    @Override
2838
    public String as_string(byte[] data) {
2839
        return this.expressionBuilder.bytearray_0x(data);
2840
//        return this.expressionBuilder.bytearray_hex(data);
2841
//        return this.expressionBuilder.bytearray_x(data);
2842
    }
2843
    
2844
    @Override
2845
    public String as_string(boolean value) {
2846
        return value? "TRUE" : "FALSE";
2847
    }
2848

    
2849
    @Override
2850
    public String as_string(Number value) {
2851
        return Objects.toString(value);
2852
    }
2853
    
2854
    @Override
2855
    public String as_string(Object value) {
2856
        if( value == null ) {
2857
            return "NULL";
2858
        }
2859
        if( value instanceof CharSequence ) {
2860
            return as_string(value.toString());
2861
        }
2862
        if( value instanceof Number ) {
2863
            return as_string((Number)value);
2864
        }
2865
        if( value instanceof Boolean ) {
2866
            return as_string((boolean)value);
2867
        }
2868
        if( value instanceof byte[] ) {
2869
            return as_string((byte[])value);
2870
        }
2871
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2872
    }
2873
    
2874
    @Override
2875
    public GeometryExpressionBuilder expression() {
2876
        return this.expressionBuilder;
2877
    }
2878

    
2879
    @Override
2880
    public boolean has_spatial_functions() {
2881
        return this.hasSpatialFunctions;
2882
    }
2883

    
2884
    @Override
2885
    public GeometrySupportType geometry_support_type() {
2886
        return this.geometrySupportType;
2887
    }
2888

    
2889
    protected GeometryExpressionBuilder createExpressionBuilder() {
2890
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2891
    }
2892

    
2893
    @Override
2894
    public Object srs_id(IProjection projection) {
2895
        String abrev = projection.getAbrev();
2896
        return abrev.split(":")[1].trim();
2897
    }
2898

    
2899
    @Override
2900
    public String default_schema() {
2901
        return this.defaultSchema;
2902
    }
2903

    
2904
    @Override
2905
    public boolean support_schemas() {
2906
        return this.supportSchemas;
2907
    }
2908

    
2909
    @Override
2910
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2911
        switch (type) {
2912
            case DataTypes.BOOLEAN:
2913
                return type_boolean;
2914
            case DataTypes.CHAR:
2915
                return type_char;
2916

    
2917

    
2918
            case DataTypes.BYTE:
2919
                return type_byte;
2920
            case DataTypes.INT:
2921
                return type_int;
2922
            case DataTypes.LONG:
2923
                return type_long;
2924

    
2925
            case DataTypes.FLOAT:
2926
                return type_float;
2927
            case DataTypes.DOUBLE:
2928
                return type_double;
2929
            case DataTypes.DECIMAL:
2930
                if (precision < 1) {
2931
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2932
                }
2933
                if (scale < 1) {
2934
                  return MessageFormat.format(type_decimal_p, precision);
2935
                }
2936
                return MessageFormat.format(type_decimal_ps, precision, scale);
2937

    
2938
                
2939
            case DataTypes.STRING:
2940
                if (size < 0) {
2941
                    return type_string;
2942
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
2943
                    return MessageFormat.format(type_string_p, size);
2944
                }
2945
                return type_string;
2946

    
2947
                
2948
            case DataTypes.DATE:
2949
                return type_date;
2950
            case DataTypes.TIME:
2951
                return type_time;
2952
            case DataTypes.TIMESTAMP:
2953
                return type_timestamp;
2954

    
2955
            case DataTypes.BYTEARRAY:
2956
                return type_bytearray;
2957

    
2958
            case DataTypes.GEOMETRY:
2959
                return type_geometry;
2960

    
2961
            case DataTypes.VERSION:
2962
                return type_version;
2963
            case DataTypes.URI:
2964
                return type_URI;
2965
            case DataTypes.URL:
2966
                return type_URL;
2967
            case DataTypes.FILE:
2968
                return type_FILE;
2969
            case DataTypes.FOLDER:
2970
                return type_FOLDER;
2971
            default:
2972
                return null;
2973
        }
2974
    }
2975

    
2976
    @Override
2977
    public Object sqlgeometrytype(int type, int subtype) {
2978
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2979
        // identificadores numericos para el tipo y otros strings.
2980
        // Por defecto vamos a devolver strings.
2981
        if (sqlgeometrytypes == null) {
2982
            sqlgeometrytypes = new HashMap<>();
2983
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
2984
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
2985
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
2986
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2987

    
2988
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2989
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2990
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2991
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2992

    
2993
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
2994
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2995
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2996
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2997

    
2998
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2999
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3000
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3001
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3002

    
3003
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3004
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3005
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3006
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3007

    
3008
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3009
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3010
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3011
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3012

    
3013
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3014
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3015
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3016
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3017

    
3018
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3019
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3020
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3021
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3022

    
3023
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3024
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3025
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3026
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3027
        }
3028
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3029
    }
3030

    
3031
    @Override
3032
    public Object sqlgeometrydimension(int type, int subtype) {
3033
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3034
        // identificadores numericos para las dimensiones y otros strings.
3035
        // Por defecto vamos a devolver enteros.
3036
        switch (subtype) {
3037
            case Geometry.SUBTYPES.GEOM3D:
3038
                return 3;
3039
            case Geometry.SUBTYPES.GEOM2DM:
3040
                return 3;
3041
            case Geometry.SUBTYPES.GEOM3DM:
3042
                return 4;
3043
            case Geometry.SUBTYPES.GEOM2D:
3044
            default:
3045
                return 2;
3046
        }
3047
    }
3048

    
3049
    @Override
3050
    public TableNameBuilder createTableNameBuilder() {
3051
        return new TableNameBuilderBase();
3052
    }
3053

    
3054
    protected SelectColumnBuilder createSelectColumnBuilder() {
3055
        return new SelectColumnBuilderBase();
3056
    }
3057

    
3058
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3059
        return new UpdateColumnBuilderBase();
3060
    }
3061

    
3062
    protected InsertColumnBuilder createInsertColumnBuilder() {
3063
        return new InsertColumnBuilderBase();
3064
    }
3065

    
3066
    protected OrderByBuilder createOrderByBuilder() {
3067
        return new OrderByBuilderBase();
3068
    }
3069

    
3070
    protected FromBuilder createFromBuilder() {
3071
        return new FromBuilderBase();
3072
    }
3073

    
3074
    protected SelectBuilder createSelectBuilder() {
3075
        return new SelectBuilderBase();
3076
    }
3077

    
3078
    protected UpdateBuilder createUpdateBuilder() {
3079
        return new UpdateBuilderBase();
3080
    }
3081

    
3082
    protected DeleteBuilder createDeleteBuilder() {
3083
        return new DeleteBuilderBase();
3084
    }
3085

    
3086
    protected GrantBuilder createGrantBuilder() {
3087
        return new GrantBuilderBase();
3088
    }
3089

    
3090
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3091
        return new GrantRoleBuilderBase(table, role);
3092
    }
3093

    
3094
    protected DropTableBuilder createDropTableBuilder() {
3095
        return new DropTableBuilderBase();
3096
    }
3097

    
3098
    protected CreateTableBuilder createCreateTableBuilder() {
3099
        return new CreateTableBuilderBase();
3100
    }
3101

    
3102
    protected AlterTableBuilder createAlterTableBuilder() {
3103
        return new AlterTableBuilderBase();
3104
    }
3105

    
3106
    protected InsertBuilder createInsertBuilder() {
3107
        return new InsertBuilderBase();
3108
    }
3109

    
3110
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3111
        return new UpdateTableStatisticsBuilderBase();
3112
    }
3113

    
3114
    protected CreateIndexBuilder createCreateIndexBuilder() {
3115
        return new CreateIndexBuilderBase();
3116
    }
3117

    
3118
    protected DropIndexBuilder createDropIndexBuilder() {
3119
        return new DropIndexBuilderBase();
3120
    }
3121

    
3122
    @Override
3123
    public SelectBuilder select() {
3124
        if (this.select == null) {
3125
            this.select = this.createSelectBuilder();
3126
        }
3127
        return this.select;
3128
    }
3129

    
3130
    @Override
3131
    public UpdateBuilder update() {
3132
        if (this.update == null) {
3133
            this.update = this.createUpdateBuilder();
3134
        }
3135
        return this.update;
3136
    }
3137

    
3138
    @Override
3139
    public UpdateTableStatisticsBuilder update_table_statistics() {
3140
        if (this.update_table_statistics == null) {
3141
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3142
        }
3143
        return this.update_table_statistics;
3144
    }
3145

    
3146
    @Override
3147
    public DropTableBuilder drop_table() {
3148
        if (this.drop_table == null) {
3149
            this.drop_table = this.createDropTableBuilder();
3150
        }
3151
        return this.drop_table;
3152
    }
3153

    
3154
    @Override
3155
    public CreateIndexBuilder create_index() {
3156
        if (this.create_index == null) {
3157
            this.create_index = this.createCreateIndexBuilder();
3158
        }
3159
        return this.create_index;
3160
    }
3161

    
3162
    @Override
3163
    public DropIndexBuilder drop_index() {
3164
        if (this.drop_index == null) {
3165
            this.drop_index = this.createDropIndexBuilder();
3166
        }
3167
        return this.drop_index;
3168
    }
3169

    
3170
    @Override
3171
    public DeleteBuilder delete() {
3172
        if (this.delete == null) {
3173
            this.delete = this.createDeleteBuilder();
3174
        }
3175
        return this.delete;
3176
    }
3177

    
3178
    @Override
3179
    public InsertBuilder insert() {
3180
        if (this.insert == null) {
3181
            this.insert = this.createInsertBuilder();
3182
        }
3183
        return this.insert;
3184
    }
3185

    
3186
    @Override
3187
    public TableNameBuilder table_name() {
3188
        if (this.table_name == null) {
3189
            this.table_name = this.createTableNameBuilder();
3190
        }
3191
        return this.table_name;
3192
    }
3193

    
3194
    
3195
    @Override
3196
    public AlterTableBuilder alter_table() {
3197
        if (this.alter_table == null) {
3198
            this.alter_table = this.createAlterTableBuilder();
3199
        }
3200
        return this.alter_table;
3201
    }
3202

    
3203
    @Override
3204
    public CreateTableBuilder create_table() {
3205
        if (this.create_table == null) {
3206
            this.create_table = this.createCreateTableBuilder();
3207
        }
3208
        return this.create_table;
3209
    }
3210

    
3211
    @Override
3212
    public GrantBuilder grant() {
3213
        if (this.grant == null) {
3214
            this.grant = this.createGrantBuilder();
3215
        }
3216
        return this.grant;
3217
    }
3218
    
3219
    @Override
3220
    public Column column(String name) {
3221
        ColumnBase col = new ColumnBase(null, name);
3222
        return col;
3223
    }
3224

    
3225
    @Override
3226
    public Column column(TableNameBuilder table, String name) {
3227
        ColumnBase col = new ColumnBase(table, name);
3228
        return col;
3229
    }
3230
    
3231
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3232
        return new JoinBase(type, table, expression);
3233
    }
3234

    
3235
    public void accept(Visitor visitor, VisitorFilter filter) {
3236
        if (this.select != null) {
3237
            this.select.accept(visitor, filter);
3238
        }
3239
        if (this.update != null) {
3240
            this.update.accept(visitor, filter);
3241
        }
3242
        if (this.insert != null) {
3243
            this.insert.accept(visitor, filter);
3244
        }
3245
        if (this.delete != null) {
3246
            this.delete.accept(visitor, filter);
3247
        }
3248
        if (this.alter_table != null) {
3249
            this.alter_table.accept(visitor, filter);
3250
        }
3251
        if (this.create_table != null) {
3252
            this.create_table.accept(visitor, filter);
3253
        }
3254
        if (this.drop_table != null) {
3255
            this.drop_table.accept(visitor, filter);
3256
        }
3257
        if (this.table_name != null) {
3258
            this.table_name.accept(visitor, filter);
3259
        }
3260
    }
3261

    
3262
        @Override
3263
    public Formatter formatter() {
3264
        return expression().formatter();
3265
    }
3266

    
3267
    @Override
3268
    public String toString() {
3269
        return this.toString(formatter());
3270
    }
3271

    
3272
    @Override
3273
    public String toString(Formatter formatter) {
3274
        if (this.select != null) {
3275
            return this.select.toString(formatter);
3276
        }
3277
        if (this.update != null) {
3278
            return this.update.toString(formatter);
3279
        }
3280
        if (this.insert != null) {
3281
            return this.insert.toString(formatter);
3282
        }
3283
        if (this.delete != null) {
3284
            return this.delete.toString(formatter);
3285
        }
3286
        if (this.alter_table != null) {
3287
            return this.alter_table.toString(formatter);
3288
        }
3289
        if (this.create_table != null) {
3290
            return this.create_table.toString(formatter);
3291
        }
3292
        if (this.drop_table != null) {
3293
            return this.drop_table.toString(formatter);
3294
        }
3295
        if (this.update_table_statistics != null) {
3296
            return this.update_table_statistics.toString(formatter);
3297
        }
3298
        if (this.create_index != null) {
3299
            return this.create_index.toString(formatter);
3300
        }
3301
        if (this.drop_index != null) {
3302
            return this.drop_index.toString(formatter);
3303
        }
3304
        if (this.table_name != null) {
3305
            return this.table_name.toString(formatter);
3306
        }
3307
        return "";
3308
    }
3309

    
3310
    @Override
3311
    public CountBuilder count() {
3312
        return new CountBuilderBase();
3313
    }
3314

    
3315
    @Override
3316
    public List<Parameter> parameters() {
3317
        final List<Parameter> params = new ArrayList<>();
3318
        this.accept(new Visitor() {
3319
            @Override
3320
            public void visit(Visitable value) {
3321
                params.add((Parameter) value);
3322
            }
3323
        }, new ClassVisitorFilter(Parameter.class));
3324
        return params;
3325
    }
3326

    
3327
    @Override
3328
    public List<Variable> variables() {
3329
        final List<Variable> vars = new ArrayList<>();
3330
        this.accept(new Visitor() {
3331
            @Override
3332
            public void visit(Visitable value) {
3333
                if (!vars.contains((Variable) value)) {
3334
                    vars.add((Variable) value);
3335
                }
3336
            }
3337
        }, new ClassVisitorFilter(Variable.class));
3338
        return vars;
3339
    }
3340

    
3341
    @Override
3342
    public List<String> parameters_names() {
3343
        List<String> params = new ArrayList<>();
3344
        for (Parameter param : parameters()) {
3345
            String s;
3346
            switch (param.type()) {
3347
                case PARAMETER_TYPE_CONSTANT:
3348
                    Object theValue = param.value();
3349
                    if (theValue == null) {
3350
                        s = "null";
3351
                    } else if (theValue instanceof String) {
3352
                        s = "'" + (String) theValue + "'";
3353
                    } else {
3354
                        s = theValue.toString();
3355
                    }
3356
                    break;
3357
                case PARAMETER_TYPE_VARIABLE:
3358
                default:
3359
                    s = "\"" + param.name() + "\"";
3360
            }
3361
            params.add(s);
3362
        }
3363
        return params;
3364
    }
3365

    
3366
    @Override
3367
    public List<String> variables_names() {
3368
        List<String> vars = new ArrayList<>();
3369
        for (Variable var : this.variables()) {
3370
            vars.add(var.name());
3371
        }
3372
        Collections.sort(vars);
3373
        return vars;
3374
    }    
3375
}