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

History | View | Annotate | Download (115 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
        protected int nullsMode;
918

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

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

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

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

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

    
993
        @Override
994
        public OrderByBuilder nulls(int mode) {
995
            this.nullsMode = mode;
996
            return this;
997
        }
998

    
999
        @Override
1000
        public int getNullsMode() {
1001
            return this.nullsMode;
1002
        }
1003

    
1004
        @Override
1005
        public String toString() {
1006
            return this.toString(formatter());
1007
        }
1008

    
1009
        @Override
1010
        public String toString(Formatter<Value> formatter) {
1011
            if (formatter!=null && formatter.canApply(this)) {
1012
                return formatter.format(this);
1013
            }
1014
            if (!StringUtils.isEmpty(this.custom)) {
1015
                return this.custom;
1016
            }
1017
            String order_s = this.value.toString(formatter);
1018
            if (this.ascending) {
1019
                order_s += " ASC";
1020
            } else {
1021
                order_s += " DESC";
1022
            }
1023
            switch(this.nullsMode) {
1024
                case MODE_NULLS_NOT_SPECIFIED:
1025
                    break;
1026
                case MODE_NULLS_FIRST:
1027
                    order_s += " NULLS FIRST";
1028
                    break;
1029
                case MODE_NULLS_LAST:
1030
                default:
1031
                    order_s += " NULLS LAST";
1032
                    break;
1033
            }
1034
            return order_s;
1035
        }
1036
    }
1037

    
1038
    public class SelectBuilderBase
1039
            extends AbstractStatement
1040
            implements SelectBuilder {
1041

    
1042
        protected FromBuilder from;
1043
        protected GeometryExpressionBuilder where;
1044
        protected long limit = -1;
1045
        protected long offset = -1;
1046
        protected List<SelectColumnBuilder> columns;
1047
        protected List<OrderByBuilder> order_by;
1048
        protected boolean distinct;
1049
        protected List<Value> groupColumn;
1050
        protected boolean check_order_and_offset = true;
1051

    
1052
        public SelectBuilderBase() {
1053
            this.columns = new ArrayList<>();
1054
            this.distinct = false;
1055
        }
1056
        @Override
1057
        public List<Value> getGroups() {
1058
            return this.groupColumn;
1059
        }
1060
        
1061
        @Override
1062
        public List<SelectColumnBuilder> getColumns() {
1063
            return Collections.unmodifiableList(this.columns);
1064
    }
1065
        
1066
        @Override
1067
        public void remove_column(String columnName) {
1068
            SelectColumnBuilder found = null;
1069
            for (SelectColumnBuilder column : columns) {
1070
                if(column.getAlias().equalsIgnoreCase(columnName)) {
1071
                    found = column;
1072
                    break;
1073
                }
1074
                    
1075
            }
1076
            if(found!=null) {
1077
                columns.remove(found);
1078
            }
1079
        }
1080

    
1081
        @Override
1082
        public SelectBuilder group_by(Value... columns) {
1083
            if( this.groupColumn==null ) {
1084
                this.groupColumn = new ArrayList<>();
1085
            }
1086
            for (Value column : columns) {
1087
                this.groupColumn.add(column);
1088
            }
1089
            return this;
1090
        }
1091

    
1092
        @Override
1093
        public void accept(Visitor visitor, VisitorFilter filter) {
1094
            if (filter==null || filter.accept(this)) {
1095
                visitor.visit(this);
1096
            }
1097
            for (SelectColumnBuilder column : columns) {
1098
                column.accept(visitor, filter);
1099
            }
1100
            if (this.has_from()) {
1101
                this.from.accept(visitor, filter);
1102
            }
1103
            if (this.has_where()) {
1104
                this.where.accept(visitor, filter);
1105
            }
1106
            if (this.has_order_by()) {
1107
                for (OrderByBuilder order : order_by) {
1108
                    order.accept(visitor, filter);
1109
                }
1110
            }
1111
            if (this.has_group_by()) {
1112
                for (Value group : groupColumn) {
1113
                    group.accept(visitor, filter);
1114
                }
1115
            }
1116
        }
1117

    
1118
        @Override
1119
        public void replace(Value target, Value replacement) {
1120
            if( this.columns!=null ) {
1121
                for (int i = 0; i < columns.size(); i++) {
1122
                    SelectColumnBuilder column = columns.get(i);
1123
                    if( column == target ) {
1124
                        columns.set(i, (SelectColumnBuilder) replacement);
1125
                    } else {
1126
                        column.replace(target, replacement);
1127
                    }
1128
                }
1129
            }
1130
            if (this.has_from()) {
1131
                if( this.from == target ) {
1132
                    this.from = (FromBuilder) replacement;
1133
                } else {
1134
                    this.from.replace(target, replacement);
1135
                }
1136
            }
1137
            if (this.has_where()) {
1138
                if( this.where == target ) {
1139
                    this.where = (GeometryExpressionBuilder) replacement;
1140
                } else if( this.where.value() == target ) {
1141
                    this.where.value(replacement);
1142
                } else {
1143
                    this.where.value().replace(target, replacement);
1144
                }
1145
            }
1146
            if (this.has_order_by()) {
1147
                for (int i = 0; i < order_by.size(); i++) {
1148
                    OrderByBuilder order = order_by.get(i);
1149
                    if( order == target ) {
1150
                        order_by.set(i, (OrderByBuilder) replacement);
1151
                    } else {
1152
                        order.replace(target, replacement);
1153
                    }
1154
                }
1155
            }
1156
            if (this.has_group_by()) {
1157
                for (int i = 0; i < groupColumn.size(); i++) {
1158
                    Value group = groupColumn.get(i);
1159
                    if( group == target ) {
1160
                        groupColumn.set(i, replacement);
1161
                    } else {
1162
                        group.replace(target, replacement);
1163
                    }
1164
                }
1165
            }
1166
        }
1167

    
1168
        @Override
1169
        public SelectBuilder distinct() {
1170
            this.distinct = true;
1171
            return this;
1172
        }
1173

    
1174
        @Override
1175
        public SelectColumnBuilder column() {
1176
            SelectColumnBuilder builder = createSelectColumnBuilder();
1177
            this.columns.add(builder);
1178
            return builder;
1179
        }
1180

    
1181
        @Override
1182
        public SelectBuilder remove_all_columns() {
1183
            this.columns = new ArrayList<>();
1184
            return this;
1185
        }
1186
        
1187
        @Override
1188
        public boolean has_column(String name) {
1189
            for (SelectColumnBuilder column : columns) {
1190
                if (StringUtils.equals(name, column.getName())) {
1191
                    return true;
1192
                }
1193
                if (StringUtils.equals(name, column.getAlias())) {
1194
                    return true;
1195
                }
1196
            }
1197
            return false;
1198
        }
1199

    
1200
        @Override
1201
        public FromBuilder from() {
1202
            if (this.from == null) {
1203
                this.from = createFromBuilder();
1204
            }
1205
            return this.from;
1206
        }
1207

    
1208
        @Override
1209
        public boolean has_from() {
1210
            return this.from != null;
1211
        }
1212

    
1213
        @Override
1214
        public GeometryExpressionBuilder where() {
1215
            if (this.where == null) {
1216
                this.where = createExpressionBuilder();
1217
            }
1218
            return this.where;
1219
        }
1220

    
1221
        @Override
1222
        public boolean has_where() {
1223
            if (this.where == null) {
1224
                return false;
1225
            }
1226
            return this.where.value() != null;
1227
        }
1228

    
1229
        @Override
1230
        public SelectBuilder limit(long limit) {
1231
            this.limit = limit;
1232
            return this;
1233
        }
1234

    
1235
        @Override
1236
        public SelectBuilder limit(Long limit) {
1237
            if (limit == null) {
1238
                this.limit = -1;
1239
            } else {
1240
                this.limit = limit;
1241
            }
1242
            return this;
1243
        }
1244

    
1245
        @Override
1246
        public boolean has_limit() {
1247
            return this.limit >= 0;
1248
        }
1249

    
1250
        @Override
1251
        public SelectBuilder offset(long offset) {
1252
            this.offset = offset;
1253
            return this;
1254
        }
1255

    
1256
        @Override
1257
        public boolean has_offset() {
1258
            return this.offset > 0;
1259
        }
1260

    
1261
        @Override
1262
        public OrderByBuilder order_by() {
1263
            if (this.order_by == null) {
1264
                this.order_by = new ArrayList<>();
1265
            }
1266
            OrderByBuilder order = createOrderByBuilder();
1267
            this.order_by.add(order);
1268
            return order;
1269
        }
1270
        
1271
        @Override
1272
        public OrderByBuilder getOrderBy(Value column) {
1273
            if(this.order_by == null){
1274
                return null;
1275
            }
1276
            for (OrderByBuilder orderByBuilder : this.order_by) {
1277
                if(orderByBuilder.isColumn(column)){
1278
                    return orderByBuilder;
1279
                }
1280
            }
1281
            return null;
1282
        }
1283
        
1284
        @Override
1285
        public OrderByBuilder getOrderBy(String column) {
1286
            if(this.order_by == null){
1287
                return null;
1288
            }
1289
            for (OrderByBuilder orderByBuilder : this.order_by) {
1290
                if(orderByBuilder.isColumn(column)){
1291
                    return orderByBuilder;
1292
                }
1293
            }
1294
            return null;
1295
        }
1296

    
1297
        @Override
1298
        public boolean has_order_by() {
1299
            if (this.order_by == null) {
1300
                return false;
1301
            }
1302
            return !this.order_by.isEmpty();
1303
        }
1304
        
1305
        @Override
1306
        public boolean has_group_by() {
1307
            if (this.groupColumn == null) {
1308
                return false;
1309
            }
1310
            return !this.groupColumn.isEmpty();
1311
        }
1312
        
1313
        @Override
1314
        public boolean has_aggregate_functions() {
1315
            if (this.columns == null || this.columns.isEmpty() ) {
1316
                return false;
1317
            }
1318
            for (SelectColumnBuilder column : this.columns) {
1319
                if( column.isAggregateFunction() ) {
1320
                    return true;
1321
                }
1322
            }
1323
            return false;
1324
        }
1325
        
1326
        @Override
1327
        public void disable_check_order_and_offset() {
1328
          this.check_order_and_offset = false;
1329
        }
1330
        
1331
        protected boolean isValid(StringBuilder message) {
1332
            if (message == null) {
1333
                message = new StringBuilder();
1334
            }
1335
            if( this.check_order_and_offset ) {
1336
              if (this.has_offset() && !this.has_order_by()) {
1337
                  // Algunos gestores de BBDD requieren que se especifique un
1338
                  // orden para poder usar OFFSET. Como eso parece buena idea para
1339
                  // asegurar que siempre tengamos los mismo resultados, lo exigimos
1340
                  // siempre.
1341
                  message.append("Can't use OFFSET without an ORDER BY.");
1342
                  return false;
1343
              }
1344
            }
1345
            return true;
1346
        }
1347

    
1348
        @Override
1349
        public String toString() {
1350
            return this.toString(formatter());
1351
        }
1352

    
1353
        @Override
1354
        public String toString(Formatter<Value> formatter) {
1355
            if (formatter!=null && formatter.canApply(this)) {
1356
                return formatter.format(this);
1357
            }
1358
            StringBuilder builder = new StringBuilder();
1359
            if (!this.isValid(builder)) {
1360
                throw new IllegalStateException(builder.toString());
1361
            }
1362
            builder.append("SELECT ");
1363
            if (this.distinct) {
1364
                builder.append("DISTINCT ");
1365
            }
1366
            boolean first = true;
1367
            for (SelectColumnBuilder column : columns) {
1368
                if (first) {
1369
                    first = false;
1370
                } else {
1371
                    builder.append(", ");
1372
                }
1373
                builder.append(column.toString(formatter));
1374
            }
1375

    
1376
            if (this.has_from()) {
1377
                builder.append(" FROM ");
1378
                builder.append(this.from.toString(formatter));
1379
            }
1380
            if (this.has_where()) {
1381
                builder.append(" WHERE ");
1382
                builder.append(this.where.toString(formatter));
1383
            }
1384
            if( this.has_group_by() ) {
1385
                builder.append(" GROUP BY ");
1386
                builder.append(this.groupColumn.get(0).toString(formatter));
1387
                for (int i = 1; i < groupColumn.size(); i++) {
1388
                    builder.append(", ");
1389
                    builder.append(this.groupColumn.get(i).toString(formatter));
1390
                }
1391
            }
1392
            if (this.has_order_by()) {
1393
                builder.append(" ORDER BY ");
1394
                first = true;
1395
                for (OrderByBuilder item : this.order_by) {
1396
                    if (first) {
1397
                        first = false;
1398
                    } else {
1399
                        builder.append(", ");
1400
                    }
1401
                    builder.append(item.toString(formatter));
1402
                }
1403
            }
1404

    
1405
            if (this.has_limit()) {
1406
                builder.append(" LIMIT ");
1407
                builder.append(this.limit);
1408
            }
1409
            if (this.has_offset()) {
1410
                builder.append(" OFFSET ");
1411
                builder.append(this.offset);
1412
            }
1413
            return builder.toString();
1414

    
1415
        }
1416
    }
