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

History | View | Annotate | Download (114 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
        protected SQLBuilder sqlbuilder;
747
        
748
        public SelectColumnBuilderBase(SQLBuilder sqlbuilder) {
749
            this.sqlbuilder = sqlbuilder;
750
        }
751
        
752
        @Override
753
        public SelectColumnBuilderBase clone() throws CloneNotSupportedException {
754
            SelectColumnBuilderBase other = (SelectColumnBuilderBase) super.clone();
755
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
756
            other.name = (Variable) org.gvsig.tools.lang.Cloneable.cloneQuietly(name);
757
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
758
            return other;
759
        }
760

    
761
        @Override
762
        public void accept(Visitor visitor, VisitorFilter filter) {
763
            if (filter==null || filter.accept(this)) {
764
                visitor.visit(this);
765
            }
766
            if (this.name != null) {
767
                this.name.accept(visitor, filter);
768
            }
769
            if (this.value != null) {
770
                this.value.accept(visitor, filter);
771
            }
772
        }
773

    
774
        @Override
775
        public void replace(Value target, Value replacement) {
776
            if (this.name!=null ) {
777
                if( this.name == target) {
778
                    this.name = (Variable) replacement;
779
                }
780
            }
781
            if( this.value!=null ) {
782
                if (this.value == target) {
783
                    this.value = replacement;
784
                } else {
785
                    this.value.replace(target, replacement);
786
                }
787
            }
788
        }
789

    
790
        @Override
791
        public SelectColumnBuilder name(String name) {
792
            return this.name(null, name);
793
        }
794

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

    
809
        @Override
810
        public SelectColumnBuilder all() {
811
            this.name = null;
812
            this.value = expression().custom("*");
813
            this.asGeometry = false;
814
            return this;
815
        }
816

    
817
        @Override
818
        public SelectColumnBuilder as_geometry() {
819
            this.asGeometry = true;
820
            return this;
821
        }
822

    
823
        @Override
824
        public SelectColumnBuilder value(Value value) {
825
            this.value = value;
826
            this.name = null;
827
            return this;
828
        }
829

    
830
        @Override
831
        public SelectColumnBuilder as(String alias) {
832
            this.alias = alias;
833
            return this;
834
        }
835

    
836
        @Override
837
        public String getName() {
838
            if (this.name==null) {
839
                return null;
840
            }
841
            return this.name.name();
842
        }
843

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

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

    
854
        @Override
855
        public String toString() {
856
            return this.toString(formatter());
857
        }
858

    
859
        @Override
860
        public String toString(Formatter<Value> formatter) {
861
            if (formatter!=null && formatter.canApply(this)) {
862
                return formatter.format(this);
863
            }
864
            StringBuilder builder = new StringBuilder();
865
            if (this.asGeometry) {
866
                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
867
            } else {
868
                if (this.name != null) {
869
                    if( this.table==null ) {
870
                        builder.append(this.name.toString(formatter));
871
                    } else {
872
                        builder.append(this.table.toString(formatter));
873
                        builder.append(".");
874
                        builder.append(this.name.toString(formatter));
875
                    }
876
                } else {
877
                    builder.append(this.value.toString(formatter));
878
                }
879
            }
880
            if (this.alias != null) {
881
                builder.append(" AS ");
882
                builder.append(as_identifier(this.alias));
883
            }
884
            return builder.toString();
885
        }
886
        
887
        @Override
888
        public boolean isGeometry() {
889
            return this.asGeometry;
890
        }
891
        
892
        @Override
893
        public TableNameBuilder getTable() {
894
            return this.table;
895
        }
896
        
897
        @Override
898
        public boolean isAggregateFunction() {
899
            if( this.value == null ) {
900
                return false;
901
            }
902
            if( !(this.value instanceof ExpressionBuilder.Function) ) {
903
                return false;
904
            }
905
            String funcname = ((ExpressionBuilder.Function)this.value).name();
906
            return this.sqlbuilder.isAggregateFunction(funcname);
907
        }
908
    }
909

    
910
    public class OrderByBuilderBase
911
            extends AbstractStatementPart
912
            implements OrderByBuilder {
913

    
914
        protected Value value;
915
        protected String custom;
916
        protected boolean ascending;
917

    
918
        public OrderByBuilderBase() {
919
            this.ascending = true;
920
        }
921
        
922
        @Override
923
        public OrderByBuilderBase clone() throws CloneNotSupportedException {
924
            OrderByBuilderBase other = (OrderByBuilderBase) super.clone();
925
            other.value = (Value) org.gvsig.tools.lang.Cloneable.cloneQuietly(value);
926
            return other;
927
        }
928
        
929
        @Override
930
        public void accept(Visitor visitor, VisitorFilter filter) {
931
            if (filter==null || filter.accept(this)) {
932
                visitor.visit(this);
933
            }
934
            if (this.value!=null) {
935
                this.value.accept(visitor, filter);
936
            }
937
        }
938

    
939
        @Override
940
        public OrderByBuilder column(String name) {
941
            this.value = expression().variable(name);
942
            return this;
943
        }
944
        
945
        @Override
946
        public boolean isColumn(String name) {
947
            if(this.value instanceof ExpressionBuilder.Variable){
948
                return StringUtils.equalsIgnoreCase(((ExpressionBuilder.Variable)this.value).name(), name);
949
            }
950
            return false;
951
        }
952
        
953
        @Override
954
        public boolean isColumn(Value value) {
955
            if(value instanceof ExpressionBuilder.Variable){
956
                return isColumn(((ExpressionBuilder.Variable)value).name());
957
            }
958
            return this.value == value;
959
        }
960
        
961
        @Override
962
        public OrderByBuilder value(Value expression) {
963
            this.value = expression;
964
            return this;
965
        }
966
        
967
        @Override
968
        public OrderByBuilder custom(String order) {
969
            this.custom = order;
970
            return this;
971
        }
972

    
973
        @Override
974
        public OrderByBuilder ascending() {
975
            this.ascending = true;
976
            return this;
977
        }
978

    
979
        @Override
980
        public OrderByBuilder ascending(boolean asc) {
981
            this.ascending = asc;
982
            return this;
983
        }
984

    
985
        @Override
986
        public OrderByBuilder descending() {
987
            this.ascending = false;
988
            return this;
989
        }
990

    
991
        @Override
992
        public String toString() {
993
            return this.toString(formatter());
994
        }
995

    
996
        @Override
997
        public String toString(Formatter<Value> formatter) {
998
            if (formatter!=null && formatter.canApply(this)) {
999
                return formatter.format(this);
1000
            }
1001
            if (!StringUtils.isEmpty(this.custom)) {
1002
                return this.custom;
1003
            }
1004
            if (this.ascending) {
1005
                return this.value.toString(formatter) + " ASC NULLS LAST";
1006
            }
1007
            return this.value.toString(formatter) + " DESC NULLS FIRST";
1008
        }
1009
    }
1010

    
1011
    public class SelectBuilderBase
1012
            extends AbstractStatement
1013
            implements SelectBuilder {
1014

    
1015
        protected FromBuilder from;
1016
        protected GeometryExpressionBuilder where;
1017
        protected long limit = -1;
1018
        protected long offset = -1;
1019
        protected List<SelectColumnBuilder> columns;
1020
        protected List<OrderByBuilder> order_by;
1021
        protected boolean distinct;
1022
        protected List<Value> groupColumn;
1023
        protected boolean check_order_and_offset = true;
1024

    
1025
        public SelectBuilderBase() {
1026
            this.columns = new ArrayList<>();
1027
            this.distinct = false;
1028
        }
1029
        @Override
1030
        public List<Value> getGroups() {
1031
            return this.groupColumn;
1032
        }
1033
        
1034
        @Override
1035
        public List<SelectColumnBuilder> getColumns() {
1036
            return Collections.unmodifiableList(this.columns);
1037
    }
1038
        
1039
        @Override
1040
        public void remove_column(String columnName) {
1041
            SelectColumnBuilder found = null;
1042
            for (SelectColumnBuilder column : columns) {
1043
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1044
                    found = column;
1045
                    break;
1046
                }
1047
                    
1048
            }
1049
            if(found!=null) {
1050
                columns.remove(found);
1051
            }
1052
        }
1053

    
1054
        @Override
1055
        public SelectBuilder group_by(Value... columns) {
1056
            if( this.groupColumn==null ) {
1057
                this.groupColumn = new ArrayList<>();
1058
            }
1059
            for (Value column : columns) {
1060
                this.groupColumn.add(column);
1061
            }
1062
            return this;
1063
        }
1064

    
1065
        @Override
1066
        public void accept(Visitor visitor, VisitorFilter filter) {
1067
            if (filter==null || filter.accept(this)) {
1068
                visitor.visit(this);
1069
            }
1070
            for (SelectColumnBuilder column : columns) {
1071
                column.accept(visitor, filter);
1072
            }
1073
            if (this.has_from()) {
1074
                this.from.accept(visitor, filter);
1075
            }
1076
            if (this.has_where()) {
1077
                this.where.accept(visitor, filter);
1078
            }
1079
            if (this.has_order_by()) {
1080
                for (OrderByBuilder order : order_by) {
1081
                    order.accept(visitor, filter);
1082
                }
1083
            }
1084
            if (this.has_group_by()) {
1085
                for (Value group : groupColumn) {
1086
                    group.accept(visitor, filter);
1087
                }
1088
            }
1089
        }
1090

    
1091
        @Override
