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

History | View | Annotate | Download (78 KB)

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

    
3
import java.text.MessageFormat;
4
import java.util.ArrayList;
5
import java.util.HashMap;
6
import java.util.HashSet;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.Set;
10
import org.apache.commons.lang3.StringUtils;
11
import org.apache.commons.lang3.tuple.ImmutablePair;
12
import org.apache.commons.lang3.tuple.Pair;
13
import org.cresques.cts.IProjection;
14
import org.gvsig.fmap.dal.DataTypes;
15
import org.gvsig.fmap.dal.ExpressionBuilder;
16
import org.gvsig.fmap.dal.SQLBuilder;
17
import org.gvsig.fmap.dal.SQLBuilder.AlterTableBuilder;
18
import org.gvsig.fmap.dal.SQLBuilder.CreateTableBuilder;
19
import org.gvsig.fmap.dal.SQLBuilder.DeleteBuilder;
20
import org.gvsig.fmap.dal.SQLBuilder.DropTableBuilder;
21
import org.gvsig.fmap.dal.SQLBuilder.FromBuilder;
22
import org.gvsig.fmap.dal.SQLBuilder.GrantBuilder;
23
import org.gvsig.fmap.dal.SQLBuilder.InsertBuilder;
24
import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
25
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
26
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
27
import org.gvsig.fmap.dal.SQLBuilder.SQLConfig;
28
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
29
import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
30
import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
31
import org.gvsig.fmap.dal.SQLBuilder.UpdateBuilder;
32
import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
33
import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
34
import org.gvsig.fmap.dal.feature.spi.ExpressionBuilderBase.AbstractValue;
35
import org.gvsig.fmap.geom.Geometry;
36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38

    
39
public class SQLBuilderBase extends ExpressionBuilderBase implements SQLBuilder {
40
    
41
    protected static final Logger logger = LoggerFactory.getLogger(SQLBuilderBase.class);
42
    
43
    protected SelectBuilder select;
44
    protected UpdateBuilder update;
45
    protected InsertBuilder insert;
46
    protected DeleteBuilder delete;
47
    protected AlterTableBuilder alter_table;
48
    protected CreateTableBuilder create_table;
49
    protected GrantBuilder grant;
50
    protected DropTableBuilder drop_table;
51
    protected UpdateTableStatisticsBuilder update_table_statistics;
52
    protected List<Parameter> parameters;
53

    
54
    protected class ColumnDescriptorBuilderBase implements ColumnDescriptorBuilder {
55

    
56
        private String name;
57
        private int type;
58
        private int type_p;
59
        private int type_s;
60
        private boolean isPk;
61
        private boolean _allowNulls;
62
        private boolean _isAutomatic;
63
        private Object defaultValue;
64
        private int geom_type;
65
        private int geom_subtype;
66
        private int geom_srsid;
67
        private boolean _isIndexed;
68

    
69
        public ColumnDescriptorBuilderBase(String name, int type, Object defaultValue) {
70
            this.name = name;
71
            this.type = type;
72
            this.type_p = -1;
73
            this.type_s = -1;
74
            this.isPk = false;
75
            this._allowNulls = true;
76
            this._isAutomatic = false;
77
            this.defaultValue = defaultValue;
78
            this.geom_type = Geometry.TYPES.GEOMETRY;
79
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
80
            this.geom_srsid = -1;
81
            this._isIndexed = false;
82
        }
83

    
84
        public ColumnDescriptorBuilderBase(String name, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
85
            this.name = name;
86
            this.type = type;
87
            this.type_p = type_p;
88
            this.type_s = type_s;
89
            this.isPk = isPk;
90
            this._allowNulls = allowNulls;
91
            this._isAutomatic = isAutomatic;
92
            this.defaultValue = defaultValue;
93
            this.geom_type = Geometry.TYPES.GEOMETRY;
94
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
95
            this.geom_srsid = -1;
96
            this._isIndexed = isIndexed;
97
        }
98
        
99
        public ColumnDescriptorBuilderBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
100
            this.name = name;
101
            this.type = DataTypes.GEOMETRY;
102
            this.type_p = 0;
103
            this.type_s = 0;
104
            this.isPk = false;
105
            this._allowNulls = allowNulls;
106
            this._isAutomatic = false;
107
            this.defaultValue = null;
108
            this.geom_type = geom_type;
109
            this.geom_subtype = geom_subtype;
110
            this.geom_srsid = getSRSId(proj);
111
            this._isIndexed = isIndexed;
112
        }
113
        
114
        @Override
115
        public String getName() {
116
            return this.name;
117
        }
118
        
119
        @Override
120
        public void setName(String name) {
121
            this.name = name;
122
        }
123

    
124
        @Override
125
        public int getType() {
126
            return this.type;
127
        }
128

    
129
        @Override
130
        public void setType(int type) {
131
            this.type = type;
132
        }
133

    
134
        @Override
135
        public int getPrecision() {
136
            return type_p;
137
        }
138

    
139
        @Override
140
        public void setPrecision(int precision) {
141
            this.type_p = precision;
142
        }
143

    
144
        @Override
145
        public int getSize() {
146
            return type_s;
147
        }
148

    
149
        @Override
150
        public void setSize(int size) {
151
            this.type_s = size;
152
        }
153

    
154
        @Override
155
        public boolean isPrimaryKey() {
156
            return isPk;
157
        }
158

    
159
        @Override
160
        public void setIsPrimaryKey(boolean isPk) {
161
            this.isPk = isPk;
162
        }
163

    
164
        @Override
165
        public boolean allowNulls() {
166
            return _allowNulls;
167
        }
168

    
169
        @Override
170
        public void setAllowNulls(boolean allowNulls) {
171
            this._allowNulls = allowNulls;
172
        }
173

    
174
        @Override
175
        public boolean isAutomatic() {
176
            return _isAutomatic;
177
        }
178

    
179
        @Override
180
        public boolean isIndexed() {
181
            return _isIndexed;
182
        }
183

    
184
        @Override
185
        public void setIsAutomatic(boolean isAutomatic) {
186
            this._isAutomatic = isAutomatic;
187
        }
188

    
189
        @Override
190
        public Object getDefaultValue() {
191
            return defaultValue;
192
        }
193

    
194
        @Override
195
        public void setDefaultValue(Object defaultValue) {
196
            this.defaultValue = defaultValue;
197
        }
198

    
199
        @Override
200
        public int getGeometryType() {
201
            return geom_type;
202
        }
203

    
204
        @Override
205
        public void setGeometryType(int geom_type) {
206
            this.geom_type = geom_type;
207
        }
208

    
209
        @Override
210
        public int getGeometrySubtype() {
211
            return geom_subtype;
212
        }
213

    
214
        @Override
215
        public void setGeometrySubtype(int geom_subtype) {
216
            this.geom_subtype = geom_subtype;
217
        }
218

    
219
        @Override
220
        public int getGeometrySRSId() {
221
            return geom_srsid;
222
        }
223

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

    
229
        @Override
230
        public boolean isGeometry() {
231
            return this.type == DataTypes.GEOMETRY;
232
        }
233
                
234
    }
235
    
236

    
237
    public class TableNameBuilderBase implements TableNameBuilder {
238

    
239
        public String tableName;
240
        public String schemaName;
241
        private String databaseName;
242

    
243
        public TableNameBuilderBase() {
244
        }
245

    
246
        @Override
247
        public void accept(Visitor visitor, VisitorFilter filter) {
248
            if( filter.accept(this) ) {
249
                visitor.visit(this);
250
            }
251
        }
252

    
253
        @Override
254
        public TableNameBuilder database(String name) {
255
            this.databaseName = name;
256
            return this;
257
        }
258

    
259
        @Override
260
        public TableNameBuilder schema(String name) {
261
            if( supportSchemas() ) {
262
                this.schemaName = name;
263
            }
264
            return this;
265
        }
266

    
267
        @Override
268
        public TableNameBuilder name(String name) {
269
            this.tableName = name;
270
            return this;
271
        }
272

    
273
        @Override
274
        public String getDatabase() {
275
            return this.databaseName;
276
        }
277

    
278
        @Override
279
        public String getSchema() {
280
            return this.schemaName;
281
        }
282

    
283
        @Override
284
        public String getName() {
285
            return this.tableName;
286
        }
287
        
288
        @Override
289
        public boolean has_schema() {
290
            if( !supportSchemas() ) {
291
                return false;
292
            }
293
            return !StringUtils.isEmpty(this.schemaName);
294
        }
295

    
296
        @Override
297
        public boolean has_database() {
298
            return !StringUtils.isEmpty(this.databaseName);
299
        }
300
        
301
        @Override
302
        public String toString() {
303
            if( this.has_database()) {
304
                if( this.has_schema()) {
305
                    return identifier(this.databaseName) + "." + 
306
                           identifier(this.schemaName) + "." + 
307
                           identifier(this.tableName);
308
                }
309
            } else {
310
                if( this.has_schema()) {
311
                    return identifier(this.schemaName) + "." + 
312
                           identifier(this.tableName);
313
                }                
314
            }
315
            return identifier(this.tableName);
316
        }
317

    
318
    }