1417

    
1418
    public class DropTableBuilderBase
1419
            extends AbstractStatement
1420
            implements DropTableBuilder {
1421

    
1422
        protected TableNameBuilder table;
1423

    
1424
        @Override
1425
        public TableNameBuilder table() {
1426
            if (table == null) {
1427
                table = createTableNameBuilder();
1428
            }
1429
            return table;
1430
        }
1431

    
1432
        @Override
1433
        public void accept(Visitor visitor, VisitorFilter filter) {
1434
            if (filter==null || filter.accept(this)) {
1435
                visitor.visit(this);
1436
            }
1437
            this.table.accept(visitor, filter);
1438
        }
1439

    
1440
        @Override
1441
        public String toString() {
1442
            return this.toString(formatter());
1443
        }
1444

    
1445
        @Override
1446
        public String toString(Formatter<Value> formatter) {
1447
            if (formatter!=null && formatter.canApply(this)) {
1448
                return formatter.format(this);
1449
            }
1450
            StringBuilder builder = new StringBuilder();
1451
            boolean first = true;
1452
            for (String sql : toStrings(formatter)) {
1453
                if (StringUtils.isEmpty(sql)) {
1454
                    continue;
1455
                }
1456
                if (first) {
1457
                    first = false;
1458
                } else {
1459
                    builder.append("; ");
1460
                }
1461
                builder.append(sql);
1462
            }
1463
            return builder.toString();
1464
        }
1465

    
1466
        @Override
1467
        public List<String> toStrings() {
1468
            return this.toStrings(formatter());
1469
        }
1470

    
1471
        @Override
1472
        public List<String> toStrings(Formatter formatter) {
1473
            List<String> sqls = new ArrayList<>();
1474

    
1475
            sqls.add(
1476
                    MessageFormat.format(
1477
                            STMT_DROP_TABLE_table,
1478
                            this.table.toString(formatter)
1479
                    )
1480
            );
1481
            String sql;
1482
            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
1483
                if (this.table.has_schema()) {
1484
                    sql = MessageFormat.format(
1485
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
1486
                            as_string(this.table.getSchema()),
1487
                            as_string(this.table.getName())
1488
                    );
1489
                } else {
1490
                    sql = MessageFormat.format(
1491
                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
1492
                            as_identifier(this.table.getName())
1493
                    );
1494
                }
1495
                if (!StringUtils.isEmpty(sql)) {
1496
                    sqls.add(sql);
1497
                }
1498
            }
1499
            return sqls;
1500
        }
1501
    }
1502

    
1503
    public class GrantRoleBuilderBase
1504
            extends AbstractStatementPart
1505
            implements GrantRoleBuilder {
1506

    
1507
        protected TableNameBuilder table;
1508
        protected String role;
1509
        protected Set<Privilege> privileges;
1510

    
1511
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
1512
            this.table = table;
1513
            this.role = role;
1514
            this.privileges = new HashSet<>();
1515
        }
1516
        
1517
        @Override
1518
        public GrantRoleBuilderBase clone() throws CloneNotSupportedException {
1519
            GrantRoleBuilderBase other = (GrantRoleBuilderBase) super.clone();
1520
            other.table = (TableNameBuilder) org.gvsig.tools.lang.Cloneable.cloneQuietly(table);
1521
            other.privileges = (Set<Privilege>) org.gvsig.tools.lang.Cloneable.cloneQuietly(privileges);
1522
            
1523
            return other;
1524
        }
1525

    
1526
        @Override
1527
        public GrantRoleBuilder privilege(Privilege privilege) {
1528
            privileges.add(privilege);
1529
            return this;
1530
        }
1531

    
1532
        @Override
1533
        public GrantRoleBuilder select() {
1534
            privileges.add(Privilege.SELECT);
1535
            return this;
1536
        }
1537

    
1538
        @Override
1539
        public GrantRoleBuilder update() {
1540
            privileges.add(Privilege.UPDATE);
1541
            return this;
1542
        }
1543

    
1544
        @Override
1545
        public GrantRoleBuilder insert() {
1546
            privileges.add(Privilege.INSERT);
1547
            return this;
1548
        }
1549

    
1550
        @Override
1551
        public GrantRoleBuilder delete() {
1552
            privileges.add(Privilege.DELETE);
1553
            return this;
1554
        }
1555

    
1556
        @Override
1557
        public GrantRoleBuilder truncate() {
1558
            privileges.add(Privilege.TRUNCATE);
1559
            return this;
1560
        }
1561

    
1562
        @Override
1563
        public GrantRoleBuilder reference() {
1564
            privileges.add(Privilege.REFERENCE);
1565
            return this;
1566
        }
1567

    
1568
        @Override
1569
        public GrantRoleBuilder trigger() {
1570
            privileges.add(Privilege.TRIGGER);
1571
            return this;
1572
        }
1573

    
1574
        @Override
1575
        public GrantRoleBuilder all() {
1576
            privileges.add(Privilege.ALL);
1577
            return this;
1578
        }