1092
        public void replace(Value target, Value replacement) {
1093
            if( this.columns!=null ) {
1094
                for (int i = 0; i < columns.size(); i++) {
1095
                    SelectColumnBuilder column = columns.get(i);
1096
                    if( column == target ) {
1097
                        columns.set(i, (SelectColumnBuilder) replacement);
1098
                    } else {
1099
                        column.replace(target, replacement);
1100
                    }
1101
                }
1102
            }
1103
            if (this.has_from()) {
1104
                if( this.from == target ) {
1105
                    this.from = (FromBuilder) replacement;
1106
                } else {
1107
                    this.from.replace(target, replacement);
1108
                }
1109
            }
1110
            if (this.has_where()) {
1111
                if( this.where == target ) {
1112
                    this.where = (GeometryExpressionBuilder) replacement;
1113
                } else if( this.where.value() == target ) {
1114
                    this.where.value(replacement);
1115
                } else {
1116
                    this.where.value().replace(target, replacement);
1117
                }
1118
            }
1119
            if (this.has_order_by()) {
1120
                for (int i = 0; i < order_by.size(); i++) {
1121
                    OrderByBuilder order = order_by.get(i);
1122
                    if( order == target ) {
1123
                        order_by.set(i, (OrderByBuilder) replacement);
1124
                    } else {
1125
                        order.replace(target, replacement);
1126
                    }
1127
                }
1128
            }
1129
            if (this.has_group_by()) {
1130
                for (int i = 0; i < groupColumn.size(); i++) {
1131
                    Value group = groupColumn.get(i);
1132
                    if( group == target ) {
1133
                        groupColumn.set(i, replacement);
1134
                    } else {
1135
                        group.replace(target, replacement);
1136
                    }
1137
                }
1138
            }
1139
        }
1140

    
1141
        @Override
1142
        public SelectBuilder distinct() {
1143
            this.distinct = true;
1144
            return this;
1145
        }
1146

    
1147
        @Override
1148
        public SelectColumnBuilder column() {
1149
            SelectColumnBuilder builder = createSelectColumnBuilder();
1150
            this.columns.add(builder);
1151
            return builder;
1152
        }
1153

    
1154
        @Override
1155
        public SelectBuilder remove_all_columns() {
1156
            this.columns = new ArrayList<>();
1157
            return this;
1158
        }
1159
        
1160
        @Override
1161
        public boolean has_column(String name) {
1162
            for (SelectColumnBuilder column : columns) {
1163
                if (StringUtils.equals(name, column.getName())) {
1164
                    return true;
1165
                }
1166
                if (StringUtils.equals(name, column.getAlias())) {
1167
                    return true;
1168
                }
1169
            }
1170
            return false;
1171
        }
1172

    
1173
        @Override
1174
        public FromBuilder from() {
1175
            if (this.from == null) {
1176
                this.from = createFromBuilder();
1177
            }
1178
            return this.from;
1179
        }
1180

    
1181
        @Override
1182
        public boolean has_from() {
1183
            return this.from != null;
1184
        }
1185

    
1186
        @Override
1187
        public GeometryExpressionBuilder where() {
1188
            if (this.where == null) {
1189
                this.where = createExpressionBuilder();
1190
            }
1191
            return this.where;
1192
        }
1193

    
1194
        @Override
1195
        public boolean has_where() {
1196
            if (this.where == null) {
1197
                return false;
1198
            }
1199
            return this.where.value() != null;
1200
        }
1201

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

    
1208
        @Override
1209
        public SelectBuilder limit(Long limit) {
1210
            if (limit == null) {
1211
                this.limit = -1;
1212
            } else {
1213
                this.limit = limit;
1214
            }
1215
            return this;
1216
        }
1217

    
1218
        @Override
1219
        public boolean has_limit() {
1220
            return this.limit >= 0;
1221
        }
1222

    
1223
        @Override
1224
        public SelectBuilder offset(long offset) {
1225
            this.offset = offset;
1226
            return this;
1227
        }
1228

    
1229
        @Override
1230
        public boolean has_offset() {
1231
            return this.offset > 0;
1232
        }
1233

    
1234
        @Override
1235
        public OrderByBuilder order_by() {
1236
            if (this.order_by == null) {
1237
                this.order_by = new ArrayList<>();
1238
            }
1239
            OrderByBuilder order = createOrderByBuilder();
1240
            this.order_by.add(order);
1241
            return order;
1242
        }
1243
        
1244
        @Override
1245
        public OrderByBuilder getOrderBy(Value column) {
1246
            if(this.order_by == null){
1247
                return null;
1248
            }
1249
            for (OrderByBuilder orderByBuilder : this.order_by) {
1250
                if(orderByBuilder.isColumn(column)){
1251
                    return orderByBuilder;
1252
                }
1253
            }
1254
            return null;
1255
        }
1256
        
1257
        @Override
1258
        public OrderByBuilder getOrderBy(String column) {
1259
            if(this.order_by == null){
1260
                return null;
1261
            }
1262
            for (OrderByBuilder orderByBuilder : this.order_by) {
1263
                if(orderByBuilder.isColumn(column)){
1264
                    return orderByBuilder;
1265
                }
1266
            }
1267
            return null;
1268
        }
1269

    
1270
        @Override
1271
        public boolean has_order_by() {
1272
            if (this.order_by == null) {
1273
                return false;
1274
            }
1275
            return !this.order_by.isEmpty();
1276
        }
1277
        
1278
        @Override
1279
        public boolean has_group_by() {
1280
            if (this.groupColumn == null) {
1281
                return false;
1282
            }
1283
            return !this.groupColumn.isEmpty();
1284
        }
1285
        
1286
        @Override
1287
        public boolean has_aggregate_functions() {
1288
            if (this.columns == null || this.columns.isEmpty() ) {
1289
                return false;
1290
            }
1291
            for (SelectColumnBuilder column : this.columns) {
1292
                if( column.isAggregateFunction() ) {
1293
                    return true;
1294
                }
1295
            }
1296
            return false;
1297
        }
1298
        
1299
        @Override
1300
        public void disable_check_order_and_offset() {
1301
          this.check_order_and_offset = false;
1302
        }
1303
        
1304
        protected boolean isValid(StringBuilder message) {
1305
            if (message == null) {
1306
                message = new StringBuilder();
1307
            }
1308
            if( this.check_order_and_offset ) {
1309
              if (this.has_offset() && !this.has_order_by()) {
1310
                  // Algunos gestores de BBDD requieren que se especifique un
1311
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1312
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1313
                  // siempre.
1314
                  message.append("Can't use OFFSET without an ORDER BY.");
1315
                  return false;
1316
              }
1317
            }
1318
            return true;
1319
        }
1320

    
1321
        @Override
1322
        public String toString() {
1323
            return this.toString(formatter());
1324
        }
1325

    
1326
        @Override
1327
        public String toString(Formatter<Value> formatter) {
1328
            if (formatter!=null && formatter.canApply(this)) {
1329
                return formatter.format(this);
1330
            }
1331
            StringBuilder builder = new StringBuilder();
1332
            if (!this.isValid(builder)) {
1333
                throw new IllegalStateException(builder.toString());
1334
            }
1335
            builder.append("SELECT ");
1336
            if (this.distinct) {
1337
                builder.append("DISTINCT ");
1338
            }
1339
            boolean first = true;
1340
            for (SelectColumnBuilder column : columns) {
1341
                if (first) {
1342
                    first = false;
1343
                } else {
1344
                    builder.append(", ");
1345
                }
1346
                builder.append(column.toString(formatter));
1347
            }
1348

    
1349
            if (this.has_from()) {
1350
                builder.append(" FROM ");
1351
                builder.append(this.from.toString(formatter));
1352
            }
1353
            if (this.has_where()) {
1354
                builder.append(" WHERE ");
1355
                builder.append(this.where.toString(formatter));
1356
            }
1357
            if( this.has_group_by() ) {
1358
                builder.append(" GROUP BY ");
1359
                builder.append(this.groupColumn.get(0).toString(formatter));
1360
                for (int i = 1; i < groupColumn.size(); i++) {
1361
                    builder.append(", ");
1362
                    builder.append(this.groupColumn.get(i).toString(formatter));
1363
                }
1364
            }
1365
            if (this.has_order_by()) {
1366
                builder.append(" ORDER BY ");
1367
                first = true;
1368
                for (OrderByBuilder item : this.order_by) {
1369
                    if (first) {
1370
                        first = false;
1371
                    } else {
1372
                        builder.append(", ");
1373
                    }
1374
                    builder.append(item.toString(formatter));
1375
                }
1376
            }
1377

    
1378
            if (this.has_limit()) {
1379
                builder.append(" LIMIT ");
1380
                builder.append(this.limit);
1381
            }
1382
            if (this.has_offset()) {
1383
                builder.append(" OFFSET ");
1384
                builder.append(this.offset);
1385
            }
1386
            return builder.toString();
1387

    
1388
        }
1389
    }
1390

    
1391
    public class DropTableBuilderBase
1392
            extends AbstractStatement