319

    
320
    public class CountBuilderBase extends AbstractValue implements CountBuilder {
321

    
322
        protected Value value;
323
        protected boolean distinct;
324
        protected boolean all ;
325
        
326
        public CountBuilderBase() {
327
            this.value = null;
328
            this.distinct = false;
329
            this.all = false;
330
        }
331
        
332
        @Override
333
        public CountBuilder all() {
334
            this.all = true;
335
            return this;
336
        }
337

    
338
        @Override
339
        public CountBuilder column(Value value) {
340
            this.value = value;
341
            return this;
342
        }
343

    
344
        @Override
345
        public CountBuilder distinct() {
346
            this.distinct = true;
347
            return this;
348
        }
349

    
350
        @Override
351
        public String toString() {
352
            if( this.all ) {
353
                return MessageFormat.format(
354
                    config.getString(SQLConfig.count),
355
                    "*"
356
                );
357
            }
358
            if( this.distinct ) {
359
                return MessageFormat.format(
360
                    config.getString(SQLConfig.count_distinct),
361
                    value.toString()
362
                );
363
            }
364
            return MessageFormat.format(
365
                config.getString(SQLConfig.count),
366
                value.toString()
367
            );
368
        }
369
        
370
        
371
    }
372
    
373
    public class FromBuilderBase implements FromBuilder {
374

    
375
        protected TableNameBuilder tableName= null;
376
        private String subquery = null;
377
        private String passthrough = null;
378

    
379
        @Override
380
        public TableNameBuilder table() {
381
            if( tableName == null ) {
382
                this.tableName = createTableNameBuilder();
383
            }
384
            return this.tableName;
385
        }
386

    
387
        @Override
388
        public void accept(Visitor visitor, VisitorFilter filter) {
389
            if( filter.accept(this) ) {
390
                visitor.visit(this);
391
            }
392
            if( this.tableName != null ) {
393
                this.tableName.accept(visitor, filter);
394
            }
395
        }
396

    
397
        @Override
398
        public FromBuilder custom(String passthrough) {
399
            this.passthrough = passthrough;
400
            return this;
401
        }
402

    
403
        @Override
404
        public FromBuilder subquery(String subquery) {
405
            this.subquery = subquery;
406
            return this;
407
        }
408
        
409
        @Override
410
        public String toString() {
411
            if( ! StringUtils.isEmpty(passthrough) ) {
412
                return passthrough;
413
            }
414
            if( ! StringUtils.isEmpty(subquery) ) {
415
                return "( " + this.subquery + ") as _subquery_alias_ ";
416
            }
417
            return this.tableName.toString();
418
        }
419

    
420
    }
421

    
422
    public class SelectColumnBuilderBase implements SelectColumnBuilder {
423

    
424
        private Variable name = null;
425
        private String alias = null;
426
        private Value value = null;
427
        private boolean asGeometry = false;
428
        
429
        @Override
430
        public void accept(Visitor visitor, VisitorFilter filter) {
431
            if( filter.accept(this) ) {
432
                visitor.visit(this);
433
            }
434
            if( this.name != null ) {
435
                this.name.accept(visitor, filter);
436
            }
437
            if( this.value != null ) {
438
                this.value.accept(visitor, filter);
439
            }
440
        }
441

    
442
        @Override
443
        public SelectColumnBuilder name(String name) {
444
            String quote = config.getString(Config.quote_for_identifiers);
445
            if (name.startsWith(quote)) {
446
                // Remove quotes
447
                name = name.substring(1, name.length() - 1);
448
            }
449
            this.name = variable(name);
450
            this.value = null;
451
            this.asGeometry = false;
452
            return this;
453
        }
454

    
455
        @Override
456
        public SelectColumnBuilder all() {
457
            this.name = null;
458
            this.value = custom("*");
459
            this.asGeometry = false;
460
            return this;
461
        }
462
        
463
        @Override
464
        public SelectColumnBuilder as_geometry() {
465
            this.asGeometry = true;
466
            return this;
467
        }
468
       
469
        @Override
470
        public SelectColumnBuilder value(Value value) {
471
            this.value = value;
472
            this.name = null;
473
            return this;
474
        }
475

    
476
        @Override
477
        public SelectColumnBuilder as(String alias) {
478
            this.alias = alias;
479
            return this;
480
        }
481

    
482
        @Override
483
        public String getName() {
484
            return this.name.getName();
485
        }
486
        
487
        @Override
488
        public String getAlias() {
489
            return this.alias;
490
        }
491
        
492
        @Override
493
        public String getValue() {
494
            return this.alias;
495
        }
496

    
497
        @Override
498
        public String toString() {
499
            StringBuilder builder = new StringBuilder();
500
            if( this.asGeometry ) {
501
                builder.append(getAsGeometry(this.name).toString());
502
            } else {
503
                if( this.name != null ) {
504
                    builder.append(this.name.toString());
505
                } else {
506
                    builder.append(this.value.toString());
507
                }
508
            }
509
            if( this.alias != null ) {
510
                builder.append(" AS ");
511
                builder.append(identifier(this.alias));
512
            }
513
            return builder.toString();
514
        }
515
    }
516

    
517
    public class OrderByBuilderBase implements OrderByBuilder {
518
        protected String value;
519
        protected String custom;
520
        protected boolean ascending;
521
        
522
        public OrderByBuilderBase() {
523
            this.ascending = true;
524
        }
525

    
526
        @Override
527
        public void accept(Visitor visitor, VisitorFilter filter) {
528
            if( filter.accept(this) ) {
529
                visitor.visit(this);
530
            }
531
        }
532

    
533
        @Override
534
        public OrderByBuilder column(String name) {
535
            this.value = name;
536
            return this;
537
        }
538

    
539
        @Override
540
        public OrderByBuilder custom(String order) {
541
            this.custom = order;
542
            return this;
543
        }
544

    
545
        @Override
546
        public OrderByBuilder ascending() {
547
            this.ascending = true;
548
            return this;
549
        }
550

    
551
        @Override
552
        public OrderByBuilder ascending(boolean asc) {
553
            this.ascending = asc;
554
            return this;
555
        }
556

    
557
        @Override
558
        public OrderByBuilder descending() {
559
            this.ascending = false;
560
            return this;
561
        }
562

    
563
        @Override
564
        public String toString() {
565
            if( !StringUtils.isEmpty(this.custom) ) {
566
                return this.custom;
567
            }
568
            if( this.ascending ) {
569
                return this.value + " ASC";
570
            }
571
            return this.value + " DESC";
572
        }
573
    }
574
    