1579

    
1580
        protected String getPrivilegeName(Privilege privilege) {
1581
            switch (privilege) {
1582
                case DELETE:
1583
                    return "DELETE";
1584
                case INSERT:
1585
                    return "INSERT";
1586
                case REFERENCE:
1587
                    return "REFERENCE";
1588
                case SELECT:
1589
                    return "SELECT";
1590
                case TRIGGER:
1591
                    return "TRIGGER";
1592
                case TRUNCATE:
1593
                    return "TRUNCATE";
1594
                case UPDATE:
1595
                    return "UPDATE";
1596
                case ALL:
1597
                default:
1598
                    return "ALL";
1599
            }
1600
        }
1601

    
1602
        @Override
1603
        public String toString() {
1604
            return this.toString(formatter());
1605
        }
1606

    
1607
        @Override
1608
        public String toString(Formatter<Value> formatter) {
1609
            if (formatter!=null && formatter.canApply(this)) {
1610
                return formatter.format(this);
1611
            }
1612
            StringBuilder builder = new StringBuilder();
1613
            boolean first = true;
1614
            for (Privilege privilege : privileges) {
1615
                if (first) {
1616
                    first = false;
1617
                } else {
1618
                    builder.append(", ");
1619
                }
1620
                builder.append(this.getPrivilegeName(privilege));
1621
            }
1622
            String sql = MessageFormat.format(
1623
                    STMT_GRANT_privileges_ON_table_TO_role,
1624
                    builder.toString(),
1625
                    table.toString(formatter),
1626
                    role
1627
            );
1628
            return sql;
1629
        }
1630
    }
1631

    
1632
    public class GrantBuilderBase
1633
            extends AbstractStatement
1634
            implements GrantBuilder {
1635

    
1636
        protected TableNameBuilder table;
1637
        protected Map<String, GrantRoleBuilder> roles;
1638

    
1639
        public GrantBuilderBase() {
1640
            this.roles = new HashMap<>();
1641
        }
1642

    
1643
        @Override
1644
        public TableNameBuilder table() {
1645
            if (table == null) {
1646
                table = createTableNameBuilder();
1647
            }
1648
            return table;
1649
        }
1650

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

    
1661
        @Override
1662
        public GrantRoleBuilder role(String role) {
1663
            GrantRoleBuilder roleBuilder = this.roles.get(role);
1664
            if (roleBuilder == null) {
1665
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1666
                this.roles.put(role, roleBuilder);
1667
            }
1668
            return roleBuilder;
1669
        }
1670

    
1671
        @Override
1672
        public String toString() {
1673
            return this.toString(formatter());
1674
        }
1675

    
1676
        @Override
1677
        public String toString(Formatter<Value> formatter) {
1678
            if (formatter!=null && formatter.canApply(this)) {
1679
                return formatter.format(this);
1680
            }
1681
            StringBuilder builder = new StringBuilder();
1682
            boolean first = true;
1683
            for (String sql : toStrings(formatter)) {
1684
                if (StringUtils.isEmpty(sql)) {
1685
                    continue;
1686
                }
1687
                if (first) {
1688
                    first = false;
1689
                } else {
1690
                    builder.append("; ");
1691
                }
1692
                builder.append(sql);
1693
            }
1694
            return builder.toString();
1695
        }
1696

    
1697
        @Override
1698
        public List<String> toStrings() {
1699
            return this.toStrings(formatter());
1700
        }
1701

    
1702
        @Override
1703
        public List<String> toStrings(Formatter formatter) {
1704
            List<String> sqls = new ArrayList<>();
1705
            for (GrantRoleBuilder role : roles.values()) {
1706
                sqls.add(role.toString(formatter));
1707
            }
1708
            return sqls;
1709
        }
1710
    }
1711

    
1712
    public class UpdateColumnBuilderBase
1713
            extends InsertColumnBuilderBase
1714
            implements UpdateColumnBuilder {
1715

    
1716
        public UpdateColumnBuilderBase() {
1717
            super();
1718
        }
1719

    
1720
        @Override
1721
        public UpdateColumnBuilder name(String name) {
1722
            return (UpdateColumnBuilder) super.name(name);
1723
        }
1724

    
1725
        @Override
1726
        public UpdateColumnBuilder with_value(Value value) {
1727
            return (UpdateColumnBuilder) super.with_value(value);
1728
        }
1729

    
1730
    }
1731

    
1732
    public class UpdateBuilderBase
1733
            extends AbstractStatement
1734
            implements UpdateBuilder {
1735

    
1736
        protected GeometryExpressionBuilder where;
1737
        protected List<UpdateColumnBuilder> columns;
1738
        protected TableNameBuilder table;
1739

    
1740
        public UpdateBuilderBase() {
1741
            this.columns = new ArrayList<>();
1742
        }
1743

    
1744
        @Override
1745
        public void accept(Visitor visitor, VisitorFilter filter) {
1746
            if (filter==null || filter.accept(this)) {
1747
                visitor.visit(this);
1748
            }
1749
            if (this.table != null) {
1750
                this.table.accept(visitor, filter);
1751
            }
1752
            for (UpdateColumnBuilder column : columns) {
1753
                column.accept(visitor, filter);
1754
            }
1755
            if (this.has_where()) {
1756
                this.where.accept(visitor, filter);
1757
            }
1758
        }
1759

    
1760
        @Override
1761
        public GeometryExpressionBuilder where() {
1762
            if (this.where == null) {
1763
                this.where = createExpressionBuilder();
1764
            }
1765
            return this.where;
1766
        }
1767

    
1768
        @Override
1769
        public TableNameBuilder table() {
1770
            if (table == null) {
1771
                table = createTableNameBuilder();
1772
            }
1773
            return table;
1774
        }
1775

    
1776
        @Override
1777
        public UpdateColumnBuilder column() {
1778
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1779
            this.columns.add(column);
1780
            return column;
1781
        }
1782

    
1783
        @Override
1784
        public boolean has_where() {
1785
            return this.where != null;
1786
        }
1787

    
1788
        @Override
1789
        public String toString() {
1790
            return this.toString(formatter());
1791
        }
1792

    
1793
        @Override
1794
        public String toString(Formatter<Value> formatter) {
1795
            if (formatter!=null && formatter.canApply(this)) {
1796
                return formatter.format(this);
1797
            }
1798
            /*
1799
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1800
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1801
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1802
             * output_expression [ AS output_name ] [, ...] ]
1803
             */
1804
            StringBuilder columnsAndValues = new StringBuilder();
1805

    
1806
            boolean first = true;
1807
            for (UpdateColumnBuilder column : columns) {
1808
                if (first) {
1809
                    first = false;
1810
                } else {
1811
                    columnsAndValues.append(", ");
1812
                }
1813
                columnsAndValues.append(as_identifier(column.getName()));
1814
                columnsAndValues.append(" = ");
1815
                columnsAndValues.append(column.getValue().toString(formatter));
1816
            }
1817

    
1818
            String sql;
1819
            if (this.has_where()) {
1820
                sql = MessageFormat.format(
1821
                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
1822
                        this.table.toString(formatter),
1823
                        columnsAndValues.toString(),
1824
                        this.where.toString(formatter)
1825
                );
1826
            } else {
1827
                sql = MessageFormat.format(
1828
                        STMT_UPDATE_table_SET_columnsAndValues,
1829
                        this.table.toString(formatter),
1830
                        columnsAndValues.toString()
1831
                );
1832
            }
1833
            return sql;
1834
        }
1835
    }
1836

    
1837
    public class DeleteBuilderBase
1838
            extends AbstractStatement
1839
            implements DeleteBuilder {
1840

    
1841
        protected GeometryExpressionBuilder where;
1842
        protected TableNameBuilder table;
1843

    
1844
        public DeleteBuilderBase() {
1845
        }
1846

    
1847
        @Override
1848
        public void accept(Visitor visitor, VisitorFilter filter) {
1849
            if (filter==null || filter.accept(this)) {
1850
                visitor.visit(this);
1851
            }
1852
            if (this.table != null) {
1853
                this.table.accept(visitor, filter);
1854
            }
1855
            if (this.has_where()) {
1856
                this.where.accept(visitor, filter);
1857
            }
1858
        }
1859

    
1860
        @Override
1861
        public GeometryExpressionBuilder where() {
1862
            if (this.where == null) {
1863
                this.where = createExpressionBuilder();
1864
            }
1865
            return this.where;
1866
        }
1867

    
1868
        @Override
1869
        public TableNameBuilder table() {
1870
            if (table == null) {
1871
                table = createTableNameBuilder();
1872
            }
1873
            return table;
1874
        }
1875

    
1876
        @Override
1877
        public boolean has_where() {
1878
            return this.where != null;
1879
        }
1880

    
1881
        @Override
1882
        public String toString() {
1883
            return this.toString(formatter());
1884
        }
1885

    
1886
        @Override
1887
        public String toString(Formatter<Value> formatter) {
1888
            if (formatter!=null && formatter.canApply(this)) {
1889
                return formatter.format(this);
1890
            }
1891
            /*
1892
             * DELETE FROM table_name
1893
             * WHERE some_column=some_value; 
1894
             */
1895
            String sql;
1896
            if (this.has_where()) {
1897
                sql = MessageFormat.format(
1898
                        STMT_DELETE_FROM_table_WHERE_expresion,
1899
                        this.table.toString(formatter),
1900
                        this.where.toString(formatter)
1901
                );
1902
            } else {
1903
                sql = MessageFormat.format(
1904
                        STMT_DELETE_FROM_table,
1905
                        this.table.toString(formatter)
1906
                );
1907
            }
1908
            return sql;
1909
        }
1910
    }