1393
            implements DropTableBuilder {
1394

    
1395
        protected TableNameBuilder table;
1396

    
1397
        @Override
1398
        public TableNameBuilder table() {
1399
            if (table == null) {
1400
                table = createTableNameBuilder();
1401
            }
1402
            return table;
1403
        }
1404

    
1405
        @Override
1406
        public void accept(Visitor visitor, VisitorFilter filter) {
1407
            if (filter==null || filter.accept(this)) {
1408
                visitor.visit(this);
1409
            }
1410
            this.table.accept(visitor, filter);
1411
        }
1412

    
1413
        @Override
1414
        public String toString() {
1415
            return this.toString(formatter());
1416
        }
1417

    
1418
        @Override
1419
        public String toString(Formatter<Value> formatter) {
1420
            if (formatter!=null && formatter.canApply(this)) {
1421
                return formatter.format(this);
1422
            }
1423
            StringBuilder builder = new StringBuilder();
1424
            boolean first = true;
1425
            for (String sql : toStrings(formatter)) {
1426
                if (StringUtils.isEmpty(sql)) {
1427
                    continue;
1428
                }
1429
                if (first) {
1430
                    first = false;
1431
                } else {
1432
                    builder.append("; ");
1433
                }
1434
                builder.append(sql);
1435
            }
1436
            return builder.toString();
1437
        }
1438

    
1439
        @Override
1440
        public List<String> toStrings() {
1441
            return this.toStrings(formatter());
1442
        }
1443

    
1444
        @Override
1445
        public List<String> toStrings(Formatter formatter) {
1446
            List<String> sqls = new ArrayList<>();
1447

    
1448
            sqls.add(
1449
                    MessageFormat.format(
1450
                            STMT_DROP_TABLE_table,
1451
                            this.table.toString(formatter)
1452
                    )
1453
            );
1454
            String sql;
1455
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1456
                if (this.table.has_schema()) {
1457
                    sql = MessageFormat.format(
1458
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1459
                            as_string(this.table.getSchema()),
1460
                            as_string(this.table.getName())
1461
                    );
1462
                } else {
1463
                    sql = MessageFormat.format(
1464
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1465
                            as_identifier(this.table.getName())
1466
                    );
1467
                }
1468
                if (!StringUtils.isEmpty(sql)) {
1469
                    sqls.add(sql);
1470
                }
1471
            }
1472
            return sqls;
1473
        }
1474
    }
1475

    
1476
    public class GrantRoleBuilderBase
1477
            extends AbstractStatementPart
1478
            implements GrantRoleBuilder {
1479

    
1480
        protected TableNameBuilder table;
1481
        protected String role;
1482
        protected Set<Privilege> privileges;
1483

    
1484
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1485
            this.table = table;
1486
            this.role = role;
1487
            this.privileges = new HashSet<>();
1488
        }
1489
        
1490
        @Override
1491
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1492
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1493
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1494
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1495
            
1496
            return other;
1497
        }
1498

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

    
1505
        @Override
1506
        public GrantRoleBuilder select() {
1507
            privileges.add(Privilege.SELECT);
1508
            return this;
1509
        }
1510

    
1511
        @Override
1512
        public GrantRoleBuilder update() {
1513
            privileges.add(Privilege.UPDATE);
1514
            return this;
1515
        }
1516

    
1517
        @Override
1518
        public GrantRoleBuilder insert() {
1519
            privileges.add(Privilege.INSERT);
1520
            return this;
1521
        }
1522

    
1523
        @Override
1524
        public GrantRoleBuilder delete() {
1525
            privileges.add(Privilege.DELETE);
1526
            return this;
1527
        }
1528

    
1529
        @Override
1530
        public GrantRoleBuilder truncate() {
1531
            privileges.add(Privilege.TRUNCATE);
1532
            return this;
1533
        }
1534

    
1535
        @Override
1536
        public GrantRoleBuilder reference() {
1537
            privileges.add(Privilege.REFERENCE);
1538
            return this;
1539
        }
1540

    
1541
        @Override
1542
        public GrantRoleBuilder trigger() {
1543
            privileges.add(Privilege.TRIGGER);
1544
            return this;
1545
        }
1546

    
1547
        @Override
1548
        public GrantRoleBuilder all() {
1549
            privileges.add(Privilege.ALL);
1550
            return this;
1551
        }
1552

    
1553
        protected String getPrivilegeName(Privilege privilege) {
1554
            switch (privilege) {
1555
                case DELETE:
1556
                    return "DELETE";
1557
                case INSERT:
1558
                    return "INSERT";
1559
                case REFERENCE:
1560
                    return "REFERENCE";
1561
                case SELECT:
1562
                    return "SELECT";
1563
                case TRIGGER:
1564
                    return "TRIGGER";
1565
                case TRUNCATE:
1566
                    return "TRUNCATE";
1567
                case UPDATE:
1568
                    return "UPDATE";
1569
                case ALL:
1570
                default:
1571
                    return "ALL";
1572
            }
1573
        }
1574

    
1575
        @Override
1576
        public String toString() {
1577
            return this.toString(formatter());
1578
        }
1579

    
1580
        @Override
1581
        public String toString(Formatter<Value> formatter) {
1582
            if (formatter!=null && formatter.canApply(this)) {
1583
                return formatter.format(this);
1584
            }
1585
            StringBuilder builder = new StringBuilder();
1586
            boolean first = true;
1587
            for (Privilege privilege : privileges) {
1588
                if (first) {
1589
                    first = false;
1590
                } else {
1591
                    builder.append(", ");
1592
                }
1593
                builder.append(this.getPrivilegeName(privilege));
1594
            }
1595
            String sql = MessageFormat.format(
1596
                    STMT_GRANT_privileges_ON_table_TO_role,
1597
                    builder.toString(),
1598
                    table.toString(formatter),
1599
                    role
1600
            );
1601
            return sql;
1602
        }
1603
    }
1604

    
1605
    public class GrantBuilderBase
1606
            extends AbstractStatement
1607
            implements GrantBuilder {
1608

    
1609
        protected TableNameBuilder table;
1610
        protected Map<String, GrantRoleBuilder> roles;
1611

    
1612
        public GrantBuilderBase() {
1613
            this.roles = new HashMap<>();
1614
        }
1615

    
1616
        @Override
1617
        public TableNameBuilder table() {
1618
            if (table == null) {
1619
                table = createTableNameBuilder();
1620
            }
1621
            return table;
1622
        }
1623

    
1624
        @Override
1625
        public void accept(Visitor visitor, VisitorFilter filter) {
1626
            if (filter==null || filter.accept(this)) {
1627
                visitor.visit(this);
1628
            }
1629
            if (this.table != null) {
1630
                this.table.accept(visitor, filter);
1631
            }
1632
        }
1633

    
1634
        @Override
1635
        public GrantRoleBuilder role(String role) {
1636
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1637
            if (roleBuilder == null) {
1638
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1639
                this.roles.put(role, roleBuilder);
1640
            }
1641
            return roleBuilder;
1642
        }
1643

    
1644
        @Override
1645
        public String toString() {
1646
            return this.toString(formatter());
1647
        }
1648

    
1649
        @Override
1650
        public String toString(Formatter<Value> formatter) {
1651
            if (formatter!=null && formatter.canApply(this)) {
1652
                return formatter.format(this);
1653
            }
1654
            StringBuilder builder = new StringBuilder();
1655
            boolean first = true;
1656
            for (String sql : toStrings(formatter)) {
1657
                if (StringUtils.isEmpty(sql)) {
1658
                    continue;
1659
                }
1660
                if (first) {
1661
                    first = false;
1662
                } else {
1663
                    builder.append("; ");
1664
                }
1665
                builder.append(sql);
1666
            }
1667
            return builder.toString();
1668
        }
1669

    
1670
        @Override
1671
        public List<String> toStrings() {
1672
            return this.toStrings(formatter());
1673
        }
1674

    
1675
        @Override
1676
        public List<String> toStrings(Formatter formatter) {
1677
            List<String> sqls = new ArrayList<>();
1678
            for (GrantRoleBuilder role : roles.values()) {
1679
                sqls.add(role.toString(formatter));
1680
            }
1681
            return sqls;
1682
        }
1683
    }
1684

    
1685
    public class UpdateColumnBuilderBase
1686
            extends InsertColumnBuilderBase
1687
            implements UpdateColumnBuilder {
1688

    
1689
        public UpdateColumnBuilderBase() {
1690
            super();
1691
        }
1692

    
1693
        @Override
1694
        public UpdateColumnBuilder name(String name) {
1695
            return (UpdateColumnBuilder) super.name(name);
1696
        }
1697

    
1698
        @Override
1699
        public UpdateColumnBuilder with_value(Value value) {
1700
            return (UpdateColumnBuilder) super.with_value(value);
1701
        }
1702

    
1703
    }
1704

    
1705
    public class UpdateBuilderBase
1706
            extends AbstractStatement