575
    public class SelectBuilderBase implements SelectBuilder {
576

    
577
        protected FromBuilder from;
578
        protected ExpressionBuilder where;
579
        protected long limit = -1;
580
        protected long offset = -1;
581
        protected List<SelectColumnBuilder> columns;
582
        protected List<OrderByBuilder> order_by;
583
        protected boolean distinct;
584

    
585
        public SelectBuilderBase() {
586
            this.columns = new ArrayList<>();
587
            this.distinct = false;
588
        }
589

    
590
        @Override
591
        public void accept(Visitor visitor, VisitorFilter filter) {
592
            if( filter.accept(this) ) {
593
                visitor.visit(this);
594
            }
595
            for (SelectColumnBuilder column : columns) {
596
                column.accept(visitor,filter);
597
            }
598
            if( this.has_from() ) {
599
                this.from.accept(visitor,filter);
600
            }
601
            if( this.has_where() ) {
602
                this.where.accept(visitor,filter);
603
            }
604
            if( this.has_order_by() ) {
605
                for (OrderByBuilder order : order_by) {
606
                    order.accept(visitor,filter);
607
                }
608
            }
609
        }
610

    
611
        @Override
612
        public SelectBuilder distinct() {
613
            this.distinct = true;
614
            return this;
615
        }
616
        
617
        @Override
618
        public SelectColumnBuilder column() {
619
            SelectColumnBuilder builder = createSelectColumnBuilder();
620
            this.columns.add(builder);
621
            return builder;
622
        }
623

    
624
        @Override
625
        public boolean has_column(String name) {
626
            for (SelectColumnBuilder column : columns) {
627
                if( name.equals(column.getName()) ) {
628
                    return true;
629
                }
630
            }
631
            return false;
632
        }
633

    
634
        @Override
635
        public FromBuilder from() {
636
            if (this.from == null) {
637
                this.from = createFromBuilder();
638
            }
639
            return this.from;
640
        }
641

    
642
        @Override
643
        public boolean has_from() {
644
            return this.from != null;
645
        }
646
        
647
        @Override
648
        public ExpressionBuilder where() {
649
            if (this.where == null) {
650
                this.where = createExpressionBuilder();
651
            }
652
            return this.where;
653
        }
654

    
655
        @Override
656
        public boolean has_where() {
657
            if( this.where == null ) {
658
                return false;
659
            }
660
            return this.where.getValue() != null;
661
        }
662
        
663
        @Override
664
        public SelectBuilder limit(long limit) {
665
            this.limit = limit;
666
            return this;
667
        }
668

    
669
        @Override
670
        public boolean has_limit() {
671
            return this.limit > 0;
672
        }
673

    
674
        @Override
675
        public SelectBuilder offset(long offset) {
676
            this.offset = offset;
677
            return this;
678
        }
679

    
680
        @Override
681
        public boolean has_offset() {
682
            return this.offset > 0;
683
        }
684

    
685
        @Override
686
        public OrderByBuilder order_by() {
687
            if( this.order_by == null ) {
688
                this.order_by = new ArrayList<>();
689
            }
690
            OrderByBuilder order = createOrderByBuilder();
691
            this.order_by.add(order);
692
            return order;
693
        }
694

    
695
        @Override
696
        public boolean has_order_by() {
697
            if( this.order_by == null ) {
698
                return false;
699
            }
700
            return !this.order_by.isEmpty();
701
        }
702
        
703
        protected boolean isValid(StringBuilder message) {
704
            if( message == null ) {
705
                message = new StringBuilder();
706
            }
707
            if( this.has_offset() && !this.has_order_by() ) {
708
                // Algunos gestores de BBDD requieren que se especifique un
709
                // orden para poder usar OFFSET. Como eso parece buena idea para
710
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
711
                // siempre.
712
                message.append("Can't use OFFSET without an ORDER BY.");
713
                return false;
714
            }
715
            return true;
716
        }
717
        
718
        @Override
719
        public String toString() {
720
            StringBuilder builder = new StringBuilder();
721
            if( !this.isValid(builder) ) {
722
                throw new IllegalStateException(builder.toString());
723
            }
724
            builder.append("SELECT ");
725
            if( this.distinct ) {
726
                builder.append("DISTINCT ");
727
            }
728
            boolean first = true;
729
            for (SelectColumnBuilder column : columns) {
730
                if (first) {
731
                    first = false;
732
                } else {
733
                    builder.append(", ");
734
                }
735
                builder.append(column.toString());
736
            }
737

    
738
            if ( this.has_from() ) {
739
                builder.append(" FROM ");
740
                builder.append(this.from.toString());
741
            }
742
            if ( this.has_where() ) {
743
                builder.append(" WHERE ");
744
                builder.append(this.where.toString());
745
            }
746
            
747
            if( this.has_order_by() ) {
748
                builder.append(" ORDER BY ");
749
                first = true;
750
                for (OrderByBuilder item : this.order_by) {
751
                    if (first) {
752
                        first = false;
753
                    } else {
754
                        builder.append(", ");
755
                    }
756
                    builder.append(item.toString());                    
757
                }   
758
            }
759
            
760
            if ( this.has_limit() ) {
761
                builder.append(" LIMIT ");
762
                builder.append(this.limit);
763
            }
764
            if ( this.has_offset() ) {
765
                builder.append(" OFFSET ");
766
                builder.append(this.offset);
767
            }
768
            return builder.toString();
769

    
770
        }
771
    }
772

    
773
    public class DropTableBuilderBase implements DropTableBuilder {
774

    
775
        protected TableNameBuilder table;
776

    
777
        @Override
778
        public TableNameBuilder table() {
779
            if( table == null ) {
780
                table = createTableNameBuilder();
781
            }
782
            return table;
783
        }
784

    
785
        @Override
786
        public void accept(Visitor visitor, VisitorFilter filter) {
787
            if( filter.accept(this) ) {
788
                visitor.visit(this);
789
            }
790
            this.table.accept(visitor,filter);
791
        }
792
        
793
        @Override
794
        public String toString() {
795
            StringBuilder builder = new StringBuilder();
796
            boolean first = true;
797
            for (String sql : toStrings()) {
798
                if( StringUtils.isEmpty(sql) ) {
799
                    continue;
800
                }
801
                if (first) {
802
                    first = false;
803
                } else {
804
                    builder.append("; ");
805
                }
806
                builder.append(sql);
807
            }
808
            return builder.toString();
809
        }
810

    
811
        @Override
812
        public List<String> toStrings() {
813
            List<String> sqls = new ArrayList<>();
814

    
815
            sqls.add(
816
                    MessageFormat.format(
817
                            config.getString(SQLConfig.DROP_TABLE_table),
818
                            this.table.toString()
819
                    )
820
            );
821
            String sql;
822
            if( config.has_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table) ) {
823
                if (this.table.has_schema()) {
824
                    sql = MessageFormat.format(
825
                            config.getString(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table),
826
                            string(this.table.getSchema()),
827
                            string(this.table.getName())
828
                    );
829
                } else {
830
                    sql = MessageFormat.format(
831
                            config.getString(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table),
832
                            identifier(this.table.getName())
833
                    );
834
                }
835
                if( !StringUtils.isEmpty(sql) ) {
836
                    sqls.add(sql);
837
                }
838
            }
839
            return sqls;
840
        }
841
    }
842

    
843
    public class GrantRoleBuilderBase implements GrantRoleBuilder {
844
        protected TableNameBuilder table;
845
        protected String role;
846
        protected Set<Privilege> privileges;
847

    
848
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
849
            this.table = table;
850
            this.role = role;
851
            this.privileges = new HashSet<>();
852
        }
853

    
854
        @Override
855
        public GrantRoleBuilder privilege(Privilege privilege) {
856
            privileges.add(privilege);
857
            return this;
858
        }
859
        
860
        @Override
861
        public GrantRoleBuilder select() {
862
             privileges.add(Privilege.SELECT);
863
            return this;
864
        }
865

    
866
        @Override
867
        public GrantRoleBuilder update() {
868
             privileges.add(Privilege.UPDATE);
869
            return this;
870
        }
871

    
872
        @Override
873
        public GrantRoleBuilder insert() {
874
            privileges.add(Privilege.INSERT);
875
            return this;
876
        }
877

    
878
        @Override
879
        public GrantRoleBuilder delete() {
880
            privileges.add(Privilege.DELETE);
881
            return this;
882
        }
883

    
884
        @Override
885
        public GrantRoleBuilder truncate() {
886
            privileges.add(Privilege.TRUNCATE);
887
            return this;
888
        }
889

    
890
        @Override
891
        public GrantRoleBuilder reference() {
892
            privileges.add(Privilege.REFERENCE);
893
            return this;
894
        }
895

    
896
        @Override
897
        public GrantRoleBuilder trigger() {
898
            privileges.add(Privilege.TRIGGER);
899
            return this;
900
        }
901

    
902
        @Override
903
        public GrantRoleBuilder all() {
904
            privileges.add(Privilege.ALL);
905
            return this;
906
        }
907

    
908
        protected String getPrivilegeName(Privilege privilege) {
909
            switch(privilege) {
910
                case DELETE:
911
                    return "DELETE";
912
                case INSERT:
913
                    return "INSERT";
914
                case REFERENCE:
915
                    return "REFERENCE";
916
                case SELECT:
917
                    return "SELECT";
918
                case TRIGGER:
919
                    return "TRIGGER";
920
                case TRUNCATE:
921
                    return "TRUNCATE";
922
                case UPDATE:
923
                    return "UPDATE";
924
                case ALL:
925
                default:
926
                    return "ALL";
927
            }
928
        }
929
        
930
        @Override
931
        public String toString() {
932
            StringBuilder builder = new StringBuilder();
933
            boolean first = true;
934
            for (Privilege privilege : privileges) {
935
                if (first) {
936
                    first = false;
937
                } else {
938
                    builder.append(", ");
939
                }
940
                builder.append( this.getPrivilegeName(privilege));
941
            }
942
            String sql = MessageFormat.format(
943
                    config.getString(SQLConfig.GRANT_privileges_ON_table_TO_role),
944
                    builder.toString(),
945
                    table.toString(),
946
                    role
947
            );
948
            return sql;
949
        }
950
    }
951
    