1911

    
1912
    public class CreateIndexBuilderBase
1913
            extends AbstractStatement
1914
            implements CreateIndexBuilder {
1915

    
1916
        protected boolean ifNotExist = false;
1917
        protected boolean isUnique = false;
1918
        protected String indexName;
1919
        protected boolean isSpatial = false;
1920
        protected TableNameBuilder table;
1921
        protected final List<String> columns;
1922

    
1923
        public CreateIndexBuilderBase() {
1924
            this.columns = new ArrayList<>();
1925
        }
1926

    
1927
        @Override
1928
        public CreateIndexBuilder unique() {
1929
            this.isUnique = true;
1930
            return this;
1931
        }
1932

    
1933
        @Override
1934
        public CreateIndexBuilder if_not_exist() {
1935
            this.ifNotExist = true;
1936
            return this;
1937
        }
1938

    
1939
        @Override
1940
        public CreateIndexBuilder name(String name) {
1941
            this.indexName = name;
1942
            return this;
1943
        }
1944

    
1945
        @Override
1946
        public CreateIndexBuilder name(String tableName, String columnName) {
1947
            this.indexName = tableName + "_IDX_" + columnName;
1948
            return this;
1949
        }
1950

    
1951
        @Override
1952
        public CreateIndexBuilder spatial() {
1953
            this.isSpatial = true;
1954
            return this;
1955
        }
1956

    
1957
        @Override
1958
        public CreateIndexBuilder column(String name) {
1959
            this.columns.add(name);
1960
            return this;
1961
        }
1962

    
1963
        @Override
1964
        public TableNameBuilder table() {
1965
            if (table == null) {
1966
                table = createTableNameBuilder();
1967
            }
1968
            return table;
1969
        }
1970

    
1971
        @Override
1972
        public void accept(Visitor visitor, VisitorFilter filter) {
1973
            if (filter==null || filter.accept(this)) {
1974
                visitor.visit(this);
1975
            }
1976
            if (this.table != null) {
1977
                this.table.accept(visitor, filter);
1978
            }
1979
        }
1980

    
1981
        @Override
1982
        public String toString() {
1983
            return this.toString(formatter());
1984
        }
1985

    
1986
        @Override
1987
        public String toString(Formatter<Value> formatter) {
1988
            if (formatter!=null && formatter.canApply(this)) {
1989
                return formatter.format(this);
1990
            }
1991
            StringBuilder builder = new StringBuilder();
1992
            boolean first = true;
1993
            for (String sql : toStrings(formatter)) {
1994
                if (StringUtils.isEmpty(sql)) {
1995
                    continue;
1996
                }
1997
                if (first) {
1998
                    first = false;
1999
                } else {
2000
                    builder.append("; ");
2001
                }
2002
                builder.append(sql);
2003
            }
2004
            return builder.toString();
2005
        }
2006

    
2007
        @Override
2008
        public List<String> toStrings() {
2009
            return this.toStrings(formatter());
2010
        }
2011

    
2012
        @Override
2013
        public List<String> toStrings(Formatter formatter) {
2014
            StringBuilder builder = new StringBuilder();
2015
            builder.append("CREATE ");
2016
            if (this.isUnique) {
2017
                builder.append("UNIQUE ");
2018
            }
2019
            builder.append("INDEX ");
2020
            if (this.ifNotExist) {
2021
                builder.append("IF NOT EXISTS ");
2022
            }
2023
            builder.append(as_identifier(this.indexName));
2024
            builder.append(" ON ");
2025
            builder.append(this.table.toString(formatter));
2026
            if (this.isSpatial) {
2027
                builder.append(" USING GIST ");
2028
            }
2029
            builder.append(" ( ");
2030
            boolean is_first_column = true;
2031
            for (String column : this.columns) {
2032
                if (is_first_column) {
2033
                    is_first_column = false;
2034
                } else {
2035
                    builder.append(", ");
2036
                }
2037
                builder.append(column);
2038
            }
2039
            builder.append(" )");
2040

    
2041
            List<String> sqls = new ArrayList<>();
2042
            sqls.add(builder.toString());
2043
            return sqls;
2044
        }
2045

    
2046
    }
2047

    
2048
    public class DropIndexBuilderBase
2049
            extends AbstractStatement
2050
            implements DropIndexBuilder {
2051

    
2052
        protected boolean ifNotExist = false;
2053
        protected String indexName;
2054

    
2055
        public DropIndexBuilderBase() {
2056
        }
2057

    
2058
        @Override
2059
        public DropIndexBuilder if_not_exist() {
2060
            this.ifNotExist = true;
2061
            return this;
2062
        }
2063

    
2064
        @Override
2065
        public DropIndexBuilder name(String name) {
2066
            this.indexName = name;
2067
            return this;
2068
        }
2069

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

    
2076
        @Override
2077
        public String toString() {
2078
            return this.toString(formatter());
2079
        }
2080

    
2081
        @Override
2082
        public String toString(Formatter<Value> formatter) {
2083
            if (formatter!=null && formatter.canApply(this)) {
2084
                return formatter.format(this);
2085
            }
2086
            StringBuilder builder = new StringBuilder();
2087
            boolean first = true;
2088
            for (String sql : toStrings(formatter)) {
2089
                if (StringUtils.isEmpty(sql)) {
2090
                    continue;
2091
                }
2092
                if (first) {
2093
                    first = false;
2094
                } else {
2095
                    builder.append("; ");
2096
                }
2097
                builder.append(sql);
2098
            }
2099
            return builder.toString();
2100
        }
2101

    
2102
        @Override
2103
        public List<String> toStrings() {
2104
            return this.toStrings(formatter());
2105
        }
2106

    
2107
        @Override
2108
        public List<String> toStrings(Formatter formatter) {
2109
            StringBuilder builder = new StringBuilder();
2110
            builder.append("DROP INDEX ");
2111
            if (this.ifNotExist) {
2112
                builder.append("IF NOT EXISTS ");
2113
            }
2114
            builder.append(as_identifier(this.indexName));
2115
            List<String> sqls = new ArrayList<>();
2116
            sqls.add(builder.toString());
2117
            return sqls;
2118
        }
2119

    
2120
    }
2121

    
2122
    public class AlterTableBuilderBase
2123
            extends AbstractStatement
2124
            implements AlterTableBuilder {
2125

    
2126
        protected TableNameBuilder table;
2127
        protected List<String> drops;
2128
        protected List<ColumnDescriptor> adds;
2129
        protected List<ColumnDescriptor> alters;
2130
        protected List<Pair<String, String>> renames;
2131
        protected String drop_primary_key_column;
2132

    
2133
        public AlterTableBuilderBase() {
2134
            this.drops = new ArrayList<>();
2135
            this.adds = new ArrayList<>();
2136
            this.alters = new ArrayList<>();
2137
            this.renames = new ArrayList<>();
2138
        }
2139

    
2140
        @Override
2141
        public boolean isEmpty() {
2142
            return this.drops.isEmpty()
2143
                    && this.adds.isEmpty()
2144
                    && this.alters.isEmpty()
2145
                    && this.renames.isEmpty();
2146
        }
2147

    
2148
        @Override
2149
        public void accept(Visitor visitor, VisitorFilter filter) {
2150
            if (filter==null || filter.accept(this)) {
2151
                visitor.visit(this);
2152
            }
2153
            if (this.table != null) {
2154
                this.table.accept(visitor, filter);
2155
            }
2156
        }
2157

    
2158
        @Override
2159
        public TableNameBuilder table() {
2160
            if (table == null) {
2161
                table = createTableNameBuilder();
2162
            }
2163
            return table;
2164
        }
2165

    
2166
        @Override
2167
        public AlterTableBuilder drop_column(String columnName) {
2168
            this.drops.add(columnName);
2169
            return this;
2170
        }
2171

    
2172
        @Override
2173
        public AlterTableBuilder drop_primary_key(String columnName) {
2174
            this.drop_primary_key_column = columnName;
2175
            return this;
2176
        }
2177

    
2178
        @Override
2179
        public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
2180
            this.adds.add(new ColumnDescriptorBase(fad));
2181
            return this;
2182
        }
2183

    
2184
        @Override
2185
        public AlterTableBuilder add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2186
            if (isPk || isAutomatic) {
2187
                allowNulls = false;
2188
            }
2189
            this.adds.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2190
            return this;
2191
        }
2192

    
2193
        @Override
2194
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2195
            if (StringUtils.isEmpty(columnName)) {
2196
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2197
            }
2198
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2199
            return this;
2200
        }
2201

    
2202
        @Override
2203
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2204
            if (StringUtils.isEmpty(columnName)) {
2205
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2206
            }
2207
            this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2208
            return this;
2209
        }
2210

    
2211
        @Override
2212
        public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
2213
            this.alters.add(new ColumnDescriptorBase(fad));
2214
            return this;
2215
        }
2216

    
2217
        @Override
2218
        public AlterTableBuilder alter_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2219
            if (isPk || isAutomatic) {
2220
                allowNulls = false;
2221
            }
2222
            this.alters.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2223
            return this;
2224
        }
2225

    
2226
        @Override
2227
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2228
            if (StringUtils.isEmpty(columnName)) {
2229
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2230
            }