1707
            implements UpdateBuilder {
1708

    
1709
        protected GeometryExpressionBuilder where;
1710
        protected List<UpdateColumnBuilder> columns;
1711
        protected TableNameBuilder table;
1712

    
1713
        public UpdateBuilderBase() {
1714
            this.columns = new ArrayList<>();
1715
        }
1716

    
1717
        @Override
1718
        public void accept(Visitor visitor, VisitorFilter filter) {
1719
            if (filter==null || filter.accept(this)) {
1720
                visitor.visit(this);
1721
            }
1722
            if (this.table != null) {
1723
                this.table.accept(visitor, filter);
1724
            }
1725
            for (UpdateColumnBuilder column : columns) {
1726
                column.accept(visitor, filter);
1727
            }
1728
            if (this.has_where()) {
1729
                this.where.accept(visitor, filter);
1730
            }
1731
        }
1732

    
1733
        @Override
1734
        public GeometryExpressionBuilder where() {
1735
            if (this.where == null) {
1736
                this.where = createExpressionBuilder();
1737
            }
1738
            return this.where;
1739
        }
1740

    
1741
        @Override
1742
        public TableNameBuilder table() {
1743
            if (table == null) {
1744
                table = createTableNameBuilder();
1745
            }
1746
            return table;
1747
        }
1748

    
1749
        @Override
1750
        public UpdateColumnBuilder column() {
1751
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1752
            this.columns.add(column);
1753
            return column;
1754
        }
1755

    
1756
        @Override
1757
        public boolean has_where() {
1758
            return this.where != null;
1759
        }
1760

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

    
1766
        @Override
1767
        public String toString(Formatter<Value> formatter) {
1768
            if (formatter!=null && formatter.canApply(this)) {
1769
                return formatter.format(this);
1770
            }
1771
            /*
1772
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1773
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1774
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1775
             * output_expression [ AS output_name ] [, ...] ]
1776
             */
1777
            StringBuilder columnsAndValues = new StringBuilder();
1778

    
1779
            boolean first = true;
1780
            for (UpdateColumnBuilder column : columns) {
1781
                if (first) {
1782
                    first = false;
1783
                } else {
1784
                    columnsAndValues.append(", ");
1785
                }
1786
                columnsAndValues.append(as_identifier(column.getName()));
1787
                columnsAndValues.append(" = ");
1788
                columnsAndValues.append(column.getValue().toString(formatter));
1789
            }
1790

    
1791
            String sql;
1792
            if (this.has_where()) {
1793
                sql = MessageFormat.format(
1794
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1795
                        this.table.toString(formatter),
1796
                        columnsAndValues.toString(),
1797
                        this.where.toString(formatter)
1798
                );
1799
            } else {
1800
                sql = MessageFormat.format(
1801
                        STMT_UPDATE_table_SET_columnsAndValues,
1802
                        this.table.toString(formatter),
1803
                        columnsAndValues.toString()
1804
                );
1805
            }
1806
            return sql;
1807
        }
1808
    }
1809

    
1810
    public class DeleteBuilderBase
1811
            extends AbstractStatement
1812
            implements DeleteBuilder {
1813

    
1814
        protected GeometryExpressionBuilder where;
1815
        protected TableNameBuilder table;
1816

    
1817
        public DeleteBuilderBase() {
1818
        }
1819

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

    
1833
        @Override
1834
        public GeometryExpressionBuilder where() {
1835
            if (this.where == null) {
1836
                this.where = createExpressionBuilder();
1837
            }
1838
            return this.where;
1839
        }
1840

    
1841
        @Override
1842
        public TableNameBuilder table() {
1843
            if (table == null) {
1844
                table = createTableNameBuilder();
1845
            }
1846
            return table;
1847
        }
1848

    
1849
        @Override
1850
        public boolean has_where() {
1851
            return this.where != null;
1852
        }
1853

    
1854
        @Override
1855
        public String toString() {
1856
            return this.toString(formatter());
1857
        }
1858

    
1859
        @Override
1860
        public String toString(Formatter<Value> formatter) {
1861
            if (formatter!=null && formatter.canApply(this)) {
1862
                return formatter.format(this);
1863
            }
1864
            /*
1865
             * DELETE FROM table_name
1866
             * WHERE some_column=some_value; 
1867
             */
1868
            String sql;
1869
            if (this.has_where()) {
1870
                sql = MessageFormat.format(
1871
                        STMT_DELETE_FROM_table_WHERE_expresion,
1872
                        this.table.toString(formatter),
1873
                        this.where.toString(formatter)
1874
                );
1875
            } else {
1876
                sql = MessageFormat.format(
1877
                        STMT_DELETE_FROM_table,
1878
                        this.table.toString(formatter)
1879
                );
1880
            }
1881
            return sql;
1882
        }
1883
    }
1884

    
1885
    public class CreateIndexBuilderBase
1886
            extends AbstractStatement
1887
            implements CreateIndexBuilder {
1888

    
1889
        protected boolean ifNotExist = false;
1890
        protected boolean isUnique = false;
1891
        protected String indexName;
1892
        protected boolean isSpatial = false;
1893
        protected TableNameBuilder table;
1894
        protected final List<String> columns;
1895

    
1896
        public CreateIndexBuilderBase() {
1897
            this.columns = new ArrayList<>();
1898
        }
1899

    
1900
        @Override
1901
        public CreateIndexBuilder unique() {
1902
            this.isUnique = true;
1903
            return this;
1904
        }
1905

    
1906
        @Override
1907
        public CreateIndexBuilder if_not_exist() {
1908
            this.ifNotExist = true;
1909
            return this;
1910
        }
1911

    
1912
        @Override
1913
        public CreateIndexBuilder name(String name) {
1914
            this.indexName = name;
1915
            return this;
1916
        }
1917

    
1918
        @Override
1919
        public CreateIndexBuilder name(String tableName, String columnName) {
1920
            this.indexName = tableName + "_IDX_" + columnName;
1921
            return this;
1922
        }
1923

    
1924
        @Override
1925
        public CreateIndexBuilder spatial() {
1926
            this.isSpatial = true;
1927
            return this;
1928
        }
1929

    
1930
        @Override
1931
        public CreateIndexBuilder column(String name) {
1932
            this.columns.add(name);
1933
            return this;
1934
        }
1935

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

    
1944
        @Override
1945
        public void accept(Visitor visitor, VisitorFilter filter) {
1946
            if (filter==null || filter.accept(this)) {
1947
                visitor.visit(this);
1948
            }
1949
            if (this.table != null) {
1950
                this.table.accept(visitor, filter);
1951
            }
1952
        }
1953

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

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

    
1980
        @Override
1981
        public List<String> toStrings() {
1982
            return this.toStrings(formatter());
1983
        }
1984

    
1985
        @Override
1986
        public List<String> toStrings(Formatter formatter) {
1987
            StringBuilder builder = new StringBuilder();
1988
            builder.append("CREATE ");
1989
            if (this.isUnique) {
1990
                builder.append("UNIQUE ");
1991
            }
1992
            builder.append("INDEX ");
1993
            if (this.ifNotExist) {
1994
                builder.append("IF NOT EXISTS ");
1995
            }
1996
            builder.append(as_identifier(this.indexName));
1997
            builder.append(" ON ");
1998
            builder.append(this.table.toString(formatter));
1999
            if (this.isSpatial) {
2000
                builder.append(" USING GIST ");
2001
            }
2002
            builder.append(" ( ");
2003
            boolean is_first_column = true;
2004
            for (String column : this.columns) {
2005
                if (is_first_column) {
2006
                    is_first_column = false;
2007
                } else {
2008
                    builder.append(", ");
2009
                }
2010
                builder.append(column);
2011
            }
2012
            builder.append(" )");
2013

    
2014
            List<String> sqls = new ArrayList<>();
2015
            sqls.add(builder.toString());
2016
            return sqls;
2017
        }
2018

    
2019
    }
2020

    
2021
    public class DropIndexBuilderBase
2022
            extends AbstractStatement
2023
            implements DropIndexBuilder {
2024

    
2025
        protected boolean ifNotExist = false;
2026
        protected String indexName;
2027

    
2028
        public DropIndexBuilderBase() {
2029
        }
2030

    
2031
        @Override
2032
        public DropIndexBuilder if_not_exist() {
2033
            this.ifNotExist = true;
2034
            return this;
2035
        }
2036

    
2037
        @Override
2038
        public DropIndexBuilder name(String name) {
2039
            this.indexName = name;
2040
            return this;
2041
        }
2042

    
2043
        @Override
2044
        public DropIndexBuilder name(String tableName, String columnName) {
2045
            this.indexName = tableName + "_IDX_" + columnName;
2046
            return this;
2047
        }
2048

    
2049
        @Override
2050
        public String toString() {
2051
            return this.toString(formatter());
2052
        }
2053

    
2054
        @Override
2055
        public String toString(Formatter<Value> formatter) {
2056
            if (formatter!=null && formatter.canApply(this)) {
2057
                return formatter.format(this);
2058
            }
2059
            StringBuilder builder = new StringBuilder();
2060
            boolean first = true;
2061
            for (String sql : toStrings(formatter)) {
2062
                if (StringUtils.isEmpty(sql)) {
2063
                    continue;
2064
                }
2065
                if (first) {
2066
                    first = false;
2067
                } else {
2068
                    builder.append("; ");
2069
                }
2070
                builder.append(sql);
2071
            }
2072
            return builder.toString();
2073
        }
2074

    
2075
        @Override
2076
        public List<String> toStrings() {
2077
            return this.toStrings(formatter());
2078
        }
2079

    
2080
        @Override
2081
        public List<String> toStrings(Formatter formatter) {
2082
            StringBuilder builder = new StringBuilder();
2083
            builder.append("DROP INDEX ");
2084
            if (this.ifNotExist) {
2085
                builder.append("IF NOT EXISTS ");
2086
            }
2087
            builder.append(as_identifier(this.indexName));
2088
            List<String> sqls = new ArrayList<>();
2089
            sqls.add(builder.toString());
2090
            return sqls;
2091
        }
2092

    
2093
    }
2094

    
2095
    public class AlterTableBuilderBase
2096
            extends AbstractStatement