952
    public class GrantBuilderBase implements GrantBuilder {
953

    
954
        protected TableNameBuilder table;
955
        protected Map<String, GrantRoleBuilder> roles;
956

    
957
        public GrantBuilderBase() {
958
            this.roles = new HashMap<>();
959
        }
960
        
961
        @Override
962
        public TableNameBuilder table() {
963
            if( table == null ) {
964
                table = createTableNameBuilder();
965
            }
966
            return table;
967
        }
968

    
969
        @Override
970
        public void accept(Visitor visitor, VisitorFilter filter) {
971
            if( filter.accept(this) ) {
972
                visitor.visit(this);
973
            }
974
            if( this.table!= null ) {
975
                this.table.accept(visitor,filter);
976
            }
977
        }
978
        
979
        @Override
980
        public GrantRoleBuilder role(String role) {
981
            GrantRoleBuilder roleBuilder = this.roles.get(role);
982
            if( roleBuilder == null ) {
983
                roleBuilder = createGrantRoleBuilder(this.table(), role);
984
                this.roles.put(role, roleBuilder);
985
            }
986
            return roleBuilder;
987
        }
988

    
989
        @Override
990
        public String toString() {
991
            StringBuilder builder = new StringBuilder();
992
            boolean first = true;
993
            for (String sql : toStrings()) {
994
                if( StringUtils.isEmpty(sql) ) {
995
                    continue;
996
                }
997
                if (first) {
998
                    first = false;
999
                } else {
1000
                    builder.append("; ");
1001
                }
1002
                builder.append(sql);
1003
            }
1004
            return builder.toString();
1005
        }
1006

    
1007
        @Override
1008
        public List<String> toStrings() {
1009
            List<String> sqls = new ArrayList<>();
1010
            for (GrantRoleBuilder role : roles.values()) {
1011
                sqls.add(role.toString());
1012
            }
1013
            return sqls;
1014
        }
1015
    }
1016

    
1017
    public class UpdateColumnBuilderBase extends InsertColumnBuilderBase implements UpdateColumnBuilder {
1018
        
1019
        public UpdateColumnBuilderBase() {
1020
            super();
1021
        }
1022

    
1023
        @Override
1024
        public UpdateColumnBuilder name(String name) {
1025
            return (UpdateColumnBuilder) super.name(name);
1026
        }
1027

    
1028
        @Override
1029
        public UpdateColumnBuilder with_value(Value value) {
1030
            return (UpdateColumnBuilder) super.with_value(value);
1031
        }
1032
        
1033
    }
1034
    
1035
    public class UpdateBuilderBase implements UpdateBuilder {
1036

    
1037
        protected ExpressionBuilder where;
1038
        protected List<UpdateColumnBuilder> columns;
1039
        protected TableNameBuilder table;
1040

    
1041
        public UpdateBuilderBase() {
1042
            this.columns = new ArrayList<>();
1043
        }
1044

    
1045
        @Override
1046
        public void accept(Visitor visitor, VisitorFilter filter) {
1047
            if( filter.accept(this) ) {
1048
                visitor.visit(this);
1049
            }
1050
            if( this.table != null ) {
1051
                this.table.accept(visitor, filter);
1052
            }
1053
            for (UpdateColumnBuilder column : columns) {
1054
                column.accept(visitor, filter);
1055
            }
1056
            if( this.has_where() ) {
1057
                this.where.accept(visitor, filter);
1058
            }
1059
        }
1060

    
1061
        @Override
1062
        public ExpressionBuilder where() {
1063
            if (this.where == null) {
1064
                this.where = createExpressionBuilder();
1065
            }
1066
            return this.where;
1067
        }
1068

    
1069
        @Override
1070
        public TableNameBuilder table() {
1071
            if( table == null ) {
1072
                table = createTableNameBuilder();
1073
            }
1074
            return table;
1075
        }
1076

    
1077
        @Override
1078
        public UpdateColumnBuilder column() {
1079
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1080
            this.columns.add(column);
1081
            return column;
1082
        }
1083
        
1084
        @Override
1085
        public boolean has_where() {
1086
            return this.where != null;
1087
        }
1088

    
1089
        @Override
1090
        public String toString() {
1091
            /*
1092
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1093
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1094
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1095
             * output_expression [ AS output_name ] [, ...] ]
1096
             */
1097
            StringBuilder columnsAndValues = new StringBuilder();
1098

    
1099
            boolean first = true;
1100
            for (UpdateColumnBuilder column : columns) {
1101
                if (first) {
1102
                    first = false;
1103
                } else {
1104
                    columnsAndValues.append(", ");
1105
                }
1106
                columnsAndValues.append(identifier(column.getName()));
1107
                columnsAndValues.append(" = ");
1108
                columnsAndValues.append(column.getValue().toString());
1109
            }
1110
            
1111
            String sql;
1112
            if ( this.has_where() ) {
1113
                sql = MessageFormat.format(
1114
                        config.getString(SQLConfig.UPDATE_table_SET_columnsAndValues_WHERE_expresion),
1115
                        this.table.toString(),
1116
                        columnsAndValues.toString(),
1117
                        this.where.toString()
1118
                );
1119
            } else {
1120
                sql = MessageFormat.format(
1121
                        config.getString(SQLConfig.UPDATE_table_SET_columnsAndValues),
1122
                        this.table.toString(),
1123
                        columnsAndValues.toString()
1124
                );
1125
            }
1126
            return sql;
1127
        }
1128
    }
1129

    
1130
    public class DeleteBuilderBase implements DeleteBuilder {
1131

    
1132
        protected ExpressionBuilder where;
1133
        protected TableNameBuilder table;
1134

    
1135
        public DeleteBuilderBase() {
1136
        }
1137

    
1138
        @Override
1139
        public void accept(Visitor visitor, VisitorFilter filter) {
1140
            if( filter.accept(this) ) {
1141
                visitor.visit(this);
1142
            }
1143
            if( this.table != null ) {
1144
                this.table.accept(visitor, filter);
1145
            }
1146
            if( this.has_where() ) {
1147
                this.where.accept(visitor, filter);
1148
            }
1149
        }
1150

    
1151
        @Override
1152
        public ExpressionBuilder where() {
1153
            if (this.where == null) {
1154
                this.where = createExpressionBuilder();
1155
            }
1156
            return this.where;
1157
        }
1158

    
1159
        @Override
1160
        public TableNameBuilder table() {
1161
            if( table == null ) {
1162
                table = createTableNameBuilder();
1163
            }
1164
            return table;
1165
        }
1166

    
1167
        @Override
1168
        public boolean has_where() {
1169
            return this.where != null;
1170
        }
1171

    
1172
        @Override
1173
        public String toString() {
1174
            /*
1175
             * DELETE FROM table_name
1176
             * WHERE some_column=some_value; 
1177
             */
1178
            String sql;
1179
            if( this.has_where() ) {
1180
                sql = MessageFormat.format(
1181
                        config.getString(SQLConfig.DELETE_FROM_table_WHERE_expresion),
1182
                        this.table.toString(),
1183
                        this.where.toString()
1184
                );
1185
            } else {
1186
                sql = MessageFormat.format(
1187
                        config.getString(SQLConfig.DELETE_FROM_table),
1188
                        this.table.toString()
1189
                );
1190
            }
1191
            return sql;
1192
        }
1193
    }
1194

    
1195
    public class AlterTableBuilderBase implements AlterTableBuilder {
1196

    
1197
        protected TableNameBuilder table;
1198
        protected List<String> drops;
1199
        protected List<ColumnDescriptorBuilderBase> adds;
1200
        protected List<ColumnDescriptorBuilderBase> alters;
1201
        protected List<Pair<String,String>> renames;
1202

    
1203
        public AlterTableBuilderBase() {
1204
            this.drops = new ArrayList<>();
1205
            this.adds = new ArrayList<>();
1206
            this.alters = new ArrayList<>();
1207
            this.renames = new ArrayList<>();
1208
        }
1209

    
1210
        @Override
1211
        public void accept(Visitor visitor, VisitorFilter filter) {
1212
            if( filter.accept(this) ) {
1213
                visitor.visit(this);
1214
            }
1215
            if( this.table != null ) {
1216
                this.table.accept(visitor, filter);
1217
            }
1218
        }
1219

    
1220
        @Override
1221
        public TableNameBuilder table() {
1222
            if( table == null ) {
1223
                table = createTableNameBuilder();
1224
            }
1225
            return table;
1226
        }
1227

    
1228
        @Override
1229
        public AlterTableBuilder drop_column(String columnName) {
1230
            this.drops.add(columnName);
1231
            return this;
1232
        }
1233

    
1234
        @Override
1235
        public AlterTableBuilder add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1236
            if (isPk || isAutomatic) {
1237
                allowNulls = false;
1238
            }
1239
            this.adds.add(new ColumnDescriptorBuilderBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1240
            return this;
1241
        }
1242

    
1243
        @Override
1244
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1245
            if( StringUtils.isEmpty(columnName) ) {
1246
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1247
            }
1248
            this.adds.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1249
            return this;
1250
        }
1251

    
1252
        @Override