2231
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2232
            return this;
2233
        }
2234

    
2235
        @Override
2236
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2237
            if (StringUtils.isEmpty(columnName)) {
2238
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2239
            }
2240
            this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2241
            return this;
2242
        }
2243

    
2244
        @Override
2245
        public AlterTableBuilder rename_column(String source, String target) {
2246
            this.renames.add(new ImmutablePair(source, target));
2247
            return this;
2248
        }
2249

    
2250
        protected String getConstrainName(String constrainType, String columnName) {
2251
            // String constraint_name = "CSTR_" + this.table().getName() + "_" + constrainType + "_" + columnName;
2252
            String constraint_name = this.table().getName() + "_" + constrainType + "_" + columnName;
2253
            return constraint_name;
2254
        }
2255

    
2256
        @Override
2257
        public String toString() {
2258
            return this.toString(formatter());
2259
        }
2260

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

    
2282
        @Override
2283
        public List<String> toStrings() {
2284
            return this.toStrings(formatter());
2285
        }
2286

    
2287
        @Override
2288
        public List<String> toStrings(Formatter formatter) {
2289
            List<String> sqls = new ArrayList<>();
2290
            if (this.isEmpty()) {
2291
                return sqls;
2292
            }
2293
            for (String column : drops) {
2294
                StringBuilder builder = new StringBuilder();
2295
                builder.append("ALTER TABLE ");
2296
                builder.append(this.table.toString(formatter));
2297
                builder.append(" DROP COLUMN IF EXISTS ");
2298
                builder.append(as_identifier(column));
2299
                sqls.add(builder.toString());
2300
            }
2301
            for (ColumnDescriptor column : adds) {
2302
                StringBuilder builder = new StringBuilder();
2303
                builder.append("ALTER TABLE ");
2304
                builder.append(this.table.toString(formatter));
2305
                builder.append(" ADD COLUMN ");
2306
                builder.append(as_identifier(column.getName()));
2307
                builder.append(" ");
2308
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2309
                    builder.append(" SERIAL");
2310
                } else {
2311
                    builder.append(
2312
                            sqltype(
2313
                                    column.getType(),
2314
                                    column.getSize(),
2315
                                    column.getPrecision(),
2316
                                    column.getScale(),
2317
                                    column.getGeometryType(),
2318
                                    column.getGeometrySubtype()
2319
                            )
2320
                    );
2321
                }
2322
                if (column.getDefaultValue() == null) {
2323
                    if (column.allowNulls()) {
2324
                        builder.append(" DEFAULT NULL");
2325
                    }
2326
                } else {
2327
                    builder.append(" DEFAULT '");
2328
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2329
                    builder.append("'");
2330
                }
2331
                if (column.allowNulls()) {
2332
                    builder.append(" NULL");
2333
                } else {
2334
                    builder.append(" NOT NULL");
2335
                }
2336
                if (column.isPrimaryKey()) {
2337
                    builder.append(" PRIMARY KEY");
2338
                }
2339
                sqls.add(builder.toString());
2340
            }
2341
            for (ColumnDescriptor column : alters) {
2342
                StringBuilder builder = new StringBuilder();
2343
                builder.append("ALTER TABLE ");
2344
                builder.append(this.table.toString(formatter));
2345
                builder.append(" ALTER COLUMN ");
2346
                builder.append(as_identifier(column.getName()));
2347
                builder.append(" SET DATA TYPE ");
2348
                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
2349
                    builder.append(" SERIAL");
2350
                } else {
2351
                    builder.append(
2352
                            sqltype(
2353
                                    column.getType(),
2354
                                    column.getSize(),
2355
                                    column.getPrecision(),
2356
                                    column.getScale(),
2357
                                    column.getGeometryType(),
2358
                                    column.getGeometrySubtype()
2359
                            )
2360
                    );
2361
                }
2362
                if (column.getDefaultValue() == null) {
2363
                    if (column.allowNulls()) {
2364
                        builder.append(" DEFAULT NULL");
2365
                    } else {
2366
                        builder.append(" DROP DEFAULT");
2367
                    }
2368
                } else {
2369
                    builder.append(" DEFAULT '");
2370
                    builder.append(column.getDefaultValue().toString());
2371
                    builder.append("'");
2372
                }
2373
                sqls.add(builder.toString());
2374
            }
2375
            for (Pair<String, String> pair : renames) {
2376
                StringBuilder builder = new StringBuilder();
2377
                builder.append("ALTER TABLE ");
2378
                builder.append(this.table.toString(formatter));
2379
                builder.append(" RENAME COLUMN ");
2380
                builder.append(as_identifier(pair.getLeft()));
2381
                builder.append(" TO ");
2382
                builder.append(as_identifier(pair.getRight()));
2383
                sqls.add(builder.toString());
2384
            }
2385
            return sqls;
2386
        }
2387

    
2388
    }
2389

    
2390
    public class CreateTableBuilderBase
2391
            extends AbstractStatement
2392
            implements CreateTableBuilder {
2393

    
2394
        protected TableNameBuilder table;
2395
        protected List<ColumnDescriptor> columns;
2396

    
2397
        public CreateTableBuilderBase() {
2398
            this.columns = new ArrayList<>();
2399
        }
2400

    
2401
        @Override
2402
        public void accept(Visitor visitor, VisitorFilter filter) {
2403
            if (filter==null || filter.accept(this)) {
2404
                visitor.visit(this);
2405
            }
2406
            if (this.table != null) {
2407
                this.table.accept(visitor, filter);
2408
            }
2409
        }
2410

    
2411
        @Override
2412
        public TableNameBuilder table() {
2413
            if (table == null) {
2414
                table = createTableNameBuilder();
2415
            }
2416
            return table;
2417
        }
2418

    
2419
        @Override
2420
        public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
2421
            this.columns.add(new ColumnDescriptorBase(fad));
2422
            return this;
2423
        }
2424

    
2425
        @Override
2426
        public CreateTableBuilderBase add_column(String columnName, int type, int size, int precision, int scale, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
2427
            if (StringUtils.isEmpty(columnName)) {
2428
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2429
            }
2430
            if (isPk || isAutomatic) {
2431
                allowNulls = false;
2432
            }
2433
            this.columns.add(new ColumnDescriptorBase(columnName, type, size, precision, scale, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
2434
            return this;
2435
        }
2436

    
2437
        @Override
2438
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
2439
            if (StringUtils.isEmpty(columnName)) {
2440
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2441
            }
2442
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
2443
            return this;
2444
        }
2445

    
2446
        @Override
2447
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
2448
            if (StringUtils.isEmpty(columnName)) {
2449
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
2450
            }
2451
            this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
2452
            return this;
2453
        }
2454

    
2455
        @Override
2456
        public ColumnDescriptor getColumnDescriptor(String columnName) {
2457
            if (StringUtils.isEmpty(columnName)) {
2458
                return null;
2459
            }
2460
            for (ColumnDescriptor column : columns) {
2461
                if (columnName.equals(column.getName())) {
2462
                    return column;
2463
                }
2464
            }
2465
            return null;
2466
        }
2467

    
2468
        @Override
2469
        public String toString() {
2470
            return this.toString(formatter());
2471
        }
2472

    
2473
        @Override
2474
        public String toString(Formatter<Value> formatter) {
2475
            if (formatter!=null && formatter.canApply(this)) {
2476
                return formatter.format(this);
2477
            }
2478
            StringBuilder builder = new StringBuilder();
2479
            boolean first = true;
2480
            for (String sql : toStrings(formatter)) {
2481
                if (StringUtils.isEmpty(sql)) {
2482
                    continue;
2483
                }
2484
                if (first) {
2485
                    first = false;
2486
                } else {
2487
                    builder.append("; ");
2488
                }
2489
                builder.append(sql);
2490
            }
2491
            return builder.toString();
2492
        }
2493

    
2494
        @Override
2495
        public List<String> toStrings() {
2496
            return this.toStrings(formatter());
2497
        }
2498

    
2499
        @Override
2500
        /*
2501
        Debe crear la tabla, y las clave primaria, pero "no" los indices.
2502
        */
2503
        public List<String> toStrings(Formatter formatter) {
2504
            List<String> sqls = new ArrayList<>();
2505
            /**
2506
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
2507
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
2508
             * column_constraint [ ... ] ] | table_constraint | LIKE
2509
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
2510
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
2511
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
2512
             *
2513
             * where column_constraint is:
2514
             *
2515
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
2516
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
2517
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
2518
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
2519
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2520
             *
2521
             * and table_constraint is:
2522
             *
2523
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
2524
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
2525
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
2526
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
2527
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
2528
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
2529
             */
2530
            
2531
            StringBuilder builder = new StringBuilder();
2532

    
2533
            builder.append("CREATE TABLE ");
2534
            builder.append(this.table.toString(formatter));
2535
            builder.append(" (");
2536
            boolean first = true;
2537
            for (ColumnDescriptor column : columns) {
2538
                if (first) {
2539
                    first = false;
2540
                } else {
2541
                    builder.append(", ");
2542
                }
2543
                builder.append(as_identifier(column.getName()));
2544
                builder.append(" ");
2545
                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
2546
                    builder.append("SERIAL");
2547
                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
2548
                    builder.append("BIGSERIAL");
2549
                } else {
2550
                    builder.append(sqltype(
2551
                            column.getType(),
2552
                            column.getSize(),
2553
                            column.getPrecision(),
2554
                            column.getScale(),
2555
                            column.getGeometryType(),
2556
                            column.getGeometrySubtype()
2557
                    )
2558
                    );
2559
                }
2560
                if (column.getDefaultValue() == null) {
2561
                    if (column.allowNulls()) {
2562
                        builder.append(" DEFAULT NULL");
2563
                    }
2564
                } else {
2565
                    builder.append(" DEFAULT '");
2566
                    builder.append(Objects.toString(column.getDefaultValue(),""));
2567
                    builder.append("'");
2568
                }
2569
                if (column.allowNulls()) {
2570
                    builder.append(" NULL");
2571
                } else {
2572
                    builder.append(" NOT NULL");
2573
                }
2574
                if (column.isPrimaryKey()) {
2575
                    builder.append(" PRIMARY KEY");
2576
                }
2577
            }