2097
            implements AlterTableBuilder {
2098

    
2099
        protected TableNameBuilder table;
2100
        protected List<String> drops;
2101
        protected List<ColumnDescriptor> adds;
2102
        protected List<ColumnDescriptor> alters;
2103
        protected List<Pair<String, String>> renames;
2104
        protected String drop_primary_key_column;
2105

    
2106
        public AlterTableBuilderBase() {
2107
            this.drops = new ArrayList<>();
2108
            this.adds = new ArrayList<>();
2109
            this.alters = new ArrayList<>();
2110
            this.renames = new ArrayList<>();
2111
        }
2112

    
2113
        @Override
2114
        public boolean isEmpty() {
2115
            return this.drops.isEmpty()
2116
                    && this.adds.isEmpty()
2117
                    && this.alters.isEmpty()
2118
                    && this.renames.isEmpty();
2119
        }
2120

    
2121
        @Override
2122
        public void accept(Visitor visitor, VisitorFilter filter) {
2123
            if (filter==null || filter.accept(this)) {
2124
                visitor.visit(this);
2125
            }
2126
            if (this.table != null) {
2127
                this.table.accept(visitor, filter);
2128
            }
2129
        }
2130

    
2131
        @Override
2132
        public TableNameBuilder table() {
2133
            if (table == null) {
2134
                table = createTableNameBuilder();
2135
            }
2136
            return table;
2137
        }
2138

    
2139
        @Override
2140
        public AlterTableBuilder drop_column(String columnName) {
2141
            this.drops.add(columnName);
2142
            return this;
2143
        }
2144

    
2145
        @Override
2146
        public AlterTableBuilder drop_primary_key(String columnName) {
2147
            this.drop_primary_key_column = columnName;
2148
            return this;
2149
        }
2150

    
2151
        @Override
2152
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2153
            this.adds.add(new ColumnDescriptorBase(fad));
2154
            return this;
2155
        }
2156

    
2157
        @Override
2158
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2159
            if (isPk || isAutomatic) {
2160
                allowNulls = false;
2161
            }
2162
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2163
            return this;
2164
        }
2165

    
2166
        @Override
2167
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2168
            if (StringUtils.isEmpty(columnName)) {
2169
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2170
            }
2171
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2172
            return this;
2173
        }
2174

    
2175
        @Override
2176
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2177
            if (StringUtils.isEmpty(columnName)) {
2178
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2179
            }
2180
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2181
            return this;
2182
        }
2183

    
2184
        @Override
2185
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2186
            this.alters.add(new ColumnDescriptorBase(fad));
2187
            return this;
2188
        }
2189

    
2190
        @Override
2191
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2192
            if (isPk || isAutomatic) {
2193
                allowNulls = false;
2194
            }
2195
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2196
            return this;
2197
        }
2198

    
2199
        @Override
2200
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2201
            if (StringUtils.isEmpty(columnName)) {
2202
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2203
            }
2204
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2205
            return this;
2206
        }
2207

    
2208
        @Override
2209
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2210
            if (StringUtils.isEmpty(columnName)) {
2211
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2212
            }
2213
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2214
            return this;
2215
        }
2216

    
2217
        @Override
2218
        public AlterTableBuilder rename_column(String source, String target) {
2219
            this.renames.add(new ImmutablePair(source, target));
2220
            return this;
2221
        }
2222

    
2223
        protected String getConstrainName(String constrainType, String columnName) {
2224
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2225
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2226
            return constraint_name;
2227
        }
2228

    
2229
        @Override
2230
        public String toString() {
2231
            return this.toString(formatter());
2232
        }
2233

    
2234
        @Override
2235
        public String toString(Formatter<Value> formatter) {
2236
            if (formatter!=null && formatter.canApply(this)) {
2237
                return formatter.format(this);
2238
            }
2239
            StringBuilder builder = new StringBuilder();
2240
            boolean first = true;
2241
            for (String sql : toStrings(formatter)) {
2242
                if (StringUtils.isEmpty(sql)) {
2243
                    continue;
2244
                }
2245
                if (first) {
2246
                    first = false;
2247
                } else {
2248
                    builder.append("; ");
2249
                }
2250
                builder.append(sql);
2251
            }
2252
            return builder.toString();
2253
        }
2254

    
2255
        @Override
2256
        public List<String> toStrings() {
2257
            return this.toStrings(formatter());
2258
        }
2259

    
2260
        @Override
2261
        public List<String> toStrings(Formatter formatter) {
2262
            List<String> sqls = new ArrayList<>();
2263
            if (this.isEmpty()) {
2264
                return sqls;
2265
            }
2266
            for (String column : drops) {
2267
                StringBuilder builder = new StringBuilder();
2268
                builder.append("ALTER TABLE ");
2269
                builder.append(this.table.toString(formatter));
2270
                builder.append(" DROP COLUMN IF EXISTS ");
2271
                builder.append(as_identifier(column));
2272
                sqls.add(builder.toString());
2273
            }
2274
            for (ColumnDescriptor column : adds) {
2275
                StringBuilder builder = new StringBuilder();
2276
                builder.append("ALTER TABLE ");
2277
                builder.append(this.table.toString(formatter));
2278
                builder.append(" ADD COLUMN ");
2279
                builder.append(as_identifier(column.getName()));
2280
                builder.append(" ");
2281
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2282
                    builder.append(" SERIAL");
2283
                } else {
2284
                    builder.append(
2285
                            sqltype(
2286
                                    column.getType(),
2287
                                    column.getSize(),
2288
                                    column.getPrecision(),
2289
                                    column.getScale(),
2290
                                    column.getGeometryType(),
2291
                                    column.getGeometrySubtype()
2292
                            )
2293
                    );
2294
                }
2295
                if (column.getDefaultValue() == null) {
2296
                    if (column.allowNulls()) {
2297
                        builder.append(" DEFAULT NULL");
2298
                    }
2299
                } else {
2300
                    builder.append(" DEFAULT '");
2301
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2302
                    builder.append("'");
2303
                }
2304
                if (column.allowNulls()) {
2305
                    builder.append(" NULL");
2306
                } else {
2307
                    builder.append(" NOT NULL");
2308
                }
2309
                if (column.isPrimaryKey()) {
2310
                    builder.append(" PRIMARY KEY");
2311
                }
2312
                sqls.add(builder.toString());
2313
            }
2314
            for (ColumnDescriptor column : alters) {
2315
                StringBuilder builder = new StringBuilder();
2316
                builder.append("ALTER TABLE ");
2317
                builder.append(this.table.toString(formatter));
2318
                builder.append(" ALTER COLUMN ");
2319
                builder.append(as_identifier(column.getName()));
2320
                builder.append(" SET DATA TYPE ");
2321
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2322
                    builder.append(" SERIAL");
2323
                } else {
2324
                    builder.append(
2325
                            sqltype(
2326
                                    column.getType(),
2327
                                    column.getSize(),
2328
                                    column.getPrecision(),
2329
                                    column.getScale(),
2330
                                    column.getGeometryType(),
2331
                                    column.getGeometrySubtype()
2332
                            )
2333
                    );
2334
                }
2335
                if (column.getDefaultValue() == null) {
2336
                    if (column.allowNulls()) {
2337
                        builder.append(" DEFAULT NULL");
2338
                    } else {
2339
                        builder.append(" DROP DEFAULT");
2340
                    }
2341
                } else {
2342
                    builder.append(" DEFAULT '");
2343
                    builder.append(column.getDefaultValue().toString());
2344
                    builder.append("'");
2345
                }
2346
                sqls.add(builder.toString());
2347
            }
2348
            for (Pair<String, String> pair : renames) {
2349
                StringBuilder builder = new StringBuilder();
2350
                builder.append("ALTER TABLE ");
2351
                builder.append(this.table.toString(formatter));
2352
                builder.append(" RENAME COLUMN ");
2353
                builder.append(as_identifier(pair.getLeft()));
2354
                builder.append(" TO ");
2355
                builder.append(as_identifier(pair.getRight()));
2356
                sqls.add(builder.toString());
2357
            }
2358
            return sqls;
2359
        }
2360

    
2361
    }
2362

    
2363
    public class CreateTableBuilderBase
2364
            extends AbstractStatement
2365
            implements CreateTableBuilder {
2366

    
2367
        protected TableNameBuilder table;
2368
        protected List<ColumnDescriptor> columns;
2369

    
2370
        public CreateTableBuilderBase() {
2371
            this.columns = new ArrayList<>();
2372
        }
2373

    
2374
        @Override
2375
        public void accept(Visitor visitor, VisitorFilter filter) {
2376
            if (filter==null || filter.accept(this)) {
2377
                visitor.visit(this);
2378
            }
2379
            if (this.table != null) {
2380
                this.table.accept(visitor, filter);
2381
            }
2382
        }
2383

    
2384
        @Override
2385
        public TableNameBuilder table() {
2386
            if (table == null) {
2387
                table = createTableNameBuilder();
2388
            }
2389
            return table;
2390
        }
2391

    
2392
        @Override
2393
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2394
            this.columns.add(new ColumnDescriptorBase(fad));
2395
            return this;
2396
        }
2397

    
2398
        @Override
2399
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2400
            if (StringUtils.isEmpty(columnName)) {
2401
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2402
            }
2403
            if (isPk || isAutomatic) {
2404
                allowNulls = false;
2405
            }
2406
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2407
            return this;
2408
        }
2409

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

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

    
2428
        @Override
2429
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2430
            if (StringUtils.isEmpty(columnName)) {
2431
                return null;
2432
            }