1253
        public AlterTableBuilder alter_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1254
            if (isPk || isAutomatic) {
1255
                allowNulls = false;
1256
            }
1257
            this.alters.add(new ColumnDescriptorBuilderBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1258
            return this;
1259
        }
1260

    
1261
        @Override
1262
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1263
            if( StringUtils.isEmpty(columnName) ) {
1264
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1265
            }
1266
            this.alters.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1267
            return this;
1268
        }
1269

    
1270
        @Override
1271
        public AlterTableBuilder rename_column(String source, String target) {
1272
            this.renames.add(new ImmutablePair(source, target));
1273
            return this;
1274
        }
1275

    
1276
        @Override
1277
        public String toString() {
1278
            StringBuilder builder = new StringBuilder();
1279
            boolean first = true;
1280
            for (String sql : toStrings()) {
1281
                if( StringUtils.isEmpty(sql) ) {
1282
                    continue;
1283
                }
1284
                if (first) {
1285
                    first = false;
1286
                } else {
1287
                    builder.append("; ");
1288
                }
1289
                builder.append(sql);
1290
            }
1291
            return builder.toString();
1292
        }
1293

    
1294
        @Override
1295
        public List<String> toStrings() {
1296
            List<String> sqls = new ArrayList<>();
1297
            /*
1298
             ALTER TABLE [ ONLY ] name [ * ]
1299
             action [, ... ]
1300
             ALTER TABLE [ ONLY ] name [ * ]
1301
             RENAME [ COLUMN ] column TO new_column
1302
             ALTER TABLE name
1303
             RENAME TO new_name
1304
             ALTER TABLE name
1305
             SET SCHEMA new_schema
1306

1307
             where action is one of:
1308

1309
             ADD [ COLUMN ] column data_type [ COLLATE collation ] [ column_constraint [ ... ] ]
1310
             DROP [ COLUMN ] [ IF EXISTS ] column [ RESTRICT | CASCADE ]
1311
             ALTER [ COLUMN ] column [ SET DATA ] TYPE data_type [ COLLATE collation ] [ USING expression ]
1312
             ALTER [ COLUMN ] column SET DEFAULT expression
1313
             ALTER [ COLUMN ] column DROP DEFAULT
1314
             ALTER [ COLUMN ] column { SET | DROP } NOT NULL
1315
             ALTER [ COLUMN ] column SET STATISTICS integer
1316
             ALTER [ COLUMN ] column SET ( attribute_option = value [, ... ] )
1317
             ALTER [ COLUMN ] column RESET ( attribute_option [, ... ] )
1318
             ALTER [ COLUMN ] column SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
1319
             ADD table_constraint [ NOT VALID ]
1320
             ADD table_constraint_using_index
1321
             VALIDATE CONSTRAINT constraint_name
1322
             DROP CONSTRAINT [ IF EXISTS ]  constraint_name [ RESTRICT | CASCADE ]
1323
             DISABLE TRIGGER [ trigger_name | ALL | USER ]
1324
             ENABLE TRIGGER [ trigger_name | ALL | USER ]
1325
             ENABLE REPLICA TRIGGER trigger_name
1326
             ENABLE ALWAYS TRIGGER trigger_name
1327
             DISABLE RULE rewrite_rule_name
1328
             ENABLE RULE rewrite_rule_name
1329
             ENABLE REPLICA RULE rewrite_rule_name
1330
             ENABLE ALWAYS RULE rewrite_rule_name
1331
             CLUSTER ON index_name
1332
             SET WITHOUT CLUSTER
1333
             SET WITH OIDS
1334
             SET WITHOUT OIDS
1335
             SET ( storage_parameter = value [, ... ] )
1336
             RESET ( storage_parameter [, ... ] )
1337
             INHERIT parent_table
1338
             NO INHERIT parent_table
1339
             OF type_name
1340
             NOT OF
1341
             OWNER TO new_owner
1342
             SET TABLESPACE new_tablespace
1343

1344
             and table_constraint_using_index is:
1345

1346
             [ CONSTRAINT constraint_name ]
1347
             { UNIQUE | PRIMARY KEY } USING INDEX index_name
1348
             [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1349

1350
             */
1351

    
1352
            for (String column : drops) {
1353
                StringBuilder builder = new StringBuilder();
1354
                builder.append("ALTER TABLE ");
1355
                builder.append(this.table.toString());
1356
                builder.append(" DROP COLUMN IF EXISTS ");
1357
                builder.append(identifier(column)); 
1358
                sqls.add(builder.toString());
1359
            }
1360
            for (ColumnDescriptorBuilderBase column : adds) {
1361
                StringBuilder builder = new StringBuilder();
1362
                builder.append("ALTER TABLE ");
1363
                builder.append(this.table.toString());
1364
                builder.append(" ADD COLUMN ");
1365
                builder.append(identifier(column.getName())); 
1366
                builder.append(" ");
1367
                if( column.getType() == DataTypes.INT && column.isAutomatic() ) {
1368
                    builder.append(" SERIAL");
1369
                } else {
1370
                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
1371
                }
1372
                if (column.getDefaultValue() == null) {
1373
                    if (column.allowNulls()) {
1374
                        builder.append(" DEFAULT NULL");
1375
                    }
1376
                } else {
1377
                    builder.append(" DEFAULT '");
1378
                    builder.append(column.getDefaultValue().toString());
1379
                    builder.append("'");
1380
                }
1381
                if (column.allowNulls()) {
1382
                    builder.append(" NULL");
1383
                } else {
1384
                    builder.append(" NOT NULL");
1385
                }
1386
                if (column.isPrimaryKey()) {
1387
                    builder.append(" PRIMARY KEY");
1388
                }
1389
                sqls.add(builder.toString());
1390
                if( column.isIndexed() ) {
1391
                    String sql;
1392
                    String name = "idx_" + this.table().getName() + "_" + column.getName();
1393
                    if( column.isGeometry() ) {
1394
                        sql = MessageFormat.format(
1395
                            config.getString(SQLConfig.CREATE_INDEX_name_ON_table_USING_GIST_column),
1396
                            name,
1397
                            this.table().toString(),
1398
                            column.getName()
1399
                        );
1400
                    } else {
1401
                        sql = MessageFormat.format(
1402
                            config.getString(SQLConfig.CREATE_INDEX_name_ON_table_column),
1403
                            name,
1404
                            this.table().toString(),
1405
                            column.getName()
1406
                        );
1407
                    }
1408
                    sqls.add(sql);
1409
                }
1410
            }
1411
            for (ColumnDescriptorBuilderBase column : alters) {
1412
                StringBuilder builder = new StringBuilder();
1413
                builder.append("ALTER TABLE ");
1414
                builder.append(this.table.toString());
1415
                builder.append(" ALTER COLUMN ");
1416
                builder.append(identifier(column.getName())); 
1417
                builder.append(" SET DATA TYPE ");
1418
                if( column.getType() == DataTypes.INT && column.isAutomatic() ) {
1419
                    builder.append(" SERIAL");
1420
                } else {
1421
                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
1422
                }
1423
                if (column.getDefaultValue() == null) {
1424
                    if (column.allowNulls()) {
1425
                        builder.append(" DEFAULT NULL");
1426
                    } else {
1427
                        builder.append(" DROP DEFAULT");
1428
                    }
1429
                } else {
1430
                    builder.append(" DEFAULT '");
1431
                    builder.append(column.getDefaultValue().toString());
1432
                    builder.append("'");
1433
                }
1434
                sqls.add(builder.toString());
1435
                if( column.isIndexed() ) {
1436
                    String sql;
1437
                    String name = "idx_" + this.table().getName() + "_" + column.getName();
1438
                    if( column.isGeometry() ) {
1439
                        sql = MessageFormat.format(
1440
                            config.getString(SQLConfig.CREATE_INDEX_name_ON_table_USING_GIST_column),
1441
                            name,
1442
                            this.table().toString(),
1443
                            column.getName()
1444
                        );
1445
                    } else {
1446
                        sql = MessageFormat.format(
1447
                            config.getString(SQLConfig.CREATE_INDEX_name_ON_table_column),
1448
                            name,
1449
                            this.table().toString(),
1450
                            column.getName()
1451
                        );
1452
                    }
1453
                    sqls.add(sql);
1454
                }
1455
            }
1456
            for (Pair<String,String> pair : renames) {
1457
                StringBuilder builder = new StringBuilder();
1458
                builder.append("ALTER TABLE ");
1459
                builder.append(this.table.toString());
1460
                builder.append(" RENAME COLUMN ");
1461
                builder.append(identifier(pair.getLeft())); 
1462
                builder.append(" TO ");
1463
                builder.append(identifier(pair.getRight())); 
1464
                sqls.add(builder.toString());
1465
            }
1466
            return sqls;
1467
        }