2578
            builder.append(" )");
2579
            sqls.add(builder.toString());
2580
            return sqls;
2581
        }
2582
    }
2583

    
2584
    public class InsertColumnBuilderBase
2585
            extends AbstractStatement
2586
            implements InsertColumnBuilder {
2587

    
2588
        protected Variable name;
2589
        protected Value value;
2590

    
2591
        public InsertColumnBuilderBase() {
2592
        }
2593

    
2594
        @Override
2595
        public void accept(Visitor visitor, VisitorFilter filter) {
2596
            if (filter==null || filter.accept(this)) {
2597
                visitor.visit(this);
2598
            }
2599
            if (this.name != null) {
2600
                this.name.accept(visitor, filter);
2601
            }
2602
            if (this.value != null) {
2603
                this.value.accept(visitor, filter);
2604
            }
2605
        }
2606

    
2607
        @Override
2608
        public InsertColumnBuilder name(String name) {
2609
            this.name = expression().variable(name);
2610
            return this;
2611
        }
2612

    
2613
        @Override
2614
        public InsertColumnBuilder with_value(Value value) {
2615
            this.value = value;
2616
            return this;
2617
        }
2618

    
2619
        @Override
2620
        public String getName() {
2621
            return this.name.name();
2622
        }
2623

    
2624
        @Override
2625
        public Value getValue() {
2626
            return this.value;
2627
        }
2628

    
2629
        @Override
2630
        public String toString() {
2631
            return this.toString(formatter());
2632
        }
2633

    
2634
        @Override
2635
        public String toString(Formatter<Value> formatter) {
2636
            if (formatter!=null && formatter.canApply(this)) {
2637
                return formatter.format(this);
2638
            }
2639
            return this.value.toString(formatter);
2640
        }
2641
    }
2642

    
2643
    public class InsertBuilderBase
2644
            extends AbstractStatement
2645
            implements InsertBuilder {
2646

    
2647
        protected List<InsertColumnBuilder> columns;
2648
        protected TableNameBuilder table;
2649

    
2650
        public InsertBuilderBase() {
2651
            this.columns = new ArrayList<>();
2652
        }
2653

    
2654
        @Override
2655
        public void accept(Visitor visitor, VisitorFilter filter) {
2656
            if (filter==null || filter.accept(this)) {
2657
                visitor.visit(this);
2658
            }
2659
            if (this.table != null) {
2660
                this.table.accept(visitor, filter);
2661
            }
2662
            for (InsertColumnBuilder column : columns) {
2663
                column.accept(visitor, filter);
2664
            }
2665
        }
2666

    
2667
        @Override
2668
        public TableNameBuilder table() {
2669
            if (table == null) {
2670
                table = createTableNameBuilder();
2671
            }
2672
            return table;
2673
        }
2674

    
2675
        @Override
2676
        public InsertColumnBuilder column() {
2677
            InsertColumnBuilder column = createInsertColumnBuilder();
2678
            this.columns.add(column);
2679
            return column;
2680
        }
2681

    
2682
        @Override
2683
        public String toString() {
2684
            return this.toString(formatter());
2685
        }
2686

    
2687
        @Override
2688
        public String toString(Formatter<Value> formatter) {
2689
            if (formatter!=null && formatter.canApply(this)) {
2690
                return formatter.format(this);
2691
            }
2692
            /*
2693
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
2694
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
2695
             * output_expression [ AS output_name ] [, ...] ]
2696
             */
2697
            StringBuilder builderColumns = new StringBuilder();
2698
            StringBuilder builderValues = new StringBuilder();
2699

    
2700
            boolean first = true;
2701
            for (InsertColumnBuilder column : columns) {
2702
                if (first) {
2703
                    first = false;
2704
                } else {
2705
                    builderColumns.append(", ");
2706
                }
2707
                builderColumns.append(as_identifier(column.getName()));
2708
            }
2709
            first = true;
2710
            for (InsertColumnBuilder column : columns) {
2711
                if (first) {
2712
                    first = false;
2713
                } else {
2714
                    builderValues.append(", ");
2715
                }
2716
                builderValues.append(column.toString(formatter));
2717
            }
2718

    
2719
            String sql = MessageFormat.format(
2720
                    STMT_INSERT_INTO_table_columns_VALUES_values,
2721
                    this.table.toString(formatter),
2722
                    builderColumns.toString(),
2723
                    builderValues.toString()
2724
            );
2725
            return sql;
2726

    
2727
        }
2728
    }
2729

    
2730
    public class UpdateTableStatisticsBuilderBase
2731
            extends AbstractStatement
2732
            implements UpdateTableStatisticsBuilder {
2733

    
2734
        protected TableNameBuilder table;
2735

    
2736
        @Override
2737
        public void accept(Visitor visitor, VisitorFilter filter) {
2738
            if (filter==null || filter.accept(this)) {
2739
                visitor.visit(this);
2740
            }
2741
            if (this.table != null) {
2742
                this.table.accept(visitor, filter);
2743
            }
2744
        }
2745

    
2746
        @Override
2747
        public TableNameBuilder table() {
2748
            if (table == null) {
2749
                table = createTableNameBuilder();
2750
            }
2751
            return table;
2752
        }
2753

    
2754
        @Override
2755
        public String toString() {
2756
            return this.toString(formatter());
2757
        }
2758

    
2759
        @Override
2760
        public String toString(Formatter<Value> formatter) {
2761
            if (formatter!=null && formatter.canApply(this)) {
2762
                return formatter.format(this);
2763
            }
2764
            StringBuilder builder = new StringBuilder();
2765
            boolean first = true;
2766
            for (String sql : toStrings(formatter)) {
2767
                if (StringUtils.isEmpty(sql)) {
2768
                    continue;
2769
                }
2770
                if (first) {
2771
                    first = false;
2772
                } else {
2773
                    builder.append("; ");
2774
                }
2775
                builder.append(sql);
2776
            }
2777
            return builder.toString();
2778
        }
2779

    
2780
        @Override
2781
        public List<String> toStrings() {
2782
            return this.toStrings(formatter());
2783
        }
2784

    
2785
        @Override
2786
        public List<String> toStrings(Formatter formatter) {
2787
            List<String> sqls = new ArrayList<>();
2788

    
2789
            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
2790
                String sql = MessageFormat.format(
2791
                        STMT_UPDATE_TABLE_STATISTICS_table,
2792
                        table.toString(formatter)
2793
                );
2794
                if (!StringUtils.isEmpty(sql)) {
2795
                    sqls.add(sql);
2796
                }
2797
            }
2798
            return sqls;
2799
        }
2800
    }
2801

    
2802
    protected GeometryExpressionBuilder expressionBuilder;
2803

    
2804
    protected String defaultSchema;
2805
    protected boolean supportSchemas;
2806
    protected boolean hasSpatialFunctions;
2807
    protected GeometrySupportType geometrySupportType;
2808
    protected boolean allowAutomaticValues;
2809

    
2810
    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
2811

    
2812
    protected String constant_true = "(1=1)";
2813
    protected String constant_false = "(1<>1)";
2814

    
2815
    protected String type_boolean = "BOOLEAN";
2816
    protected String type_byte = "TINYINT";
2817
    protected String type_bytearray = "BYTEA";
2818
    protected String type_geometry = "TEXT";
2819
    protected String type_char = "CHARACTER(1)";
2820
    protected String type_date = "DATE";
2821
    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
2822
    protected String type_decimal_ps = "NUMERIC({0,Number,##########},{1,Number,##########})";
2823
    protected String type_decimal_p = "NUMERIC({0,Number,##########})";
2824
    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
2825
    protected String type_int = "INT";
2826
    protected String type_long = "BIGINT";
2827
    protected String type_string = "TEXT";
2828
    protected String type_string_p = "VARCHAR({0,Number,#######})";
2829
    protected String type_time = "TIME";
2830
    protected String type_timestamp = "TIMESTAMP";
2831
    protected String type_version = "VARCHAR(30)";
2832
    protected String type_URI = "TEXT";
2833
    protected String type_URL = "TEXT";
2834
    protected String type_FILE = "TEXT";
2835
    protected String type_FOLDER = "TEXT";
2836

    
2837
    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
2838
    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
2839
    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
2840
    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
2841
    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
2842
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
2843
    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
2844
    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