2433
            for (ColumnDescriptor column : columns) {
2434
                if (columnName.equals(column.getName())) {
2435
                    return column;
2436
                }
2437
            }
2438
            return null;
2439
        }
2440

    
2441
        @Override
2442
        public String toString() {
2443
            return this.toString(formatter());
2444
        }
2445

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

    
2467
        @Override
2468
        public List<String> toStrings() {
2469
            return this.toStrings(formatter());
2470
        }
2471

    
2472
        @Override
2473
        public List<String> toStrings(Formatter formatter) {
2474
            List<String> sqls = new ArrayList<>();
2475
            /**
2476
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2477
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2478
             * column_constraint [ ... ] ] | table_constraint | LIKE
2479
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2480
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2481
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2482
             *
2483
             * where column_constraint is:
2484
             *
2485
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2486
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2487
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2488
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2489
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2490
             *
2491
             * and table_constraint is:
2492
             *
2493
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2494
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2495
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2496
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2497
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2498
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2499
             */
2500
            StringBuilder builder = new StringBuilder();
2501

    
2502
            builder.append("CREATE TABLE ");
2503
            builder.append(this.table.toString(formatter));
2504
            builder.append(" (");
2505
            boolean first = true;
2506
            for (ColumnDescriptor column : columns) {
2507
                if (first) {
2508
                    first = false;
2509
                } else {
2510
                    builder.append(", ");
2511
                }
2512
                builder.append(as_identifier(column.getName()));
2513
                builder.append(" ");
2514
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2515
                    builder.append("SERIAL");
2516
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2517
                    builder.append("BIGSERIAL");
2518
                } else {
2519
                    builder.append(sqltype(
2520
                            column.getType(),
2521
                            column.getSize(),
2522
                            column.getPrecision(),
2523
                            column.getScale(),
2524
                            column.getGeometryType(),
2525
                            column.getGeometrySubtype()
2526
                    )
2527
                    );
2528
                }
2529
                if (column.getDefaultValue() == null) {
2530
                    if (column.allowNulls()) {
2531
                        builder.append(" DEFAULT NULL");
2532
                    }
2533
                } else {
2534
                    builder.append(" DEFAULT '");
2535
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2536
                    builder.append("'");
2537
                }
2538
                if (column.allowNulls()) {
2539
                    builder.append(" NULL");
2540
                } else {
2541
                    builder.append(" NOT NULL");
2542
                }
2543
                if (column.isPrimaryKey()) {
2544
                    builder.append(" PRIMARY KEY");
2545
                }
2546
            }
2547
            builder.append(" )");
2548
            sqls.add(builder.toString());
2549
            return sqls;
2550
        }
2551
    }
2552

    
2553
    public class InsertColumnBuilderBase
2554
            extends AbstractStatement
2555
            implements InsertColumnBuilder {
2556

    
2557
        protected Variable name;
2558
        protected Value value;
2559

    
2560
        public InsertColumnBuilderBase() {
2561
        }
2562

    
2563
        @Override
2564
        public void accept(Visitor visitor, VisitorFilter filter) {
2565
            if (filter==null || filter.accept(this)) {
2566
                visitor.visit(this);
2567
            }
2568
            if (this.name != null) {
2569
                this.name.accept(visitor, filter);
2570
            }
2571
            if (this.value != null) {
2572
                this.value.accept(visitor, filter);
2573
            }
2574
        }
2575

    
2576
        @Override
2577
        public InsertColumnBuilder name(String name) {
2578
            this.name = expression().variable(name);
2579
            return this;
2580
        }
2581

    
2582
        @Override
2583
        public InsertColumnBuilder with_value(Value value) {
2584
            this.value = value;
2585
            return this;
2586
        }
2587

    
2588
        @Override
2589
        public String getName() {
2590
            return this.name.name();
2591
        }
2592

    
2593
        @Override
2594
        public Value getValue() {
2595
            return this.value;
2596
        }
2597

    
2598
        @Override
2599
        public String toString() {
2600
            return this.toString(formatter());
2601
        }
2602

    
2603
        @Override
2604
        public String toString(Formatter<Value> formatter) {
2605
            if (formatter!=null && formatter.canApply(this)) {
2606
                return formatter.format(this);
2607
            }
2608
            return this.value.toString(formatter);
2609
        }
2610
    }
2611

    
2612
    public class InsertBuilderBase
2613
            extends AbstractStatement
2614
            implements InsertBuilder {
2615

    
2616
        protected List<InsertColumnBuilder> columns;
2617
        protected TableNameBuilder table;
2618

    
2619
        public InsertBuilderBase() {
2620
            this.columns = new ArrayList<>();
2621
        }
2622

    
2623
        @Override
2624
        public void accept(Visitor visitor, VisitorFilter filter) {
2625
            if (filter==null || filter.accept(this)) {
2626
                visitor.visit(this);
2627
            }
2628
            if (this.table != null) {
2629
                this.table.accept(visitor, filter);
2630
            }
2631
            for (InsertColumnBuilder column : columns) {
2632
                column.accept(visitor, filter);
2633
            }
2634
        }
2635

    
2636
        @Override
2637
        public TableNameBuilder table() {
2638
            if (table == null) {
2639
                table = createTableNameBuilder();
2640
            }
2641
            return table;
2642
        }
2643

    
2644
        @Override
2645
        public InsertColumnBuilder column() {
2646
            InsertColumnBuilder column = createInsertColumnBuilder();
2647
            this.columns.add(column);
2648
            return column;
2649
        }
2650

    
2651
        @Override
2652
        public String toString() {
2653
            return this.toString(formatter());
2654
        }
2655

    
2656
        @Override
2657
        public String toString(Formatter<Value> formatter) {
2658
            if (formatter!=null && formatter.canApply(this)) {
2659
                return formatter.format(this);
2660
            }
2661
            /*
2662
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2663
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2664
             * output_expression [ AS output_name ] [, ...] ]
2665
             */
2666
            StringBuilder builderColumns = new StringBuilder();
2667
            StringBuilder builderValues = new StringBuilder();
2668

    
2669
            boolean first = true;
2670
            for (InsertColumnBuilder column : columns) {
2671
                if (first) {
2672
                    first = false;
2673
                } else {
2674
                    builderColumns.append(", ");
2675
                }
2676
                builderColumns.append(as_identifier(column.getName()));
2677
            }
2678
            first = true;
2679
            for (InsertColumnBuilder column : columns) {
2680
                if (first) {
2681
                    first = false;
2682
                } else {
2683
                    builderValues.append(", ");
2684
                }
2685
                builderValues.append(column.toString(formatter));
2686
            }
2687

    
2688
            String sql = MessageFormat.format(
2689
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2690
                    this.table.toString(formatter),
2691
                    builderColumns.toString(),
2692
                    builderValues.toString()
2693
            );
2694
            return sql;
2695

    
2696
        }
2697
    }
2698

    
2699
    public class UpdateTableStatisticsBuilderBase
2700
            extends AbstractStatement
2701
            implements UpdateTableStatisticsBuilder {
2702

    
2703
        protected TableNameBuilder table;
2704

    
2705
        @Override
2706
        public void accept(Visitor visitor, VisitorFilter filter) {
2707
            if (filter==null || filter.accept(this)) {
2708
                visitor.visit(this);
2709
            }
2710
            if (this.table != null) {
2711
                this.table.accept(visitor, filter);
2712
            }
2713
        }
2714

    
2715
        @Override
2716
        public TableNameBuilder table() {
2717
            if (table == null) {
2718
                table = createTableNameBuilder();
2719
            }
2720
            return table;
2721
        }
2722

    
2723
        @Override
2724
        public String toString() {
2725
            return this.toString(formatter());
2726
        }
2727

    
2728
        @Override
2729
        public String toString(Formatter<Value> formatter) {
2730
            if (formatter!=null && formatter.canApply(this)) {
2731
                return formatter.format(this);
2732
            }
2733
            StringBuilder builder = new StringBuilder();
2734
            boolean first = true;
2735
            for (String sql : toStrings(formatter)) {
2736
                if (StringUtils.isEmpty(sql)) {
2737
                    continue;
2738
                }
2739
                if (first) {
2740
                    first = false;
2741
                } else {
2742
                    builder.append("; ");
2743
                }
2744
                builder.append(sql);
2745
            }
2746
            return builder.toString();
2747
        }
2748

    
2749
        @Override
2750
        public List<String> toStrings() {
2751
            return this.toStrings(formatter());
2752
        }
2753

    
2754
        @Override
2755
        public List<String> toStrings(Formatter formatter) {
2756
            List<String> sqls = new ArrayList<>();
2757

    
2758
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2759
                String sql = MessageFormat.format(
2760
                        STMT_UPDATE_TABLE_STATISTICS_table,
2761
                        table.toString(formatter)
2762
                );
2763
                if (!StringUtils.isEmpty(sql)) {
2764
                    sqls.add(sql);
2765
                }
2766
            }
2767
            return sqls;
2768
        }
2769
    }
2770

    
2771
    protected GeometryExpressionBuilder expressionBuilder;
2772

    
2773
    protected String defaultSchema;
2774
    protected boolean supportSchemas;
2775
    protected boolean hasSpatialFunctions;
2776
    protected GeometrySupportType geometrySupportType;
2777
    protected boolean allowAutomaticValues;
2778

    
2779
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2780

    
2781
    protected String constant_true = "(1=1)";
2782
    protected String constant_false = "(1<>1)";
2783

    
2784
    protected String type_boolean = "BOOLEAN";