1468

    
1469
    }
1470

    
1471
    public class CreateTableBuilderBase implements CreateTableBuilder {
1472

    
1473
        protected TableNameBuilder table;
1474
        protected List<ColumnDescriptorBuilderBase> columns;
1475

    
1476
        public CreateTableBuilderBase() {
1477
            this.columns = new ArrayList<>();
1478
        }
1479

    
1480
        @Override
1481
        public void accept(Visitor visitor, VisitorFilter filter) {
1482
            if( filter.accept(this) ) {
1483
                visitor.visit(this);
1484
            }
1485
            if( this.table != null ) {
1486
                this.table.accept(visitor, filter);
1487
            }
1488
        }
1489

    
1490
        @Override
1491
        public TableNameBuilder table() {
1492
            if( table == null ) {
1493
                table = createTableNameBuilder();
1494
            }
1495
            return table;
1496
        }
1497

    
1498
        @Override
1499
        public CreateTableBuilderBase add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1500
            if( StringUtils.isEmpty(columnName) ) {
1501
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1502
            }
1503
            if (isPk || isAutomatic) {
1504
                allowNulls = false;
1505
            }
1506
            this.columns.add(new ColumnDescriptorBuilderBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1507
            return this;
1508
        }
1509

    
1510
        @Override
1511
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1512
            if( StringUtils.isEmpty(columnName) ) {
1513
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1514
            }
1515
            this.columns.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1516
            return this;
1517
        }
1518

    
1519
        @Override
1520
        public ColumnDescriptorBuilder getColumnDescriptor(String columnName) {
1521
            if( StringUtils.isEmpty(columnName) ) {
1522
                return null;
1523
            }
1524
            for (ColumnDescriptorBuilderBase column : columns) {
1525
                if( columnName.equals(column.getName()) ) {
1526
                    return column;
1527
                }
1528
            }
1529
            return null;
1530
        }
1531
                
1532
        @Override
1533
        public String toString() {
1534
            StringBuilder builder = new StringBuilder();
1535
            boolean first = true;
1536
            for (String sql : toStrings()) {
1537
                if( StringUtils.isEmpty(sql) ) {
1538
                    continue;
1539
                }
1540
                if (first) {
1541
                    first = false;
1542
                } else {
1543
                    builder.append("; ");
1544
                }
1545
                builder.append(sql);
1546
            }
1547
            return builder.toString();
1548
        }
1549

    
1550
        @Override
1551
        public List<String> toStrings() {
1552
            List<String> sqls = new ArrayList<>();
1553
            /**
1554
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
1555
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
1556
             * column_constraint [ ... ] ] | table_constraint | LIKE
1557
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
1558
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
1559
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
1560
             *
1561
             * where column_constraint is:
1562
             *
1563
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
1564
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
1565
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
1566
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
1567
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1568
             *
1569
             * and table_constraint is:
1570
             *
1571
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
1572
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
1573
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
1574
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
1575
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
1576
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1577
             */
1578
            StringBuilder builder = new StringBuilder();
1579

    
1580
            builder.append("CREATE TABLE ");
1581
            builder.append(this.table.toString());
1582
            builder.append(" (");
1583
            boolean first = true;
1584
            for (ColumnDescriptorBuilderBase column : columns) {
1585
                if (first) {
1586
                    first = false;
1587
                } else {
1588
                    builder.append(", ");
1589
                }
1590
                builder.append(identifier(column.getName()));
1591
                builder.append(" ");
1592
                if( column.isAutomatic() && column.getType() == DataTypes.INT ) {
1593
                    builder.append("SERIAL");
1594
                } else if( column.isAutomatic() && column.getType() == DataTypes.LONG ) {
1595
                    builder.append("BIGSERIAL");
1596
                } else {
1597
                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
1598
                }
1599
                if (column.getDefaultValue() == null) {
1600
                    if (column.allowNulls()) {
1601
                        builder.append(" DEFAULT NULL");
1602
                    }
1603
                } else {
1604
                    builder.append(" DEFAULT '");
1605
                    builder.append(column.getDefaultValue().toString());
1606
                    builder.append("'");
1607
                }
1608
                if (column.allowNulls()) {
1609
                    builder.append(" NULL");
1610
                } else {
1611
                    builder.append(" NOT NULL");
1612
                }
1613
                if (column.isPrimaryKey()) {
1614
                    builder.append(" PRIMARY KEY");
1615
                }
1616
            }
1617
            builder.append(" )");
1618
            sqls.add(builder.toString());
1619
            for (ColumnDescriptorBuilderBase column : columns) {
1620
                if( column.isIndexed() ) {
1621
                    String sql;
1622
                    String name = "idx_" + this.table().getName() + "_" + column.getName();
1623
                    if( column.isGeometry() ) {
1624
                        sql = MessageFormat.format(
1625
                            config.getString(SQLConfig.CREATE_INDEX_name_ON_table_USING_GIST_column),
1626
                            name,
1627
                            this.table().toString(),
1628
                            column.getName()
1629
                        );
1630
                    } else {
1631
                        sql = MessageFormat.format(
1632
                            config.getString(SQLConfig.CREATE_INDEX_name_ON_table_column),
1633
                            name,
1634
                            this.table().toString(),
1635
                            column.getName()
1636
                        );
1637
                    }
1638
                    sqls.add(sql);
1639
                }
1640
            }            
1641
            return sqls;
1642
        }
1643
    }
1644

    
1645
    public class InsertColumnBuilderBase implements InsertColumnBuilder {
1646
        protected Variable name;
1647
        protected Value value;
1648
        
1649
        public InsertColumnBuilderBase() {
1650
        }
1651

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

    
1665
        @Override
1666
        public InsertColumnBuilder name(String name) {
1667
            this.name = variable(name);
1668
            return this;
1669
        }
1670

    
1671
        @Override
1672
        public InsertColumnBuilder with_value(Value value) {
1673
            this.value = value;
1674
            return this;
1675
        }
1676
        
1677
        @Override
1678
        public String getName() {
1679
            return this.name.getName();
1680
        }
1681
        
1682
        @Override
1683
        public Value getValue() {
1684
            return this.value;
1685
        }
1686
        
1687
        @Override
1688
        public String toString() {
1689
            return this.value.toString();
1690
        }
1691
    }
1692
    
1693
    public class InsertBuilderBase implements InsertBuilder {
1694

    
1695
        protected List<InsertColumnBuilder> columns;
1696
        protected TableNameBuilder table;
1697

    
1698
        public InsertBuilderBase() {
1699
            this.columns = new ArrayList<>();
1700
        }
1701

    
1702
        @Override
1703
        public void accept(Visitor visitor, VisitorFilter filter) {
1704
            if( filter.accept(this) ) {
1705
                visitor.visit(this);
1706
            }
1707
            if( this.table != null ) {
1708
                this.table.accept(visitor, filter);
1709
            }
1710
            for (InsertColumnBuilder column : columns) {
1711
                column.accept(visitor, filter);
1712
            }
1713
        }
1714

    
1715
        @Override
1716
        public TableNameBuilder table() {
1717
            if( table == null ) {
1718
                table = createTableNameBuilder();
1719
            }
1720
            return table;
1721
        }
1722

    
1723
        @Override
1724
        public InsertColumnBuilder column() {
1725
            InsertColumnBuilder column = createInsertColumnBuilder();
1726
            this.columns.add(column);
1727
            return column;
1728
        }
1729

    
1730
        @Override
1731
        public String toString() {
1732
            /*
1733
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
1734
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
1735
             * output_expression [ AS output_name ] [, ...] ]
1736
             */
1737
            StringBuilder builderColumns = new StringBuilder();
1738
            StringBuilder builderValues = new StringBuilder();
1739
            
1740
            boolean first = true;
1741
            for (InsertColumnBuilder column : columns) {
1742
                if (first) {
1743
                    first = false;
1744
                } else {
1745
                    builderColumns.append(", ");
1746
                }
1747
                builderColumns.append(identifier(column.getName()));
1748
            }
1749
            first = true;
1750
            for (InsertColumnBuilder column : columns) {
1751
                if (first) {
1752
                    first = false;
1753
                } else {
1754
                    builderValues.append(", ");
1755
                }
1756
                builderValues.append(column.toString());
1757
            }
1758
            
1759
            String sql = MessageFormat.format(
1760
                    config.getString(SQLConfig.INSERT_INTO_table_columns_VALUES_values),
1761
                    this.table.toString(),
1762
                    builderColumns.toString(),
1763
                    builderValues.toString()
1764
            );
1765
            return sql;
1766

    
1767
        }
1768
    }