2845
    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
2846
    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
2847

    
2848
    public SQLBuilderBase() {
2849
        this.expressionBuilder = GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2850

    
2851
        this.hasSpatialFunctions = false;
2852
        this.supportSchemas = true;
2853
        this.geometrySupportType = GeometrySupportType.WKT;
2854

    
2855
        this.defaultSchema = "public";
2856
        this.allowAutomaticValues = true;
2857

    
2858
    }
2859
    
2860
    @Override
2861
    public void setProperties(Class filter, final Object... values) {
2862
        this.expressionBuilder.setProperties(filter, values);
2863
        this.accept((Visitable v) -> {
2864
            for (int i = 0; i < values.length; i+=2) {
2865
                ((Value)v).setProperty((String) values[i], values[i+1]);
2866
            }
2867
        }, new ClassVisitorFilter(filter) );
2868
    }
2869

    
2870
    public String quote_for_identifiers() {
2871
        return "\"";
2872
    }
2873

    
2874
    public String quote_for_strings() {
2875
        return "'";
2876
    }
2877

    
2878
    @Override
2879
    public String as_identifier(String id) {
2880
        String quote = this.quote_for_identifiers();
2881
//        No se porque no esta disponible wrapIfMissing
2882
//        return StringUtils.wrapIfMissing(id,quote);
2883
        if (id.startsWith(quote)) {
2884
            return id;
2885
        }
2886
        return quote + id + quote;
2887

    
2888
    }
2889

    
2890
    @Override
2891
    public String as_string(String s) {
2892
        String quote = this.quote_for_strings();
2893
//        No se porque no esta disponible wrapIfMissing
2894
//        return StringUtils.wrapIfMissing(id,quote);
2895
        if (s.startsWith(quote)) {
2896
            return s;
2897
        }
2898
        return quote + s + quote;
2899

    
2900
    }
2901

    
2902
    @Override
2903
    public String as_string(byte[] data) {
2904
        return this.expressionBuilder.bytearray_0x(data);
2905
//        return this.expressionBuilder.bytearray_hex(data);
2906
//        return this.expressionBuilder.bytearray_x(data);
2907
    }
2908
    
2909
    @Override
2910
    public String as_string(boolean value) {
2911
        return value? "TRUE" : "FALSE";
2912
    }
2913

    
2914
    @Override
2915
    public String as_string(Number value) {
2916
        return Objects.toString(value);
2917
    }
2918
    
2919
    @Override
2920
    public String as_string(Object value) {
2921
        if( value == null ) {
2922
            return "NULL";
2923
        }
2924
        if( value instanceof CharSequence ) {
2925
            return as_string(value.toString());
2926
        }
2927
        if( value instanceof Number ) {
2928
            return as_string((Number)value);
2929
        }
2930
        if( value instanceof Boolean ) {
2931
            return as_string((boolean)value);
2932
        }
2933
        if( value instanceof byte[] ) {
2934
            return as_string((byte[])value);
2935
        }
2936
        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
2937
    }
2938
    
2939
    @Override
2940
    public GeometryExpressionBuilder expression() {
2941
        return this.expressionBuilder;
2942
    }
2943

    
2944
    @Override
2945
    public boolean has_spatial_functions() {
2946
        return this.hasSpatialFunctions;
2947
    }
2948

    
2949
    @Override
2950
    public GeometrySupportType geometry_support_type() {
2951
        return this.geometrySupportType;
2952
    }
2953

    
2954
    protected GeometryExpressionBuilder createExpressionBuilder() {
2955
        return GeometryExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2956
    }
2957

    
2958
    @Override
2959
    public Object srs_id(IProjection projection) {
2960
        String abrev = projection.getAbrev();
2961
        return abrev.split(":")[1].trim();
2962
    }
2963

    
2964
    @Override
2965
    public String default_schema() {
2966
        return this.defaultSchema;
2967
    }
2968

    
2969
    @Override
2970
    public boolean support_schemas() {
2971
        return this.supportSchemas;
2972
    }
2973

    
2974
    @Override
2975
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
2976
        switch (type) {
2977
            case DataTypes.BOOLEAN:
2978
                return type_boolean;
2979
            case DataTypes.CHAR:
2980
                return type_char;
2981

    
2982

    
2983
            case DataTypes.BYTE:
2984
                return type_byte;
2985
            case DataTypes.INT:
2986
                return type_int;
2987
            case DataTypes.LONG:
2988
                return type_long;
2989

    
2990
            case DataTypes.FLOAT:
2991
                return type_float;
2992
            case DataTypes.DOUBLE:
2993
                return type_double;
2994
            case DataTypes.DECIMAL:
2995
                if (precision < 1) {
2996
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
2997
                }
2998
                if (scale < 1) {
2999
                  return MessageFormat.format(type_decimal_p, precision);
3000
                }
3001
                return MessageFormat.format(type_decimal_ps, precision, scale);
3002

    
3003
                
3004
            case DataTypes.STRING:
3005
                if (size < 0) {
3006
                    return type_string;
3007
                } else if (size < DataManager.RECOMENDED_SIZE_FOR_CLOB) {
3008
                    return MessageFormat.format(type_string_p, size);
3009
                }
3010
                return type_string;
3011

    
3012
                
3013
            case DataTypes.DATE:
3014
                return type_date;
3015
            case DataTypes.TIME:
3016
                return type_time;
3017
            case DataTypes.TIMESTAMP:
3018
                return type_timestamp;
3019

    
3020
            case DataTypes.BYTEARRAY:
3021
                return type_bytearray;
3022

    
3023
            case DataTypes.GEOMETRY:
3024
                return type_geometry;
3025

    
3026
            case DataTypes.VERSION:
3027
                return type_version;
3028
            case DataTypes.URI:
3029
                return type_URI;
3030
            case DataTypes.URL:
3031
                return type_URL;
3032
            case DataTypes.FILE:
3033
                return type_FILE;
3034
            case DataTypes.FOLDER:
3035
                return type_FOLDER;
3036
            default:
3037
                return null;
3038
        }
3039
    }
3040

    
3041
    @Override
3042
    public Object sqlgeometrytype(int type, int subtype) {
3043
        // Devuelve un Object por que algunos gestores de BBDD utilizan
3044
        // identificadores numericos para el tipo y otros strings.
3045
        // Por defecto vamos a devolver strings.
3046
        if (sqlgeometrytypes == null) {
3047
            sqlgeometrytypes = new HashMap<>();
3048
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
3049
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
3050
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
3051
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
3052

    
3053
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
3054
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
3055
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
3056
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
3057

    
3058
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
3059
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
3060
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
3061
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
3062

    
3063
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
3064
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
3065
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
3066
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
3067

    
3068
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3069
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3070
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3071
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3072

    
3073
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
3074
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
3075
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
3076
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
3077

    
3078
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3079
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3080
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3081
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3082

    
3083
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
3084
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
3085
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
3086
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
3087

    
3088
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
3089
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
3090
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
3091
            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
3092
        }
3093
        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
3094
    }
3095

    
3096
    @Override
3097
    public Object sqlgeometrydimension(int type, int subtype) {
3098
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
3099
        // identificadores numericos para las dimensiones y otros strings.
3100
        // Por defecto vamos a devolver enteros.
3101
        switch (subtype) {
3102
            case Geometry.SUBTYPES.GEOM3D:
3103
                return 3;
3104
            case Geometry.SUBTYPES.GEOM2DM:
3105
                return 3;
3106
            case Geometry.SUBTYPES.GEOM3DM:
3107
                return 4;
3108
            case Geometry.SUBTYPES.GEOM2D:
3109
            default:
3110
                return 2;
3111
        }
3112
    }
3113

    
3114
    @Override
3115
    public TableNameBuilder createTableNameBuilder() {
3116
        return new TableNameBuilderBase();
3117
    }
3118

    
3119
    protected SelectColumnBuilder createSelectColumnBuilder() {
3120
        return new SelectColumnBuilderBase(this);
3121
    }
3122

    
3123
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
3124
        return new UpdateColumnBuilderBase();
3125
    }
3126

    
3127
    protected InsertColumnBuilder createInsertColumnBuilder() {
3128
        return new InsertColumnBuilderBase();
3129
    }
3130

    
3131
    protected OrderByBuilder createOrderByBuilder() {
3132
        return new OrderByBuilderBase();
3133
    }
3134

    
3135
    protected FromBuilder createFromBuilder() {
3136
        return new FromBuilderBase();
3137
    }
3138

    
3139
    protected SelectBuilder createSelectBuilder() {
3140
        return new SelectBuilderBase();
3141
    }
3142

    
3143
    protected UpdateBuilder createUpdateBuilder() {
3144
        return new UpdateBuilderBase();
3145
    }
3146

    
3147
    protected DeleteBuilder createDeleteBuilder() {
3148
        return new DeleteBuilderBase();
3149
    }
3150

    
3151
    protected GrantBuilder createGrantBuilder() {
3152
        return new GrantBuilderBase();
3153
    }
3154

    
3155
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
3156
        return new GrantRoleBuilderBase(table, role);
3157
    }
3158

    
3159
    protected DropTableBuilder createDropTableBuilder() {
3160
        return new DropTableBuilderBase();
3161
    }