2785
    protected String type_byte = "TINYINT";
2786
    protected String type_bytearray = "BYTEA";
2787
    protected String type_geometry = "TEXT";
2788
    protected String type_char = "CHARACTER(1)";
2789
    protected String type_date = "DATE";
2790
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2791
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2792
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2793
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2794
    protected String type_int = "INT";
2795
    protected String type_long = "BIGINT";
2796
    protected String type_string = "TEXT";
2797
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2798
    protected String type_time = "TIME";
2799
    protected String type_timestamp = "TIMESTAMP";
2800
    protected String type_version = "VARCHAR(30)";
2801
    protected String type_URI = "TEXT";
2802
    protected String type_URL = "TEXT";
2803
    protected String type_FILE = "TEXT";
2804
    protected String type_FOLDER = "TEXT";
2805

    
2806
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2807
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2808
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2809
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2810
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2811
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2812
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2813
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2814
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2815
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2816

    
2817
    public SQLBuilderBase() {
2818
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2819

    
2820
        this.hasSpatialFunctions = false;
2821
        this.supportSchemas = true;
2822
        this.geometrySupportType = GeometrySupportType.WKT;
2823

    
2824
        this.defaultSchema = "public";
2825
        this.allowAutomaticValues = true;
2826

    
2827
    }
2828
    
2829
    @Override
2830
    public void setProperties(Class filter, final Object... values) {
2831
        this.expressionBuilder.setProperties(filter, values);
2832
        this.accept((Visitable v) -> {
2833
            for (int i = 0; i < values.length; i+=2) {
2834
                ((Value)v).setProperty((String) values[i], values[i+1]);
2835
            }
2836
        }, new ClassVisitorFilter(filter) );
2837
    }
2838

    
2839
    public String quote_for_identifiers() {
2840
        return "\"";
2841
    }
2842

    
2843
    public String quote_for_strings() {
2844
        return "'";
2845
    }
2846

    
2847
    @Override
2848
    public String as_identifier(String id) {
2849
        String quote = this.quote_for_identifiers();
2850
//        No se porque no esta disponible wrapIfMissing
2851
//        return StringUtils.wrapIfMissing(id,quote);
2852
        if (id.startsWith(quote)) {
2853
            return id;
2854
        }
2855
        return quote + id + quote;
2856

    
2857
    }
2858

    
2859
    @Override
2860
    public String as_string(String s) {
2861
        String quote = this.quote_for_strings();
2862
//        No se porque no esta disponible wrapIfMissing
2863
//        return StringUtils.wrapIfMissing(id,quote);
2864
        if (s.startsWith(quote)) {
2865
            return s;
2866
        }
2867
        return quote + s + quote;
2868

    
2869
    }
2870

    
2871
    @Override
2872
    public String as_string(byte[] data) {
2873
        return this.expressionBuilder.bytearray_0x(data);
2874
//        return this.expressionBuilder.bytearray_hex(data);
2875
//        return this.expressionBuilder.bytearray_x(data);
2876
    }
2877
    
2878
    @Override
2879
    public String as_string(boolean value) {
2880
        return value? "TRUE" : "FALSE";
2881
    }
2882

    
2883
    @Override
2884
    public String as_string(Number value) {
2885
        return Objects.toString(value);
2886
    }
2887
    
2888
    @Override
2889
    public String as_string(Object value) {
2890
        if( value == null ) {
2891
            return "NULL";
2892
        }
2893
        if( value instanceof CharSequence ) {
2894
            return as_string(value.toString());
2895
        }
2896
        if( value instanceof Number ) {
2897
            return as_string((Number)value);
2898
        }
2899
        if( value instanceof Boolean ) {
2900
            return as_string((boolean)value);
2901
        }
2902
        if( value instanceof byte[] ) {
2903
            return as_string((byte[])value);
2904
        }
2905
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2906
    }
2907
    
2908
    @Override
2909
    public GeometryExpressionBuilder expression() {
2910
        return this.expressionBuilder;
2911
    }
2912

    
2913
    @Override
2914
    public boolean has_spatial_functions() {
2915
        return this.hasSpatialFunctions;
2916
    }
2917

    
2918
    @Override
2919
    public GeometrySupportType geometry_support_type() {
2920
        return this.geometrySupportType;
2921
    }
2922

    
2923
    protected GeometryExpressionBuilder createExpressionBuilder() {
2924
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2925
    }
2926

    
2927
    @Override
2928
    public Object srs_id(IProjection projection) {
2929
        String abrev = projection.getAbrev();
2930
        return abrev.split(":")[1].trim();
2931
    }
2932

    
2933
    @Override
2934
    public String default_schema() {
2935
        return this.defaultSchema;
2936
    }
2937

    
2938
    @Override
2939
    public boolean support_schemas() {
2940
        return this.supportSchemas;
2941
    }
2942

    
2943
    @Override
2944
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2945
        switch (type) {
2946
            case DataTypes.BOOLEAN:
2947
                return type_boolean;
2948
            case DataTypes.CHAR:
2949
                return type_char;
2950

    
2951

    
2952
            case DataTypes.BYTE:
2953
                return type_byte;
2954
            case DataTypes.INT:
2955
                return type_int;
2956
            case DataTypes.LONG:
2957
                return type_long;
2958

    
2959
            case DataTypes.FLOAT:
2960
                return type_float;
2961
            case DataTypes.DOUBLE:
2962
                return type_double;
2963
            case DataTypes.DECIMAL:
2964
                if (precision < 1) {
2965
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2966
                }
2967
                if (scale < 1) {
2968
                  return MessageFormat.format(type_decimal_p, precision);
2969
                }
2970
                return MessageFormat.format(type_decimal_ps, precision, scale);
2971

    
2972
                
2973
            case DataTypes.STRING:
2974
                if (size < 0) {
2975
                    return type_string;
2976
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
2977
                    return MessageFormat.format(type_string_p, size);
2978
                }
2979
                return type_string;
2980

    
2981
                
2982
            case DataTypes.DATE:
2983
                return type_date;
2984
            case DataTypes.TIME:
2985
                return type_time;
2986
            case DataTypes.TIMESTAMP:
2987
                return type_timestamp;
2988

    
2989
            case DataTypes.BYTEARRAY:
2990
                return type_bytearray;
2991

    
2992
            case DataTypes.GEOMETRY:
2993
                return type_geometry;
2994

    
2995
            case DataTypes.VERSION:
2996
                return type_version;
2997
            case DataTypes.URI:
2998
                return type_URI;
2999
            case DataTypes.URL:
3000
                return type_URL;
3001
            case DataTypes.FILE:
3002
                return type_FILE;
3003
            case DataTypes.FOLDER:
3004
                return type_FOLDER;
3005
            default:
3006
                return null;
3007
        }
3008
    }
3009

    
3010
    @Override
3011
    public Object sqlgeometrytype(int type, int subtype) {
3012
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3013
        // identificadores numericos para el tipo y otros strings.
3014
        // Por defecto vamos a devolver strings.
3015
        if (sqlgeometrytypes == null) {
3016
            sqlgeometrytypes = new HashMap<>();
3017
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3018
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3019
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3020
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3021

    
3022
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3023
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3024
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3025
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3026

    
3027
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3028
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3029
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3030
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3031

    
3032
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3033
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3034
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3035
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3036

    
3037
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3038
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3039
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3040
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3041

    
3042
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3043
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3044
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3045
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3046

    
3047
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3048
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3049
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3050
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3051

    
3052
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3053
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3054
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3055
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3056

    
3057
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3058
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3059
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3060
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3061
        }
3062
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3063
    }
3064

    
3065
    @Override
3066
    public Object sqlgeometrydimension(int type, int subtype) {
3067
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3068
        // identificadores numericos para las dimensiones y otros strings.
3069
        // Por defecto vamos a devolver enteros.
3070
        switch (subtype) {
3071
            case Geometry.SUBTYPES.GEOM3D:
3072
                return 3;
3073
            case Geometry.SUBTYPES.GEOM2DM:
3074
                return 3;
3075
            case Geometry.SUBTYPES.GEOM3DM:
3076
                return 4;
3077
            case Geometry.SUBTYPES.GEOM2D:
3078
            default:
3079
                return 2;
3080
        }
3081
    }
3082

    
3083
    @Override
3084
    public TableNameBuilder createTableNameBuilder() {
3085
        return new TableNameBuilderBase();
3086
    }
3087

    
3088
    protected SelectColumnBuilder createSelectColumnBuilder() {
3089
        return new SelectColumnBuilderBase(this);
3090
    }
3091

    
3092
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3093
        return new UpdateColumnBuilderBase();
3094
    }
3095

    
3096
    protected InsertColumnBuilder createInsertColumnBuilder() {
3097
        return new InsertColumnBuilderBase();
3098
    }
3099

    
3100
    protected OrderByBuilder createOrderByBuilder() {
3101
        return new OrderByBuilderBase();
3102
    }
3103

    
3104
    protected FromBuilder createFromBuilder() {
3105
        return new FromBuilderBase();
3106
    }
3107

    
3108
    protected SelectBuilder createSelectBuilder() {
3109
        return new SelectBuilderBase();
3110
    }
3111

    
3112
    protected UpdateBuilder createUpdateBuilder() {
3113
        return new UpdateBuilderBase();
3114
    }
3115

    
3116
    protected DeleteBuilder createDeleteBuilder() {
3117
        return new DeleteBuilderBase();
3118
    }