1769

    
1770
    public class UpdateTableStatisticsBuilderBase implements UpdateTableStatisticsBuilder {
1771

    
1772
        protected TableNameBuilder table;
1773

    
1774
        @Override
1775
        public void accept(Visitor visitor, VisitorFilter filter) {
1776
            if( filter.accept(this) ) {
1777
                visitor.visit(this);
1778
            }
1779
            if( this.table != null ) {
1780
                this.table.accept(visitor, filter);
1781
            }
1782
        }
1783

    
1784
        @Override
1785
        public TableNameBuilder table() {
1786
            if( table == null ) {
1787
                table = createTableNameBuilder();
1788
            }
1789
            return table;
1790
        }
1791

    
1792
        @Override
1793
        public String toString() {
1794
            StringBuilder builder = new StringBuilder();
1795
            boolean first = true;
1796
            for (String sql : toStrings()) {
1797
                if( StringUtils.isEmpty(sql) ) {
1798
                    continue;
1799
                }
1800
                if (first) {
1801
                    first = false;
1802
                } else {
1803
                    builder.append("; ");
1804
                }
1805
                builder.append(sql);
1806
            }
1807
            return builder.toString();
1808
        }
1809

    
1810
        @Override
1811
        public List<String> toStrings() {
1812
            List<String> sqls = new ArrayList<>();
1813
            
1814
            if( config.has_functionality(SQLConfig.UPDATE_TABLE_STATISTICS_table) ) {
1815
                String sql = MessageFormat.format(
1816
                        config.getString(SQLConfig.UPDATE_TABLE_STATISTICS_table),
1817
                        table.toString()
1818
                    );
1819
                if( !StringUtils.isEmpty(sql) ) {
1820
                    sqls.add(sql);
1821
                }
1822
            }
1823
            return sqls;
1824
        }
1825
    }
1826
    
1827
    public SQLBuilderBase() {
1828
        super();
1829
        config.set(SQLConfig.default_schema, "public");
1830
        config.set(SQLConfig.allowAutomaticValues, true);
1831
        
1832
        config.set(SQLConfig.ST_ExtentAggregate, "ST_Extent({0})");
1833
        config.set(SQLConfig.ST_UnionAggregate, "ST_Union({0})");
1834
        config.set(SQLConfig.count, "COUNT({0})");
1835
        config.set(SQLConfig.count_distinct, "COUNT(DISTINCT {0})");
1836

    
1837
        config.set(SQLConfig.type_boolean, "BOOLEAN");
1838
        config.set(SQLConfig.type_byte, "TINYINT");
1839
        config.set(SQLConfig.type_bytearray, "BYTEA");
1840
        config.set(SQLConfig.type_geometry, "TEXT");
1841
        config.set(SQLConfig.type_char, "CHARACTER(1)");
1842
        config.set(SQLConfig.type_date, "DATE");
1843
        config.set(SQLConfig.type_double, "DOUBLE PRECISION"); //float con 53 bits de mantisa, float(54)
1844
        config.set(SQLConfig.type_numeric_p, "NUMERIC({0})");
1845
        config.set(SQLConfig.type_numeric_ps, "NUMERIC({0},{1})");
1846
        config.set(SQLConfig.type_bigdecimal, "NUMERIC({0},{1})");
1847
        config.set(SQLConfig.type_float, "REAL"); //float con 24 bits de mantisa, float(24)
1848
        config.set(SQLConfig.type_int, "INT");
1849
        config.set(SQLConfig.type_long, "BIGINT");
1850
        config.set(SQLConfig.type_string, "TEXT");
1851
        config.set(SQLConfig.type_string_p, "VARCHAR({0})");
1852
        config.set(SQLConfig.type_time, "TIME");
1853
        config.set(SQLConfig.type_timestamp, "TIMESTAMP");
1854
        config.set(SQLConfig.type_version, "VARCHAR(30)");
1855
        config.set(SQLConfig.type_URI, "TEXT");
1856
        config.set(SQLConfig.type_URL, "TEXT");
1857
        config.set(SQLConfig.type_FILE, "TEXT");
1858
        config.set(SQLConfig.type_FOLDER, "TEXT");
1859

    
1860
        config.set(SQLConfig.DELETE_FROM_table_WHERE_expresion, "DELETE FROM {0} WHERE {1}");
1861
        config.set(SQLConfig.DELETE_FROM_table, "DELETE FROM {0}");
1862
        config.set(SQLConfig.INSERT_INTO_table_columns_VALUES_values, "INSERT INTO {0} ( {1} ) VALUES ( {2} )");
1863
        config.set(SQLConfig.UPDATE_TABLE_STATISTICS_table, "VACUUM ANALYZE {0}");
1864
        config.set(SQLConfig.DROP_TABLE_table, "DROP TABLE {0}");
1865
        config.set(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table, "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}");
1866
        config.set(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table, "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}");
1867
        config.set(SQLConfig.UPDATE_table_SET_columnsAndValues_WHERE_expresion, "UPDATE {0} SET {1} WHERE {2}");
1868
        config.set(SQLConfig.UPDATE_table_SET_columnsAndValues, "UPDATE {0} SET {1}");
1869
        config.set(SQLConfig.GRANT_privileges_ON_table_TO_role, "GRANT {0} ON {1} TO {2}");        
1870
        config.set(SQLConfig.CREATE_INDEX_name_ON_table_column, "CREATE INDEX {0} ON {1} ({2})");
1871
        config.set(SQLConfig.CREATE_INDEX_name_ON_table_USING_GIST_column, "CREATE INDEX {0} ON {1} USING GIST ({2})");
1872
    }
1873
    
1874
    @Override
1875
    public String default_schema() {
1876
        return config.getString(SQLConfig.default_schema);
1877
    }
1878

    
1879
    @Override
1880
    public boolean supportSchemas() {
1881
        return config.getBoolean(Config.support_schemas);
1882
    }
1883
    
1884
    @Override
1885
    @Deprecated
1886
    public String sqltype(int type, int p, int s) {
1887
        return this.sqltype(type, p, s, Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.UNKNOWN);
1888
    }
1889

    
1890
    @Override
1891
    public String sqltype(int type, int p, int s, int geomType, int geomSubtype) {
1892
        switch (type) {
1893
            case DataTypes.BOOLEAN:
1894
                return config.getString(SQLConfig.type_boolean);
1895
            case DataTypes.BYTE:
1896
                return config.getString(SQLConfig.type_byte);
1897
            case DataTypes.BYTEARRAY:
1898
                return config.getString(SQLConfig.type_bytearray);
1899
            case DataTypes.GEOMETRY:
1900
                return config.getString(SQLConfig.type_geometry);
1901
            case DataTypes.CHAR:
1902
                return config.getString(SQLConfig.type_char);
1903
            case DataTypes.DATE:
1904
                return config.getString(SQLConfig.type_date);
1905
            case DataTypes.DOUBLE:
1906
                  // FIXME: Si cargamos la capa "country" al exportarla a
1907
                  // SQLServer falla por:
1908
                  //  Error de desbordamiento aritm?tico al convertir float al tipo de datos numeric.
1909
                  // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
1910
                  // Algeria intenta asignarle un valor de 2320972.0 y falla.
1911
                  // Habria que repasar el proveedor de shape.
1912
                
1913
//                if (p > 1) {
1914
//                    if (s < 0) {
1915
//                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
1916
//                    }
1917
//                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
1918
//                }
1919
                return MessageFormat.format(config.getString(SQLConfig.type_double),p,s);
1920
            case DataTypes.BIGDECIMAL:
1921
                if (p < 1) {
1922
                    p = 20;
1923
                }
1924
                if (s < 0) {
1925
                    s = 10;
1926
                }
1927
                return MessageFormat.format(config.getString(SQLConfig.type_bigdecimal), p,s);
1928
            case DataTypes.FLOAT:
1929
                return MessageFormat.format(config.getString(SQLConfig.type_float), p,s);
1930
            case DataTypes.INT:
1931
                return MessageFormat.format(config.getString(SQLConfig.type_int), p,s);
1932
            case DataTypes.LONG:
1933
                return MessageFormat.format(config.getString(SQLConfig.type_long), p,s);
1934
            case DataTypes.STRING:
1935
                if (p < 0) {
1936
                    return config.getString(SQLConfig.type_string);
1937
                } else if (p < 4096) {
1938
                    return MessageFormat.format(config.getString(SQLConfig.type_string_p),p);
1939
                }
1940
                return config.getString(SQLConfig.type_string);
1941
            case DataTypes.TIME:
1942
                return config.getString(SQLConfig.type_time);
1943
            case DataTypes.TIMESTAMP:
1944
                return config.getString(SQLConfig.type_timestamp);
1945
            case DataTypes.VERSION:
1946
                return config.getString(SQLConfig.type_version);
1947
            case DataTypes.URI:
1948
                return config.getString(SQLConfig.type_URI);
1949
            case DataTypes.URL:
1950
                return config.getString(SQLConfig.type_URL);
1951
            case DataTypes.FILE:
1952
                return config.getString(SQLConfig.type_FILE);
1953
            case DataTypes.FOLDER:
1954
                return config.getString(SQLConfig.type_FOLDER);
1955
            default:
1956
                return null;
1957
        }
1958
    }