3162

    
3163
    protected CreateTableBuilder createCreateTableBuilder() {
3164
        return new CreateTableBuilderBase();
3165
    }
3166

    
3167
    protected AlterTableBuilder createAlterTableBuilder() {
3168
        return new AlterTableBuilderBase();
3169
    }
3170

    
3171
    protected InsertBuilder createInsertBuilder() {
3172
        return new InsertBuilderBase();
3173
    }
3174

    
3175
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
3176
        return new UpdateTableStatisticsBuilderBase();
3177
    }
3178

    
3179
    protected CreateIndexBuilder createCreateIndexBuilder() {
3180
        return new CreateIndexBuilderBase();
3181
    }
3182

    
3183
    protected DropIndexBuilder createDropIndexBuilder() {
3184
        return new DropIndexBuilderBase();
3185
    }
3186

    
3187
    @Override
3188
    public SelectBuilder select() {
3189
        if (this.select == null) {
3190
            this.select = this.createSelectBuilder();
3191
        }
3192
        return this.select;
3193
    }
3194

    
3195
    @Override
3196
    public UpdateBuilder update() {
3197
        if (this.update == null) {
3198
            this.update = this.createUpdateBuilder();
3199
        }
3200
        return this.update;
3201
    }
3202

    
3203
    @Override
3204
    public UpdateTableStatisticsBuilder update_table_statistics() {
3205
        if (this.update_table_statistics == null) {
3206
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
3207
        }
3208
        return this.update_table_statistics;
3209
    }
3210

    
3211
    @Override
3212
    public DropTableBuilder drop_table() {
3213
        if (this.drop_table == null) {
3214
            this.drop_table = this.createDropTableBuilder();
3215
        }
3216
        return this.drop_table;
3217
    }
3218

    
3219
    @Override
3220
    public CreateIndexBuilder create_index() {
3221
        if (this.create_index == null) {
3222
            this.create_index = this.createCreateIndexBuilder();
3223
        }
3224
        return this.create_index;
3225
    }
3226

    
3227
    @Override
3228
    public DropIndexBuilder drop_index() {
3229
        if (this.drop_index == null) {
3230
            this.drop_index = this.createDropIndexBuilder();
3231
        }
3232
        return this.drop_index;
3233
    }
3234

    
3235
    @Override
3236
    public DeleteBuilder delete() {
3237
        if (this.delete == null) {
3238
            this.delete = this.createDeleteBuilder();
3239
        }
3240
        return this.delete;
3241
    }
3242

    
3243
    @Override
3244
    public InsertBuilder insert() {
3245
        if (this.insert == null) {
3246
            this.insert = this.createInsertBuilder();
3247
        }
3248
        return this.insert;
3249
    }
3250

    
3251
    @Override
3252
    public TableNameBuilder table_name() {
3253
        if (this.table_name == null) {
3254
            this.table_name = this.createTableNameBuilder();
3255
        }
3256
        return this.table_name;
3257
    }
3258

    
3259
    
3260
    @Override
3261
    public AlterTableBuilder alter_table() {
3262
        if (this.alter_table == null) {
3263
            this.alter_table = this.createAlterTableBuilder();
3264
        }
3265
        return this.alter_table;
3266
    }
3267

    
3268
    @Override
3269
    public CreateTableBuilder create_table() {
3270
        if (this.create_table == null) {
3271
            this.create_table = this.createCreateTableBuilder();
3272
        }
3273
        return this.create_table;
3274
    }
3275

    
3276
    @Override
3277
    public GrantBuilder grant() {
3278
        if (this.grant == null) {
3279
            this.grant = this.createGrantBuilder();
3280
        }
3281
        return this.grant;
3282
    }
3283
    
3284
    @Override
3285
    public Column column(String name) {
3286
        ColumnBase col = new ColumnBase(null, name);
3287
        return col;
3288
    }
3289

    
3290
    @Override
3291
    public Column column(TableNameBuilder table, String name) {
3292
        ColumnBase col = new ColumnBase(table, name);
3293
        return col;
3294
    }
3295
    
3296
    protected JoinBase createJoin(String type, TableNameBuilder table, Value expression) {
3297
        return new JoinBase(type, table, expression);
3298
    }
3299

    
3300
    public void accept(Visitor visitor, VisitorFilter filter) {
3301
        if (this.select != null) {
3302
            this.select.accept(visitor, filter);
3303
        }
3304
        if (this.update != null) {
3305
            this.update.accept(visitor, filter);
3306
        }
3307
        if (this.insert != null) {
3308
            this.insert.accept(visitor, filter);
3309
        }
3310
        if (this.delete != null) {
3311
            this.delete.accept(visitor, filter);
3312
        }
3313
        if (this.alter_table != null) {
3314
            this.alter_table.accept(visitor, filter);
3315
        }
3316
        if (this.create_table != null) {
3317
            this.create_table.accept(visitor, filter);
3318
        }
3319
        if (this.drop_table != null) {
3320
            this.drop_table.accept(visitor, filter);
3321
        }
3322
        if (this.table_name != null) {
3323
            this.table_name.accept(visitor, filter);
3324
        }
3325
    }
3326

    
3327
        @Override
3328
    public Formatter formatter() {
3329
        return expression().formatter();
3330
    }
3331

    
3332
    @Override
3333
    public String toString() {
3334
        return this.toString(formatter());
3335
    }
3336

    
3337
    @Override
3338
    public String toString(Formatter formatter) {
3339
        if (this.select != null) {
3340
            return this.select.toString(formatter);
3341
        }
3342
        if (this.update != null) {
3343
            return this.update.toString(formatter);
3344
        }
3345
        if (this.insert != null) {
3346
            return this.insert.toString(formatter);
3347
        }
3348
        if (this.delete != null) {
3349
            return this.delete.toString(formatter);
3350
        }
3351
        if (this.alter_table != null) {
3352
            return this.alter_table.toString(formatter);
3353
        }
3354
        if (this.create_table != null) {
3355
            return this.create_table.toString(formatter);
3356
        }
3357
        if (this.drop_table != null) {
3358
            return this.drop_table.toString(formatter);
3359
        }
3360
        if (this.update_table_statistics != null) {
3361
            return this.update_table_statistics.toString(formatter);
3362
        }
3363
        if (this.create_index != null) {
3364
            return this.create_index.toString(formatter);
3365
        }
3366
        if (this.drop_index != null) {
3367
            return this.drop_index.toString(formatter);
3368
        }
3369
        if (this.table_name != null) {
3370
            return this.table_name.toString(formatter);
3371
        }
3372
        return "";
3373
    }
3374

    
3375
    @Override
3376
    public CountBuilder count() {
3377
        return new CountBuilderBase();
3378
    }
3379

    
3380
    @Override
3381
    public List<Parameter> parameters() {
3382
        final List<Parameter> params = new ArrayList<>();
3383
        this.accept((Visitable value) -> {
3384
            params.add((Parameter) value);
3385
        }, new ClassVisitorFilter(Parameter.class));
3386
        return params;
3387
    }
3388

    
3389
    @Override
3390
    public List<Variable> variables() {
3391
        final List<Variable> vars = new ArrayList<>();
3392
        this.accept(new Visitor() {
3393
            @Override
3394
            public void visit(Visitable value) {
3395
                if (!vars.contains((Variable) value)) {
3396
                    vars.add((Variable) value);
3397
                }
3398
            }
3399
        }, new ClassVisitorFilter(Variable.class));
3400
        return vars;
3401
    }
3402

    
3403
    @Override
3404
    public List<String> parameters_names() {
3405
        List<String> params = new ArrayList<>();
3406
        for (Parameter param : parameters()) {
3407
            String s;
3408
            switch (param.type()) {
3409
                case PARAMETER_TYPE_CONSTANT:
3410
                    Object theValue = param.value();
3411
                    if (theValue == null) {
3412
                        s = "null";
3413
                    } else if (theValue instanceof String) {
3414
                        s = "'" + (String) theValue + "'";
3415
                    } else {
3416
                        s = theValue.toString();
3417
                    }
3418
                    break;
3419
                case PARAMETER_TYPE_VARIABLE:
3420
                default:
3421
                    s = "\"" + param.name() + "\"";
3422
            }
3423
            params.add(s);
3424
        }
3425
        return params;
3426
    }
3427

    
3428
    @Override
3429
    public List<String> variables_names() {
3430
        List<String> vars = new ArrayList<>();
3431
        for (Variable var : this.variables()) {
3432
            vars.add(var.name());
3433
        }
3434
        Collections.sort(vars);
3435
        return vars;
3436
    }    
3437
    
3438
    protected String[] aggregateFunctionNames = new String[] {
3439
        "MAX",
3440
        "MIN",
3441
        "COUNT",
3442
        "SUM"
3443
    };
3444
    
3445
    @Override
3446
    public boolean isAggregateFunction(String funcname) {
3447
        for (String aggregateFunctionName : this.aggregateFunctionNames) {
3448
            if( StringUtils.equalsIgnoreCase(aggregateFunctionName, funcname)) {
3449
                return true;
3450
            }
3451
        }
3452
        return false;
3453
    }
3454

    
3455
    @Override
3456
    public int getMaxRecomendedSQLLength() {
3457
        return DEFAULT_RECOMENDED_SQL_LENGTH;
3458
    }
3459
    
3460
    
3461
}