3119

    
3120
    protected GrantBuilder createGrantBuilder() {
3121
        return new GrantBuilderBase();
3122
    }
3123

    
3124
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3125
        return new GrantRoleBuilderBase(table, role);
3126
    }
3127

    
3128
    protected DropTableBuilder createDropTableBuilder() {
3129
        return new DropTableBuilderBase();
3130
    }
3131

    
3132
    protected CreateTableBuilder createCreateTableBuilder() {
3133
        return new CreateTableBuilderBase();
3134
    }
3135

    
3136
    protected AlterTableBuilder createAlterTableBuilder() {
3137
        return new AlterTableBuilderBase();
3138
    }
3139

    
3140
    protected InsertBuilder createInsertBuilder() {
3141
        return new InsertBuilderBase();
3142
    }
3143

    
3144
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3145
        return new UpdateTableStatisticsBuilderBase();
3146
    }
3147

    
3148
    protected CreateIndexBuilder createCreateIndexBuilder() {
3149
        return new CreateIndexBuilderBase();
3150
    }
3151

    
3152
    protected DropIndexBuilder createDropIndexBuilder() {
3153
        return new DropIndexBuilderBase();
3154
    }
3155

    
3156
    @Override
3157
    public SelectBuilder select() {
3158
        if (this.select == null) {
3159
            this.select = this.createSelectBuilder();
3160
        }
3161
        return this.select;
3162
    }
3163

    
3164
    @Override
3165
    public UpdateBuilder update() {
3166
        if (this.update == null) {
3167
            this.update = this.createUpdateBuilder();
3168
        }
3169
        return this.update;
3170
    }
3171

    
3172
    @Override
3173
    public UpdateTableStatisticsBuilder update_table_statistics() {
3174
        if (this.update_table_statistics == null) {
3175
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3176
        }
3177
        return this.update_table_statistics;
3178
    }
3179

    
3180
    @Override
3181
    public DropTableBuilder drop_table() {
3182
        if (this.drop_table == null) {
3183
            this.drop_table = this.createDropTableBuilder();
3184
        }
3185
        return this.drop_table;
3186
    }
3187

    
3188
    @Override
3189
    public CreateIndexBuilder create_index() {
3190
        if (this.create_index == null) {
3191
            this.create_index = this.createCreateIndexBuilder();
3192
        }
3193
        return this.create_index;
3194
    }
3195

    
3196
    @Override
3197
    public DropIndexBuilder drop_index() {
3198
        if (this.drop_index == null) {
3199
            this.drop_index = this.createDropIndexBuilder();
3200
        }
3201
        return this.drop_index;
3202
    }
3203

    
3204
    @Override
3205
    public DeleteBuilder delete() {
3206
        if (this.delete == null) {
3207
            this.delete = this.createDeleteBuilder();
3208
        }
3209
        return this.delete;
3210
    }
3211

    
3212
    @Override
3213
    public InsertBuilder insert() {
3214
        if (this.insert == null) {
3215
            this.insert = this.createInsertBuilder();
3216
        }
3217
        return this.insert;
3218
    }
3219

    
3220
    @Override
3221
    public TableNameBuilder table_name() {
3222
        if (this.table_name == null) {
3223
            this.table_name = this.createTableNameBuilder();
3224
        }
3225
        return this.table_name;
3226
    }
3227

    
3228
    
3229
    @Override
3230
    public AlterTableBuilder alter_table() {
3231
        if (this.alter_table == null) {
3232
            this.alter_table = this.createAlterTableBuilder();
3233
        }
3234
        return this.alter_table;
3235
    }
3236

    
3237
    @Override
3238
    public CreateTableBuilder create_table() {
3239
        if (this.create_table == null) {
3240
            this.create_table = this.createCreateTableBuilder();
3241
        }
3242
        return this.create_table;
3243
    }
3244

    
3245
    @Override
3246
    public GrantBuilder grant() {
3247
        if (this.grant == null) {
3248
            this.grant = this.createGrantBuilder();
3249
        }
3250
        return this.grant;
3251
    }
3252
    
3253
    @Override
3254
    public Column column(String name) {
3255
        ColumnBase col = new ColumnBase(null, name);
3256
        return col;
3257
    }
3258

    
3259
    @Override
3260
    public Column column(TableNameBuilder table, String name) {
3261
        ColumnBase col = new ColumnBase(table, name);
3262
        return col;
3263
    }
3264
    
3265
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3266
        return new JoinBase(type, table, expression);
3267
    }
3268

    
3269
    public void accept(Visitor visitor, VisitorFilter filter) {
3270
        if (this.select != null) {
3271
            this.select.accept(visitor, filter);
3272
        }
3273
        if (this.update != null) {
3274
            this.update.accept(visitor, filter);
3275
        }
3276
        if (this.insert != null) {
3277
            this.insert.accept(visitor, filter);
3278
        }
3279
        if (this.delete != null) {
3280
            this.delete.accept(visitor, filter);
3281
        }
3282
        if (this.alter_table != null) {
3283
            this.alter_table.accept(visitor, filter);
3284
        }
3285
        if (this.create_table != null) {
3286
            this.create_table.accept(visitor, filter);
3287
        }
3288
        if (this.drop_table != null) {
3289
            this.drop_table.accept(visitor, filter);
3290
        }
3291
        if (this.table_name != null) {
3292
            this.table_name.accept(visitor, filter);
3293
        }
3294
    }
3295

    
3296
        @Override
3297
    public Formatter formatter() {
3298
        return expression().formatter();
3299
    }
3300

    
3301
    @Override
3302
    public String toString() {
3303
        return this.toString(formatter());
3304
    }
3305

    
3306
    @Override
3307
    public String toString(Formatter formatter) {
3308
        if (this.select != null) {
3309
            return this.select.toString(formatter);
3310
        }
3311
        if (this.update != null) {
3312
            return this.update.toString(formatter);
3313
        }
3314
        if (this.insert != null) {
3315
            return this.insert.toString(formatter);
3316
        }
3317
        if (this.delete != null) {
3318
            return this.delete.toString(formatter);
3319
        }
3320
        if (this.alter_table != null) {
3321
            return this.alter_table.toString(formatter);
3322
        }
3323
        if (this.create_table != null) {
3324
            return this.create_table.toString(formatter);
3325
        }
3326
        if (this.drop_table != null) {
3327
            return this.drop_table.toString(formatter);
3328
        }
3329
        if (this.update_table_statistics != null) {
3330
            return this.update_table_statistics.toString(formatter);
3331
        }
3332
        if (this.create_index != null) {
3333
            return this.create_index.toString(formatter);
3334
        }
3335
        if (this.drop_index != null) {
3336
            return this.drop_index.toString(formatter);
3337
        }
3338
        if (this.table_name != null) {
3339
            return this.table_name.toString(formatter);
3340
        }
3341
        return "";
3342
    }
3343

    
3344
    @Override
3345
    public CountBuilder count() {
3346
        return new CountBuilderBase();
3347
    }
3348

    
3349
    @Override
3350
    public List<Parameter> parameters() {
3351
        final List<Parameter> params = new ArrayList<>();
3352
        this.accept((Visitable value) -> {
3353
            params.add((Parameter) value);
3354
        }, new ClassVisitorFilter(Parameter.class));
3355
        return params;
3356
    }
3357

    
3358
    @Override
3359
    public List<Variable> variables() {
3360
        final List<Variable> vars = new ArrayList<>();
3361
        this.accept(new Visitor() {
3362
            @Override
3363
            public void visit(Visitable value) {
3364
                if (!vars.contains((Variable) value)) {
3365
                    vars.add((Variable) value);
3366
                }
3367
            }
3368
        }, new ClassVisitorFilter(Variable.class));
3369
        return vars;
3370
    }
3371

    
3372
    @Override
3373
    public List<String> parameters_names() {
3374
        List<String> params = new ArrayList<>();
3375
        for (Parameter param : parameters()) {
3376
            String s;
3377
            switch (param.type()) {
3378
                case PARAMETER_TYPE_CONSTANT:
3379
                    Object theValue = param.value();
3380
                    if (theValue == null) {
3381
                        s = "null";
3382
                    } else if (theValue instanceof String) {
3383
                        s = "'" + (String) theValue + "'";
3384
                    } else {
3385
                        s = theValue.toString();
3386
                    }
3387
                    break;
3388
                case PARAMETER_TYPE_VARIABLE:
3389
                default:
3390
                    s = "\"" + param.name() + "\"";
3391
            }
3392
            params.add(s);
3393
        }
3394
        return params;
3395
    }
3396

    
3397
    @Override
3398
    public List<String> variables_names() {
3399
        List<String> vars = new ArrayList<>();
3400
        for (Variable var : this.variables()) {
3401
            vars.add(var.name());
3402
        }
3403
        Collections.sort(vars);
3404
        return vars;
3405
    }    
3406
    
3407
    protected String[] aggregateFunctionNames = new String[] {
3408
        "MAX",
3409
        "MIN",
3410
        "COUNT",
3411
        "SUM"
3412
    };
3413
    
3414
    @Override
3415
    public boolean isAggregateFunction(String funcname) {
3416
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
3417
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
3418
                return true;
3419
            }
3420
        }
3421
        return false;
3422
    }
3423

    
3424
    @Override
3425
    public int getMaxRecomendedSQLLength() {
3426
        return DEFAULT_RECOMENDED_SQL_LENGTH;
3427
    }
3428
    
3429
    
3430
}