1959

    
1960
    private static Map<Pair<Integer,Integer>,String> sqlgeometrytypes = null;
1961
    
1962
    @Override
1963
    public Object sqlgeometrytype(int type, int subtype) {
1964
        // Devuelve un Object por que algunos gestores de BBDD utilizan
1965
        // identificadores numericos para el tipo y otros strings.
1966
        // Por defecto vamos a devolver strings.
1967
        if( sqlgeometrytypes==null ) {
1968
            sqlgeometrytypes = new HashMap<>();
1969
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2D), "POINT");
1970
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3D), "POINTZ");
1971
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2DM), "POINTM");
1972
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3DM), "POINTZM");
1973

    
1974
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2D), "LINESTRING");
1975
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
1976
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
1977
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
1978

    
1979
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2D), "POLYGON");
1980
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
1981
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
1982
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
1983

    
1984
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
1985
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
1986
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
1987
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
1988

    
1989
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
1990
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
1991
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
1992
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
1993

    
1994
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
1995
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
1996
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
1997
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
1998

    
1999
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2000
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2001
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2002
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2003

    
2004
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2005
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2006
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2007
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2008

    
2009
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2010
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2011
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2012
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2013
        }
2014
        return sqlgeometrytypes.get(new ImmutablePair<>(type,subtype));
2015
    }
2016

    
2017
    @Override
2018
    public Object sqlgeometrydimension(int type, int subtype) {
2019
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2020
        // identificadores numericos para las dimensiones y otros strings.
2021
        // Por defecto vamos a devolver enteros.
2022
        switch(subtype) {
2023
            case Geometry.SUBTYPES.GEOM3D:
2024
                return 3;
2025
            case Geometry.SUBTYPES.GEOM2DM:
2026
                return 3;
2027
            case Geometry.SUBTYPES.GEOM3DM:
2028
                return 4;
2029
            case Geometry.SUBTYPES.GEOM2D:
2030
            default:
2031
                return 2;
2032
        }
2033
    }
2034
    
2035
    protected TableNameBuilder createTableNameBuilder() {
2036
        return new TableNameBuilderBase();
2037
    }
2038
    
2039
    protected SelectColumnBuilder createSelectColumnBuilder() {
2040
        return new SelectColumnBuilderBase();
2041
    }
2042
    
2043
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2044
        return new UpdateColumnBuilderBase();
2045
    }
2046
    
2047
    protected InsertColumnBuilder createInsertColumnBuilder() {
2048
        return new InsertColumnBuilderBase();
2049
    }
2050
    
2051
    protected OrderByBuilder createOrderByBuilder() {
2052
        return new OrderByBuilderBase();
2053
    }
2054

    
2055
    protected FromBuilder createFromBuilder() {
2056
        return new FromBuilderBase();
2057
    }
2058

    
2059
    protected SelectBuilder createSelectBuilder() {
2060
        return new SelectBuilderBase();
2061
    }
2062

    
2063
    protected UpdateBuilder createUpdateBuilder() {
2064
        return new UpdateBuilderBase();
2065
    }
2066

    
2067
    protected DeleteBuilder createDeleteBuilder() {
2068
        return new DeleteBuilderBase();
2069
    }
2070

    
2071
    protected GrantBuilder createGrantBuilder() {
2072
        return new GrantBuilderBase();
2073
    }
2074

    
2075
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2076
        return new GrantRoleBuilderBase(table, role);
2077
    }
2078
    
2079
    protected DropTableBuilder createDropTableBuilder() {
2080
        return new DropTableBuilderBase();
2081
    }
2082

    
2083
    protected CreateTableBuilder createCreateTableBuilder() {
2084
        return new CreateTableBuilderBase();
2085
    }
2086

    
2087
    protected AlterTableBuilder createAlterTableBuilder() {
2088
        return new AlterTableBuilderBase();
2089
    }
2090

    
2091
    protected InsertBuilder createInsertBuilder() {
2092
        return new InsertBuilderBase();
2093
    }
2094

    
2095
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2096
        return new UpdateTableStatisticsBuilderBase();
2097
    }
2098

    
2099
    @Override
2100
    public SelectBuilder select() {
2101
        if (this.select == null) {
2102
            this.select = this.createSelectBuilder();
2103
        }
2104
        return this.select;
2105
    }
2106

    
2107
    @Override
2108
    public UpdateBuilder update() {
2109
        if (this.update == null) {
2110
            this.update = this.createUpdateBuilder();
2111
        }
2112
        return this.update;
2113
    }
2114

    
2115
    @Override
2116
    public UpdateTableStatisticsBuilder update_table_statistics() {
2117
        if (this.update_table_statistics == null) {
2118
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2119
        }
2120
        return this.update_table_statistics;
2121
    }
2122

    
2123
    @Override
2124
    public DropTableBuilder drop_table() {
2125
        if (this.drop_table == null) {
2126
            this.drop_table = this.createDropTableBuilder();
2127
        }
2128
        return this.drop_table;
2129
    }
2130

    
2131
    @Override
2132
    public DeleteBuilder delete() {
2133
        if (this.delete == null) {
2134
            this.delete = this.createDeleteBuilder();
2135
        }
2136
        return this.delete;
2137
    }
2138

    
2139
    @Override
2140
    public InsertBuilder insert() {
2141
        if (this.insert == null) {
2142
            this.insert = this.createInsertBuilder();
2143
        }
2144
        return this.insert;
2145
    }
2146

    
2147
    @Override
2148
    public AlterTableBuilder alter_table() {
2149
        if (this.alter_table == null) {
2150
            this.alter_table = this.createAlterTableBuilder();
2151
        }
2152
        return this.alter_table;
2153
    }
2154

    
2155
    @Override
2156
    public CreateTableBuilder create_table() {
2157
        if (this.create_table == null) {
2158
            this.create_table = this.createCreateTableBuilder();
2159
        }
2160
        return this.create_table;
2161
    }
2162

    
2163
    @Override
2164
    public GrantBuilder grant() {
2165
        if (this.grant == null) {
2166
            this.grant = this.createGrantBuilder();
2167
        }
2168
        return this.grant;
2169
    }
2170

    
2171
    @Override
2172
    public void accept(Visitor visitor, VisitorFilter filter) {
2173
        if (this.select != null) {
2174
            this.select.accept(visitor, filter);
2175
        }
2176
        if (this.update != null) {
2177
            this.update.accept(visitor, filter);
2178
        }
2179
        if (this.insert != null) {
2180
            this.insert.accept(visitor, filter);
2181
        }
2182
        if (this.delete != null) {
2183
            this.delete.accept(visitor, filter);
2184
        }
2185
        if (this.alter_table != null) {
2186
            this.alter_table.accept(visitor, filter);
2187
        }
2188
        if (this.create_table != null) {
2189
            this.create_table.accept(visitor, filter);
2190
        }
2191
        if (this.drop_table != null) {
2192
            this.drop_table.accept(visitor, filter);
2193
        }
2194
    }
2195

    
2196
    
2197
    @Override
2198
    public String toString() {
2199
        if (this.select != null) {
2200
            return this.select.toString();
2201
        }
2202
        if (this.update != null) {
2203
            return this.update.toString();
2204
        }
2205
        if (this.insert != null) {
2206
            return this.insert.toString();
2207
        }
2208
        if (this.delete != null) {
2209
            return this.delete.toString();
2210
        }
2211
        if (this.alter_table != null) {
2212
            return this.alter_table.toString();
2213
        }
2214
        if (this.create_table != null) {
2215
            return this.create_table.toString();
2216
        }
2217
        if (this.drop_table != null) {
2218
            return this.drop_table.toString();
2219
        }
2220
        if (this.update_table_statistics != null) {
2221
            return this.update_table_statistics.toString();
2222
        }
2223
        if ( this.value != null ) {
2224
            return this.value.toString();
2225
        }
2226
        return ""; 
2227
    }
2228

    
2229
    @Override
2230
    public Function ST_UnionAggregate(Value geom) {
2231
        return function("ST_UnionAggregate", config.getString(SQLConfig.ST_UnionAggregate), geom);
2232
    }
2233

    
2234
    @Override
2235
    public Function ST_ExtentAggregate(Value geom) {
2236
        return function("ST_ExtentAggregate", config.getString(SQLConfig.ST_ExtentAggregate), geom);
2237
    }
2238

    
2239
    @Override
2240
    public CountBuilder count() {
2241
        return new CountBuilderBase();
2242
    }
2243

    
2244
}