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

History | View | Annotate | Download (78.7 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 CreateIndexBuilder create_index;
53
    protected List<Parameter> parameters;
54

    
55
    protected class ColumnDescriptorBuilderBase implements ColumnDescriptorBuilder {
56

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

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

    
85
        public ColumnDescriptorBuilderBase(String name, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
86
            this.name = name;
87
            this.type = type;
88
            this.type_p = type_p;
89
            this.type_s = type_s;
90
            this.isPk = isPk;
91
            this._allowNulls = allowNulls;
92
            this._isAutomatic = isAutomatic;
93
            this.defaultValue = defaultValue;
94
            this.geom_type = Geometry.TYPES.GEOMETRY;
95
            this.geom_subtype = Geometry.SUBTYPES.GEOM2D;
96
            this.geom_srsdbcode = null;
97
            this._isIndexed = isIndexed;
98
        }
99
        
100
        public ColumnDescriptorBuilderBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
101
            this.name = name;
102
            this.type = DataTypes.GEOMETRY;
103
            this.type_p = 0;
104
            this.type_s = 0;
105
            this.isPk = false;
106
            this._allowNulls = allowNulls;
107
            this._isAutomatic = false;
108
            this.defaultValue = null;
109
            this.geom_type = geom_type;
110
            this.geom_subtype = geom_subtype;
111
            this.geom_srsdbcode = getSRSId(proj);
112
            this._isIndexed = isIndexed;
113
        }
114
        
115
        public ColumnDescriptorBuilderBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
116
            this.name = name;
117
            this.type = DataTypes.GEOMETRY;
118
            this.type_p = 0;
119
            this.type_s = 0;
120
            this.isPk = false;
121
            this._allowNulls = allowNulls;
122
            this._isAutomatic = false;
123
            this.defaultValue = null;
124
            this.geom_type = geom_type;
125
            this.geom_subtype = geom_subtype;
126
            this.geom_srsdbcode = srsdbcode;
127
            this._isIndexed = isIndexed;
128
        }
129
        
130
        @Override
131
        public String getName() {
132
            return this.name;
133
        }
134
        
135
        @Override
136
        public void setName(String name) {
137
            this.name = name;
138
        }
139

    
140
        @Override
141
        public int getType() {
142
            return this.type;
143
        }
144

    
145
        @Override
146
        public void setType(int type) {
147
            this.type = type;
148
        }
149

    
150
        @Override
151
        public int getPrecision() {
152
            return type_p;
153
        }
154

    
155
        @Override
156
        public void setPrecision(int precision) {
157
            this.type_p = precision;
158
        }
159

    
160
        @Override
161
        public int getSize() {
162
            return type_s;
163
        }
164

    
165
        @Override
166
        public void setSize(int size) {
167
            this.type_s = size;
168
        }
169

    
170
        @Override
171
        public boolean isPrimaryKey() {
172
            return isPk;
173
        }
174

    
175
        @Override
176
        public void setIsPrimaryKey(boolean isPk) {
177
            this.isPk = isPk;
178
        }
179

    
180
        @Override
181
        public boolean allowNulls() {
182
            return _allowNulls;
183
        }
184

    
185
        @Override
186
        public void setAllowNulls(boolean allowNulls) {
187
            this._allowNulls = allowNulls;
188
        }
189

    
190
        @Override
191
        public boolean isAutomatic() {
192
            return _isAutomatic;
193
        }
194

    
195
        @Override
196
        public boolean isIndexed() {
197
            return _isIndexed;
198
        }
199

    
200
        @Override
201
        public void setIsAutomatic(boolean isAutomatic) {
202
            this._isAutomatic = isAutomatic;
203
        }
204

    
205
        @Override
206
        public Object getDefaultValue() {
207
            return defaultValue;
208
        }
209

    
210
        @Override
211
        public void setDefaultValue(Object defaultValue) {
212
            this.defaultValue = defaultValue;
213
        }
214

    
215
        @Override
216
        public int getGeometryType() {
217
            return geom_type;
218
        }
219

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

    
225
        @Override
226
        public int getGeometrySubtype() {
227
            return geom_subtype;
228
        }
229

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

    
235
        @Override
236
        public Object getGeometrySRSId() {
237
            return geom_srsdbcode;
238
        }
239

    
240
        @Override
241
        public void setGeometrySRSId(Object geom_srsid) {
242
            this.geom_srsdbcode = geom_srsid;
243
        }        
244

    
245
        @Override
246
        public boolean isGeometry() {
247
            return this.type == DataTypes.GEOMETRY;
248
        }
249
                
250
    }
251
    
252

    
253
    public class TableNameBuilderBase implements TableNameBuilder {
254

    
255
        public String tableName;
256
        public String schemaName;
257
        private String databaseName;
258

    
259
        public TableNameBuilderBase() {
260
        }
261

    
262
        @Override
263
        public void accept(Visitor visitor, VisitorFilter filter) {
264
            if( filter.accept(this) ) {
265
                visitor.visit(this);
266
            }
267
        }
268

    
269
        @Override
270
        public TableNameBuilder database(String name) {
271
            this.databaseName = name;
272
            return this;
273
        }
274

    
275
        @Override
276
        public TableNameBuilder schema(String name) {
277
            if( supportSchemas() ) {
278
                this.schemaName = name;
279
            }
280
            return this;
281
        }
282

    
283
        @Override
284
        public TableNameBuilder name(String name) {
285
            this.tableName = name;
286
            return this;
287
        }
288

    
289
        @Override
290
        public String getDatabase() {
291
            return this.databaseName;
292
        }
293

    
294
        @Override
295
        public String getSchema() {
296
            return this.schemaName;
297
        }
298

    
299
        @Override
300
        public String getName() {
301
            return this.tableName;
302
        }
303
        
304
        @Override
305
        public boolean has_schema() {
306
            if( !supportSchemas() ) {
307
                return false;
308
            }
309
            return !StringUtils.isEmpty(this.schemaName);
310
        }
311

    
312
        @Override
313
        public boolean has_database() {
314
            return !StringUtils.isEmpty(this.databaseName);
315
        }
316
        
317
        @Override
318
        public String toString() {
319
            if( this.has_database()) {
320
                if( this.has_schema()) {
321
                    return identifier(this.databaseName) + "." + 
322
                           identifier(this.schemaName) + "." + 
323
                           identifier(this.tableName);
324
                }
325
            } else {
326
                if( this.has_schema()) {
327
                    return identifier(this.schemaName) + "." + 
328
                           identifier(this.tableName);
329
                }                
330
            }
331
            return identifier(this.tableName);
332
        }
333

    
334
    }
335

    
336
    public class CountBuilderBase extends AbstractValue implements CountBuilder {
337

    
338
        protected Value value;
339
        protected boolean distinct;
340
        protected boolean all ;
341
        
342
        public CountBuilderBase() {
343
            this.value = null;
344
            this.distinct = false;
345
            this.all = false;
346
        }
347
        
348
        @Override
349
        public CountBuilder all() {
350
            this.all = true;
351
            return this;
352
        }
353

    
354
        @Override
355
        public CountBuilder column(Value value) {
356
            this.value = value;
357
            return this;
358
        }
359

    
360
        @Override
361
        public CountBuilder distinct() {
362
            this.distinct = true;
363
            return this;
364
        }
365

    
366
        @Override
367
        public String toString() {
368
            if( this.all ) {
369
                return MessageFormat.format(
370
                    config.getString(SQLConfig.count),
371
                    "*"
372
                );
373
            }
374
            if( this.distinct ) {
375
                return MessageFormat.format(
376
                    config.getString(SQLConfig.count_distinct),
377
                    value.toString()
378
                );
379
            }
380
            return MessageFormat.format(
381
                config.getString(SQLConfig.count),
382
                value.toString()
383
            );
384
        }
385
        
386
        
387
    }
388
    
389
    public class FromBuilderBase implements FromBuilder {
390

    
391
        protected TableNameBuilder tableName= null;
392
        private String subquery = null;
393
        private String passthrough = null;
394

    
395
        @Override
396
        public TableNameBuilder table() {
397
            if( tableName == null ) {
398
                this.tableName = createTableNameBuilder();
399
            }
400
            return this.tableName;
401
        }
402

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

    
413
        @Override
414
        public FromBuilder custom(String passthrough) {
415
            this.passthrough = passthrough;
416
            return this;
417
        }
418

    
419
        @Override
420
        public FromBuilder subquery(String subquery) {
421
            this.subquery = subquery;
422
            return this;
423
        }
424
        
425
        @Override
426
        public String toString() {
427
            if( ! StringUtils.isEmpty(passthrough) ) {
428
                return passthrough;
429
            }
430
            if( ! StringUtils.isEmpty(subquery) ) {
431
                return "( " + this.subquery + ") as _subquery_alias_ ";
432
            }
433
            return this.tableName.toString();
434
        }
435

    
436
    }
437

    
438
    public class SelectColumnBuilderBase implements SelectColumnBuilder {
439

    
440
        private Variable name = null;
441
        private String alias = null;
442
        private Value value = null;
443
        private boolean asGeometry = false;
444
        
445
        @Override
446
        public void accept(Visitor visitor, VisitorFilter filter) {
447
            if( filter.accept(this) ) {
448
                visitor.visit(this);
449
            }
450
            if( this.name != null ) {
451
                this.name.accept(visitor, filter);
452
            }
453
            if( this.value != null ) {
454
                this.value.accept(visitor, filter);
455
            }
456
        }
457

    
458
        @Override
459
        public SelectColumnBuilder name(String name) {
460
            String quote = config.getString(Config.quote_for_identifiers);
461
            if (name.startsWith(quote)) {
462
                // Remove quotes
463
                name = name.substring(1, name.length() - 1);
464
            }
465
            this.name = variable(name);
466
            this.value = null;
467
            this.asGeometry = false;
468
            return this;
469
        }
470

    
471
        @Override
472
        public SelectColumnBuilder all() {
473
            this.name = null;
474
            this.value = custom("*");
475
            this.asGeometry = false;
476
            return this;
477
        }
478
        
479
        @Override
480
        public SelectColumnBuilder as_geometry() {
481
            this.asGeometry = true;
482
            return this;
483
        }
484
       
485
        @Override
486
        public SelectColumnBuilder value(Value value) {
487
            this.value = value;
488
            this.name = null;
489
            return this;
490
        }
491

    
492
        @Override
493
        public SelectColumnBuilder as(String alias) {
494
            this.alias = alias;
495
            return this;
496
        }
497

    
498
        @Override
499
        public String getName() {
500
            return this.name.getName();
501
        }
502
        
503
        @Override
504
        public String getAlias() {
505
            return this.alias;
506
        }
507
        
508
        @Override
509
        public String getValue() {
510
            return this.alias;
511
        }
512

    
513
        @Override
514
        public String toString() {
515
            StringBuilder builder = new StringBuilder();
516
            if( this.asGeometry ) {
517
                builder.append(getAsGeometry(this.name).toString());
518
            } else {
519
                if( this.name != null ) {
520
                    builder.append(this.name.toString());
521
                } else {
522
                    builder.append(this.value.toString());
523
                }
524
            }
525
            if( this.alias != null ) {
526
                builder.append(" AS ");
527
                builder.append(identifier(this.alias));
528
            }
529
            return builder.toString();
530
        }
531
    }
532

    
533
    public class OrderByBuilderBase implements OrderByBuilder {
534
        protected String value;
535
        protected String custom;
536
        protected boolean ascending;
537
        
538
        public OrderByBuilderBase() {
539
            this.ascending = true;
540
        }
541

    
542
        @Override
543
        public void accept(Visitor visitor, VisitorFilter filter) {
544
            if( filter.accept(this) ) {
545
                visitor.visit(this);
546
            }
547
        }
548

    
549
        @Override
550
        public OrderByBuilder column(String name) {
551
            this.value = name;
552
            return this;
553
        }
554

    
555
        @Override
556
        public OrderByBuilder custom(String order) {
557
            this.custom = order;
558
            return this;
559
        }
560

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

    
567
        @Override
568
        public OrderByBuilder ascending(boolean asc) {
569
            this.ascending = asc;
570
            return this;
571
        }
572

    
573
        @Override
574
        public OrderByBuilder descending() {
575
            this.ascending = false;
576
            return this;
577
        }
578

    
579
        @Override
580
        public String toString() {
581
            if( !StringUtils.isEmpty(this.custom) ) {
582
                return this.custom;
583
            }
584
            if( this.ascending ) {
585
                return this.value + " ASC";
586
            }
587
            return this.value + " DESC";
588
        }
589
    }
590
    
591
    public class SelectBuilderBase implements SelectBuilder {
592

    
593
        protected FromBuilder from;
594
        protected ExpressionBuilder where;
595
        protected long limit = -1;
596
        protected long offset = -1;
597
        protected List<SelectColumnBuilder> columns;
598
        protected List<OrderByBuilder> order_by;
599
        protected boolean distinct;
600

    
601
        public SelectBuilderBase() {
602
            this.columns = new ArrayList<>();
603
            this.distinct = false;
604
        }
605

    
606
        @Override
607
        public void accept(Visitor visitor, VisitorFilter filter) {
608
            if( filter.accept(this) ) {
609
                visitor.visit(this);
610
            }
611
            for (SelectColumnBuilder column : columns) {
612
                column.accept(visitor,filter);
613
            }
614
            if( this.has_from() ) {
615
                this.from.accept(visitor,filter);
616
            }
617
            if( this.has_where() ) {
618
                this.where.accept(visitor,filter);
619
            }
620
            if( this.has_order_by() ) {
621
                for (OrderByBuilder order : order_by) {
622
                    order.accept(visitor,filter);
623
                }
624
            }
625
        }
626

    
627
        @Override
628
        public SelectBuilder distinct() {
629
            this.distinct = true;
630
            return this;
631
        }
632
        
633
        @Override
634
        public SelectColumnBuilder column() {
635
            SelectColumnBuilder builder = createSelectColumnBuilder();
636
            this.columns.add(builder);
637
            return builder;
638
        }
639

    
640
        @Override
641
        public boolean has_column(String name) {
642
            for (SelectColumnBuilder column : columns) {
643
                if( name.equals(column.getName()) ) {
644
                    return true;
645
                }
646
            }
647
            return false;
648
        }
649

    
650
        @Override
651
        public FromBuilder from() {
652
            if (this.from == null) {
653
                this.from = createFromBuilder();
654
            }
655
            return this.from;
656
        }
657

    
658
        @Override
659
        public boolean has_from() {
660
            return this.from != null;
661
        }
662
        
663
        @Override
664
        public ExpressionBuilder where() {
665
            if (this.where == null) {
666
                this.where = createExpressionBuilder();
667
            }
668
            return this.where;
669
        }
670

    
671
        @Override
672
        public boolean has_where() {
673
            if( this.where == null ) {
674
                return false;
675
            }
676
            return this.where.getValue() != null;
677
        }
678
        
679
        @Override
680
        public SelectBuilder limit(long limit) {
681
            this.limit = limit;
682
            return this;
683
        }
684

    
685
        @Override
686
        public boolean has_limit() {
687
            return this.limit > 0;
688
        }
689

    
690
        @Override
691
        public SelectBuilder offset(long offset) {
692
            this.offset = offset;
693
            return this;
694
        }
695

    
696
        @Override
697
        public boolean has_offset() {
698
            return this.offset > 0;
699
        }
700

    
701
        @Override
702
        public OrderByBuilder order_by() {
703
            if( this.order_by == null ) {
704
                this.order_by = new ArrayList<>();
705
            }
706
            OrderByBuilder order = createOrderByBuilder();
707
            this.order_by.add(order);
708
            return order;
709
        }
710

    
711
        @Override
712
        public boolean has_order_by() {
713
            if( this.order_by == null ) {
714
                return false;
715
            }
716
            return !this.order_by.isEmpty();
717
        }
718
        
719
        protected boolean isValid(StringBuilder message) {
720
            if( message == null ) {
721
                message = new StringBuilder();
722
            }
723
            if( this.has_offset() && !this.has_order_by() ) {
724
                // Algunos gestores de BBDD requieren que se especifique un
725
                // orden para poder usar OFFSET. Como eso parece buena idea para
726
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
727
                // siempre.
728
                message.append("Can't use OFFSET without an ORDER BY.");
729
                return false;
730
            }
731
            return true;
732
        }
733
        
734
        @Override
735
        public String toString() {
736
            StringBuilder builder = new StringBuilder();
737
            if( !this.isValid(builder) ) {
738
                throw new IllegalStateException(builder.toString());
739
            }
740
            builder.append("SELECT ");
741
            if( this.distinct ) {
742
                builder.append("DISTINCT ");
743
            }
744
            boolean first = true;
745
            for (SelectColumnBuilder column : columns) {
746
                if (first) {
747
                    first = false;
748
                } else {
749
                    builder.append(", ");
750
                }
751
                builder.append(column.toString());
752
            }
753

    
754
            if ( this.has_from() ) {
755
                builder.append(" FROM ");
756
                builder.append(this.from.toString());
757
            }
758
            if ( this.has_where() ) {
759
                builder.append(" WHERE ");
760
                builder.append(this.where.toString());
761
            }
762
            
763
            if( this.has_order_by() ) {
764
                builder.append(" ORDER BY ");
765
                first = true;
766
                for (OrderByBuilder item : this.order_by) {
767
                    if (first) {
768
                        first = false;
769
                    } else {
770
                        builder.append(", ");
771
                    }
772
                    builder.append(item.toString());                    
773
                }   
774
            }
775
            
776
            if ( this.has_limit() ) {
777
                builder.append(" LIMIT ");
778
                builder.append(this.limit);
779
            }
780
            if ( this.has_offset() ) {
781
                builder.append(" OFFSET ");
782
                builder.append(this.offset);
783
            }
784
            return builder.toString();
785

    
786
        }
787
    }
788

    
789
    public class DropTableBuilderBase implements DropTableBuilder {
790

    
791
        protected TableNameBuilder table;
792

    
793
        @Override
794
        public TableNameBuilder table() {
795
            if( table == null ) {
796
                table = createTableNameBuilder();
797
            }
798
            return table;
799
        }
800

    
801
        @Override
802
        public void accept(Visitor visitor, VisitorFilter filter) {
803
            if( filter.accept(this) ) {
804
                visitor.visit(this);
805
            }
806
            this.table.accept(visitor,filter);
807
        }
808
        
809
        @Override
810
        public String toString() {
811
            StringBuilder builder = new StringBuilder();
812
            boolean first = true;
813
            for (String sql : toStrings()) {
814
                if( StringUtils.isEmpty(sql) ) {
815
                    continue;
816
                }
817
                if (first) {
818
                    first = false;
819
                } else {
820
                    builder.append("; ");
821
                }
822
                builder.append(sql);
823
            }
824
            return builder.toString();
825
        }
826

    
827
        @Override
828
        public List<String> toStrings() {
829
            List<String> sqls = new ArrayList<>();
830

    
831
            sqls.add(
832
                    MessageFormat.format(
833
                            config.getString(SQLConfig.DROP_TABLE_table),
834
                            this.table.toString()
835
                    )
836
            );
837
            String sql;
838
            if( config.has_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table) ) {
839
                if (this.table.has_schema()) {
840
                    sql = MessageFormat.format(
841
                            config.getString(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table),
842
                            string(this.table.getSchema()),
843
                            string(this.table.getName())
844
                    );
845
                } else {
846
                    sql = MessageFormat.format(
847
                            config.getString(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table),
848
                            identifier(this.table.getName())
849
                    );
850
                }
851
                if( !StringUtils.isEmpty(sql) ) {
852
                    sqls.add(sql);
853
                }
854
            }
855
            return sqls;
856
        }
857
    }
858

    
859
    public class GrantRoleBuilderBase implements GrantRoleBuilder {
860
        protected TableNameBuilder table;
861
        protected String role;
862
        protected Set<Privilege> privileges;
863

    
864
        public GrantRoleBuilderBase(TableNameBuilder table, String role) {
865
            this.table = table;
866
            this.role = role;
867
            this.privileges = new HashSet<>();
868
        }
869

    
870
        @Override
871
        public GrantRoleBuilder privilege(Privilege privilege) {
872
            privileges.add(privilege);
873
            return this;
874
        }
875
        
876
        @Override
877
        public GrantRoleBuilder select() {
878
             privileges.add(Privilege.SELECT);
879
            return this;
880
        }
881

    
882
        @Override
883
        public GrantRoleBuilder update() {
884
             privileges.add(Privilege.UPDATE);
885
            return this;
886
        }
887

    
888
        @Override
889
        public GrantRoleBuilder insert() {
890
            privileges.add(Privilege.INSERT);
891
            return this;
892
        }
893

    
894
        @Override
895
        public GrantRoleBuilder delete() {
896
            privileges.add(Privilege.DELETE);
897
            return this;
898
        }
899

    
900
        @Override
901
        public GrantRoleBuilder truncate() {
902
            privileges.add(Privilege.TRUNCATE);
903
            return this;
904
        }
905

    
906
        @Override
907
        public GrantRoleBuilder reference() {
908
            privileges.add(Privilege.REFERENCE);
909
            return this;
910
        }
911

    
912
        @Override
913
        public GrantRoleBuilder trigger() {
914
            privileges.add(Privilege.TRIGGER);
915
            return this;
916
        }
917

    
918
        @Override
919
        public GrantRoleBuilder all() {
920
            privileges.add(Privilege.ALL);
921
            return this;
922
        }
923

    
924
        protected String getPrivilegeName(Privilege privilege) {
925
            switch(privilege) {
926
                case DELETE:
927
                    return "DELETE";
928
                case INSERT:
929
                    return "INSERT";
930
                case REFERENCE:
931
                    return "REFERENCE";
932
                case SELECT:
933
                    return "SELECT";
934
                case TRIGGER:
935
                    return "TRIGGER";
936
                case TRUNCATE:
937
                    return "TRUNCATE";
938
                case UPDATE:
939
                    return "UPDATE";
940
                case ALL:
941
                default:
942
                    return "ALL";
943
            }
944
        }
945
        
946
        @Override
947
        public String toString() {
948
            StringBuilder builder = new StringBuilder();
949
            boolean first = true;
950
            for (Privilege privilege : privileges) {
951
                if (first) {
952
                    first = false;
953
                } else {
954
                    builder.append(", ");
955
                }
956
                builder.append( this.getPrivilegeName(privilege));
957
            }
958
            String sql = MessageFormat.format(
959
                    config.getString(SQLConfig.GRANT_privileges_ON_table_TO_role),
960
                    builder.toString(),
961
                    table.toString(),
962
                    role
963
            );
964
            return sql;
965
        }
966
    }
967
    
968
    public class GrantBuilderBase implements GrantBuilder {
969

    
970
        protected TableNameBuilder table;
971
        protected Map<String, GrantRoleBuilder> roles;
972

    
973
        public GrantBuilderBase() {
974
            this.roles = new HashMap<>();
975
        }
976
        
977
        @Override
978
        public TableNameBuilder table() {
979
            if( table == null ) {
980
                table = createTableNameBuilder();
981
            }
982
            return table;
983
        }
984

    
985
        @Override
986
        public void accept(Visitor visitor, VisitorFilter filter) {
987
            if( filter.accept(this) ) {
988
                visitor.visit(this);
989
            }
990
            if( this.table!= null ) {
991
                this.table.accept(visitor,filter);
992
            }
993
        }
994
        
995
        @Override
996
        public GrantRoleBuilder role(String role) {
997
            GrantRoleBuilder roleBuilder = this.roles.get(role);
998
            if( roleBuilder == null ) {
999
                roleBuilder = createGrantRoleBuilder(this.table(), role);
1000
                this.roles.put(role, roleBuilder);
1001
            }
1002
            return roleBuilder;
1003
        }
1004

    
1005
        @Override
1006
        public String toString() {
1007
            StringBuilder builder = new StringBuilder();
1008
            boolean first = true;
1009
            for (String sql : toStrings()) {
1010
                if( StringUtils.isEmpty(sql) ) {
1011
                    continue;
1012
                }
1013
                if (first) {
1014
                    first = false;
1015
                } else {
1016
                    builder.append("; ");
1017
                }
1018
                builder.append(sql);
1019
            }
1020
            return builder.toString();
1021
        }
1022

    
1023
        @Override
1024
        public List<String> toStrings() {
1025
            List<String> sqls = new ArrayList<>();
1026
            for (GrantRoleBuilder role : roles.values()) {
1027
                sqls.add(role.toString());
1028
            }
1029
            return sqls;
1030
        }
1031
    }
1032

    
1033
    public class UpdateColumnBuilderBase extends InsertColumnBuilderBase implements UpdateColumnBuilder {
1034
        
1035
        public UpdateColumnBuilderBase() {
1036
            super();
1037
        }
1038

    
1039
        @Override
1040
        public UpdateColumnBuilder name(String name) {
1041
            return (UpdateColumnBuilder) super.name(name);
1042
        }
1043

    
1044
        @Override
1045
        public UpdateColumnBuilder with_value(Value value) {
1046
            return (UpdateColumnBuilder) super.with_value(value);
1047
        }
1048
        
1049
    }
1050
    
1051
    public class UpdateBuilderBase implements UpdateBuilder {
1052

    
1053
        protected ExpressionBuilder where;
1054
        protected List<UpdateColumnBuilder> columns;
1055
        protected TableNameBuilder table;
1056

    
1057
        public UpdateBuilderBase() {
1058
            this.columns = new ArrayList<>();
1059
        }
1060

    
1061
        @Override
1062
        public void accept(Visitor visitor, VisitorFilter filter) {
1063
            if( filter.accept(this) ) {
1064
                visitor.visit(this);
1065
            }
1066
            if( this.table != null ) {
1067
                this.table.accept(visitor, filter);
1068
            }
1069
            for (UpdateColumnBuilder column : columns) {
1070
                column.accept(visitor, filter);
1071
            }
1072
            if( this.has_where() ) {
1073
                this.where.accept(visitor, filter);
1074
            }
1075
        }
1076

    
1077
        @Override
1078
        public ExpressionBuilder where() {
1079
            if (this.where == null) {
1080
                this.where = createExpressionBuilder();
1081
            }
1082
            return this.where;
1083
        }
1084

    
1085
        @Override
1086
        public TableNameBuilder table() {
1087
            if( table == null ) {
1088
                table = createTableNameBuilder();
1089
            }
1090
            return table;
1091
        }
1092

    
1093
        @Override
1094
        public UpdateColumnBuilder column() {
1095
            UpdateColumnBuilder column = createUpdateColumnBuilder();
1096
            this.columns.add(column);
1097
            return column;
1098
        }
1099
        
1100
        @Override
1101
        public boolean has_where() {
1102
            return this.where != null;
1103
        }
1104

    
1105
        @Override
1106
        public String toString() {
1107
            /*
1108
             * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
1109
             * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
1110
             * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
1111
             * output_expression [ AS output_name ] [, ...] ]
1112
             */
1113
            StringBuilder columnsAndValues = new StringBuilder();
1114

    
1115
            boolean first = true;
1116
            for (UpdateColumnBuilder column : columns) {
1117
                if (first) {
1118
                    first = false;
1119
                } else {
1120
                    columnsAndValues.append(", ");
1121
                }
1122
                columnsAndValues.append(identifier(column.getName()));
1123
                columnsAndValues.append(" = ");
1124
                columnsAndValues.append(column.getValue().toString());
1125
            }
1126
            
1127
            String sql;
1128
            if ( this.has_where() ) {
1129
                sql = MessageFormat.format(
1130
                        config.getString(SQLConfig.UPDATE_table_SET_columnsAndValues_WHERE_expresion),
1131
                        this.table.toString(),
1132
                        columnsAndValues.toString(),
1133
                        this.where.toString()
1134
                );
1135
            } else {
1136
                sql = MessageFormat.format(
1137
                        config.getString(SQLConfig.UPDATE_table_SET_columnsAndValues),
1138
                        this.table.toString(),
1139
                        columnsAndValues.toString()
1140
                );
1141
            }
1142
            return sql;
1143
        }
1144
    }
1145

    
1146
    public class DeleteBuilderBase implements DeleteBuilder {
1147

    
1148
        protected ExpressionBuilder where;
1149
        protected TableNameBuilder table;
1150

    
1151
        public DeleteBuilderBase() {
1152
        }
1153

    
1154
        @Override
1155
        public void accept(Visitor visitor, VisitorFilter filter) {
1156
            if( filter.accept(this) ) {
1157
                visitor.visit(this);
1158
            }
1159
            if( this.table != null ) {
1160
                this.table.accept(visitor, filter);
1161
            }
1162
            if( this.has_where() ) {
1163
                this.where.accept(visitor, filter);
1164
            }
1165
        }
1166

    
1167
        @Override
1168
        public ExpressionBuilder where() {
1169
            if (this.where == null) {
1170
                this.where = createExpressionBuilder();
1171
            }
1172
            return this.where;
1173
        }
1174

    
1175
        @Override
1176
        public TableNameBuilder table() {
1177
            if( table == null ) {
1178
                table = createTableNameBuilder();
1179
            }
1180
            return table;
1181
        }
1182

    
1183
        @Override
1184
        public boolean has_where() {
1185
            return this.where != null;
1186
        }
1187

    
1188
        @Override
1189
        public String toString() {
1190
            /*
1191
             * DELETE FROM table_name
1192
             * WHERE some_column=some_value; 
1193
             */
1194
            String sql;
1195
            if( this.has_where() ) {
1196
                sql = MessageFormat.format(
1197
                        config.getString(SQLConfig.DELETE_FROM_table_WHERE_expresion),
1198
                        this.table.toString(),
1199
                        this.where.toString()
1200
                );
1201
            } else {
1202
                sql = MessageFormat.format(
1203
                        config.getString(SQLConfig.DELETE_FROM_table),
1204
                        this.table.toString()
1205
                );
1206
            }
1207
            return sql;
1208
        }
1209
    }
1210

    
1211
    public class CreateIndexBuilderBase implements CreateIndexBuilder {
1212

    
1213
        protected boolean ifNotExist = false;
1214
        protected boolean isUnique = false;
1215
        protected String indexName;
1216
        protected boolean isSpatial = false;
1217
        protected TableNameBuilder table;
1218
        protected final List<String> columns;
1219
        
1220
        public CreateIndexBuilderBase() {
1221
            this.columns = new ArrayList<>();
1222
        }
1223
        
1224
        @Override
1225
        public CreateIndexBuilder unique() {
1226
            this.isUnique = true;
1227
            return this;
1228
        }
1229

    
1230
        @Override
1231
        public CreateIndexBuilder if_not_exist() {
1232
            this.ifNotExist = true;
1233
            return this;
1234
        }
1235

    
1236
        @Override
1237
        public CreateIndexBuilder name(String name) {
1238
            this.indexName = name;
1239
            return this;
1240
        }
1241

    
1242
        @Override
1243
        public CreateIndexBuilder spatial() {
1244
            this.isSpatial = true;
1245
            return this;
1246
        }
1247

    
1248
        @Override
1249
        public CreateIndexBuilder column(String name) {
1250
            this.columns.add(name);
1251
            return this;
1252
        }
1253

    
1254
        @Override
1255
        public TableNameBuilder table() {
1256
            if( table == null ) {
1257
                table = createTableNameBuilder();
1258
            }
1259
            return table;
1260
        }
1261

    
1262
        @Override
1263
        public void accept(Visitor visitor, VisitorFilter filter) {
1264
            if( filter.accept(this) ) {
1265
                visitor.visit(this);
1266
            }
1267
            if( this.table != null ) {
1268
                this.table.accept(visitor, filter);
1269
            }
1270
        }
1271
        
1272
        @Override
1273
        public List<String> toStrings() {
1274
            StringBuilder builder = new StringBuilder();
1275
            builder.append("CREATE ");
1276
            if( this.isUnique ) {
1277
                builder.append("UNIQUE ");
1278
            }
1279
            builder.append("INDEX ");
1280
            if( this.ifNotExist ) {
1281
                builder.append("IF NOT EXISTS ");
1282
            }
1283
            builder.append(identifier(this.indexName));
1284
            builder.append(" ON ");
1285
            builder.append(this.table.toString());
1286
            if( this.isSpatial ) {
1287
                builder.append(" USING GIST ");
1288
            }
1289
            builder.append(" ( ");
1290
            boolean is_first_column = true;
1291
            for( String column : this.columns) {
1292
                if( is_first_column ) {
1293
                    is_first_column = false;
1294
                } else {
1295
                    builder.append(", ");
1296
                }
1297
                builder.append(column);
1298
            }
1299
            builder.append(" )");
1300
            
1301
            List<String> sqls = new ArrayList<>();
1302
            sqls.add(builder.toString());
1303
            return sqls;
1304
        }
1305

    
1306
    }
1307
    
1308
    public class AlterTableBuilderBase implements AlterTableBuilder {
1309

    
1310
        protected TableNameBuilder table;
1311
        protected List<String> drops;
1312
        protected List<ColumnDescriptorBuilderBase> adds;
1313
        protected List<ColumnDescriptorBuilderBase> alters;
1314
        protected List<Pair<String,String>> renames;
1315

    
1316
        public AlterTableBuilderBase() {
1317
            this.drops = new ArrayList<>();
1318
            this.adds = new ArrayList<>();
1319
            this.alters = new ArrayList<>();
1320
            this.renames = new ArrayList<>();
1321
        }
1322

    
1323
        @Override
1324
        public boolean isEmpty() {
1325
            return this.drops.isEmpty() && 
1326
                this.adds.isEmpty() && 
1327
                this.alters.isEmpty() && 
1328
                this.renames.isEmpty();
1329
        }
1330
        
1331
        @Override
1332
        public void accept(Visitor visitor, VisitorFilter filter) {
1333
            if( filter.accept(this) ) {
1334
                visitor.visit(this);
1335
            }
1336
            if( this.table != null ) {
1337
                this.table.accept(visitor, filter);
1338
            }
1339
        }
1340

    
1341
        @Override
1342
        public TableNameBuilder table() {
1343
            if( table == null ) {
1344
                table = createTableNameBuilder();
1345
            }
1346
            return table;
1347
        }
1348

    
1349
        @Override
1350
        public AlterTableBuilder drop_column(String columnName) {
1351
            this.drops.add(columnName);
1352
            return this;
1353
        }
1354

    
1355
        @Override
1356
        public AlterTableBuilder add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1357
            if (isPk || isAutomatic) {
1358
                allowNulls = false;
1359
            }
1360
            this.adds.add(new ColumnDescriptorBuilderBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1361
            return this;
1362
        }
1363

    
1364
        @Override
1365
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1366
            if( StringUtils.isEmpty(columnName) ) {
1367
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1368
            }
1369
            this.adds.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1370
            return this;
1371
        }
1372

    
1373
        @Override
1374
        public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1375
            if( StringUtils.isEmpty(columnName) ) {
1376
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1377
            }
1378
            this.adds.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1379
            return this;
1380
        }
1381

    
1382
        @Override
1383
        public AlterTableBuilder alter_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1384
            if (isPk || isAutomatic) {
1385
                allowNulls = false;
1386
            }
1387
            this.alters.add(new ColumnDescriptorBuilderBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1388
            return this;
1389
        }
1390

    
1391
        @Override
1392
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1393
            if( StringUtils.isEmpty(columnName) ) {
1394
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1395
            }
1396
            this.alters.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1397
            return this;
1398
        }
1399

    
1400
        @Override
1401
        public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1402
            if( StringUtils.isEmpty(columnName) ) {
1403
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1404
            }
1405
            this.alters.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1406
            return this;
1407
        }
1408

    
1409
        @Override
1410
        public AlterTableBuilder rename_column(String source, String target) {
1411
            this.renames.add(new ImmutablePair(source, target));
1412
            return this;
1413
        }
1414

    
1415
        @Override
1416
        public String toString() {
1417
            StringBuilder builder = new StringBuilder();
1418
            boolean first = true;
1419
            for (String sql : toStrings()) {
1420
                if( StringUtils.isEmpty(sql) ) {
1421
                    continue;
1422
                }
1423
                if (first) {
1424
                    first = false;
1425
                } else {
1426
                    builder.append("; ");
1427
                }
1428
                builder.append(sql);
1429
            }
1430
            return builder.toString();
1431
        }
1432

    
1433
        @Override
1434
        public List<String> toStrings() {
1435
            List<String> sqls = new ArrayList<>();
1436
            if( this.isEmpty() ) {
1437
                return sqls;
1438
            }
1439
            for (String column : drops) {
1440
                StringBuilder builder = new StringBuilder();
1441
                builder.append("ALTER TABLE ");
1442
                builder.append(this.table.toString());
1443
                builder.append(" DROP COLUMN IF EXISTS ");
1444
                builder.append(identifier(column)); 
1445
                sqls.add(builder.toString());
1446
            }
1447
            for (ColumnDescriptorBuilderBase column : adds) {
1448
                StringBuilder builder = new StringBuilder();
1449
                builder.append("ALTER TABLE ");
1450
                builder.append(this.table.toString());
1451
                builder.append(" ADD COLUMN ");
1452
                builder.append(identifier(column.getName())); 
1453
                builder.append(" ");
1454
                if( column.getType() == DataTypes.INT && column.isAutomatic() ) {
1455
                    builder.append(" SERIAL");
1456
                } else {
1457
                    builder.append(
1458
                        sqltype(
1459
                            column.getType(), 
1460
                            column.getPrecision(), 
1461
                            column.getSize(),
1462
                            column.getGeometryType(),
1463
                            column.getGeometrySubtype()
1464
                        )
1465
                    );
1466
                }
1467
                if (column.getDefaultValue() == null) {
1468
                    if (column.allowNulls()) {
1469
                        builder.append(" DEFAULT NULL");
1470
                    }
1471
                } else {
1472
                    builder.append(" DEFAULT '");
1473
                    builder.append(column.getDefaultValue().toString());
1474
                    builder.append("'");
1475
                }
1476
                if (column.allowNulls()) {
1477
                    builder.append(" NULL");
1478
                } else {
1479
                    builder.append(" NOT NULL");
1480
                }
1481
                if (column.isPrimaryKey()) {
1482
                    builder.append(" PRIMARY KEY");
1483
                }
1484
                sqls.add(builder.toString());
1485
            }
1486
            for (ColumnDescriptorBuilderBase column : alters) {
1487
                StringBuilder builder = new StringBuilder();
1488
                builder.append("ALTER TABLE ");
1489
                builder.append(this.table.toString());
1490
                builder.append(" ALTER COLUMN ");
1491
                builder.append(identifier(column.getName())); 
1492
                builder.append(" SET DATA TYPE ");
1493
                if( column.getType() == DataTypes.INT && column.isAutomatic() ) {
1494
                    builder.append(" SERIAL");
1495
                } else {
1496
                    builder.append(
1497
                        sqltype(
1498
                            column.getType(), 
1499
                            column.getPrecision(), 
1500
                            column.getSize(),
1501
                            column.getGeometryType(),
1502
                            column.getGeometrySubtype()
1503
                        )
1504
                    );
1505
                }
1506
                if (column.getDefaultValue() == null) {
1507
                    if (column.allowNulls()) {
1508
                        builder.append(" DEFAULT NULL");
1509
                    } else {
1510
                        builder.append(" DROP DEFAULT");
1511
                    }
1512
                } else {
1513
                    builder.append(" DEFAULT '");
1514
                    builder.append(column.getDefaultValue().toString());
1515
                    builder.append("'");
1516
                }
1517
                sqls.add(builder.toString());
1518
            }
1519
            for (Pair<String,String> pair : renames) {
1520
                StringBuilder builder = new StringBuilder();
1521
                builder.append("ALTER TABLE ");
1522
                builder.append(this.table.toString());
1523
                builder.append(" RENAME COLUMN ");
1524
                builder.append(identifier(pair.getLeft())); 
1525
                builder.append(" TO ");
1526
                builder.append(identifier(pair.getRight())); 
1527
                sqls.add(builder.toString());
1528
            }
1529
            return sqls;
1530
        }
1531

    
1532
    }
1533

    
1534
    public class CreateTableBuilderBase implements CreateTableBuilder {
1535

    
1536
        protected TableNameBuilder table;
1537
        protected List<ColumnDescriptorBuilderBase> columns;
1538

    
1539
        public CreateTableBuilderBase() {
1540
            this.columns = new ArrayList<>();
1541
        }
1542

    
1543
        @Override
1544
        public void accept(Visitor visitor, VisitorFilter filter) {
1545
            if( filter.accept(this) ) {
1546
                visitor.visit(this);
1547
            }
1548
            if( this.table != null ) {
1549
                this.table.accept(visitor, filter);
1550
            }
1551
        }
1552

    
1553
        @Override
1554
        public TableNameBuilder table() {
1555
            if( table == null ) {
1556
                table = createTableNameBuilder();
1557
            }
1558
            return table;
1559
        }
1560

    
1561
        @Override
1562
        public CreateTableBuilderBase add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
1563
            if( StringUtils.isEmpty(columnName) ) {
1564
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1565
            }
1566
            if (isPk || isAutomatic) {
1567
                allowNulls = false;
1568
            }
1569
            this.columns.add(new ColumnDescriptorBuilderBase(columnName, type, type_p, type_s, isPk, isIndexed, allowNulls, isAutomatic, defaultValue));
1570
            return this;
1571
        }
1572

    
1573
        @Override
1574
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
1575
            if( StringUtils.isEmpty(columnName) ) {
1576
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1577
            }
1578
            this.columns.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, proj, isIndexed, allowNulls));
1579
            return this;
1580
        }
1581

    
1582
        @Override
1583
        public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
1584
            if( StringUtils.isEmpty(columnName) ) {
1585
                throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
1586
            }
1587
            this.columns.add(new ColumnDescriptorBuilderBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
1588
            return this;
1589
        }
1590

    
1591
        @Override
1592
        public ColumnDescriptorBuilder getColumnDescriptor(String columnName) {
1593
            if( StringUtils.isEmpty(columnName) ) {
1594
                return null;
1595
            }
1596
            for (ColumnDescriptorBuilderBase column : columns) {
1597
                if( columnName.equals(column.getName()) ) {
1598
                    return column;
1599
                }
1600
            }
1601
            return null;
1602
        }
1603
                
1604
        @Override
1605
        public String toString() {
1606
            StringBuilder builder = new StringBuilder();
1607
            boolean first = true;
1608
            for (String sql : toStrings()) {
1609
                if( StringUtils.isEmpty(sql) ) {
1610
                    continue;
1611
                }
1612
                if (first) {
1613
                    first = false;
1614
                } else {
1615
                    builder.append("; ");
1616
                }
1617
                builder.append(sql);
1618
            }
1619
            return builder.toString();
1620
        }
1621

    
1622
        @Override
1623
        public List<String> toStrings() {
1624
            List<String> sqls = new ArrayList<>();
1625
            /**
1626
             * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
1627
             * table_name ( { column_name data_type [ DEFAULT default_expr ] [
1628
             * column_constraint [ ... ] ] | table_constraint | LIKE
1629
             * parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] } [, ... ] )
1630
             * [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS
1631
             * ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
1632
             *
1633
             * where column_constraint is:
1634
             *
1635
             * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE |
1636
             * PRIMARY KEY | CHECK (expression) | REFERENCES reftable [ (
1637
             * refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON
1638
             * DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT
1639
             * DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1640
             *
1641
             * and table_constraint is:
1642
             *
1643
             * [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] )
1644
             * | PRIMARY KEY ( column_name [, ... ] ) | CHECK ( expression ) |
1645
             * FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ (
1646
             * refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
1647
             * SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE
1648
             * | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
1649
             */
1650
            StringBuilder builder = new StringBuilder();
1651

    
1652
            builder.append("CREATE TABLE ");
1653
            builder.append(this.table.toString());
1654
            builder.append(" (");
1655
            boolean first = true;
1656
            for (ColumnDescriptorBuilderBase column : columns) {
1657
                if (first) {
1658
                    first = false;
1659
                } else {
1660
                    builder.append(", ");
1661
                }
1662
                builder.append(identifier(column.getName()));
1663
                builder.append(" ");
1664
                if( column.isAutomatic() && column.getType() == DataTypes.INT ) {
1665
                    builder.append("SERIAL");
1666
                } else if( column.isAutomatic() && column.getType() == DataTypes.LONG ) {
1667
                    builder.append("BIGSERIAL");
1668
                } else {
1669
                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
1670
                }
1671
                if (column.getDefaultValue() == null) {
1672
                    if (column.allowNulls()) {
1673
                        builder.append(" DEFAULT NULL");
1674
                    }
1675
                } else {
1676
                    builder.append(" DEFAULT '");
1677
                    builder.append(column.getDefaultValue().toString());
1678
                    builder.append("'");
1679
                }
1680
                if (column.allowNulls()) {
1681
                    builder.append(" NULL");
1682
                } else {
1683
                    builder.append(" NOT NULL");
1684
                }
1685
                if (column.isPrimaryKey()) {
1686
                    builder.append(" PRIMARY KEY");
1687
                }
1688
            }
1689
            builder.append(" )");
1690
            sqls.add(builder.toString());
1691
            return sqls;
1692
        }
1693
    }
1694

    
1695
    public class InsertColumnBuilderBase implements InsertColumnBuilder {
1696
        protected Variable name;
1697
        protected Value value;
1698
        
1699
        public InsertColumnBuilderBase() {
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.name != null ) {
1708
                this.name.accept(visitor, filter);
1709
            }
1710
            if( this.value != null ) {
1711
                this.value.accept(visitor, filter);
1712
            }
1713
        }
1714

    
1715
        @Override
1716
        public InsertColumnBuilder name(String name) {
1717
            this.name = variable(name);
1718
            return this;
1719
        }
1720

    
1721
        @Override
1722
        public InsertColumnBuilder with_value(Value value) {
1723
            this.value = value;
1724
            return this;
1725
        }
1726
        
1727
        @Override
1728
        public String getName() {
1729
            return this.name.getName();
1730
        }
1731
        
1732
        @Override
1733
        public Value getValue() {
1734
            return this.value;
1735
        }
1736
        
1737
        @Override
1738
        public String toString() {
1739
            return this.value.toString();
1740
        }
1741
    }
1742
    
1743
    public class InsertBuilderBase implements InsertBuilder {
1744

    
1745
        protected List<InsertColumnBuilder> columns;
1746
        protected TableNameBuilder table;
1747

    
1748
        public InsertBuilderBase() {
1749
            this.columns = new ArrayList<>();
1750
        }
1751

    
1752
        @Override
1753
        public void accept(Visitor visitor, VisitorFilter filter) {
1754
            if( filter.accept(this) ) {
1755
                visitor.visit(this);
1756
            }
1757
            if( this.table != null ) {
1758
                this.table.accept(visitor, filter);
1759
            }
1760
            for (InsertColumnBuilder column : columns) {
1761
                column.accept(visitor, filter);
1762
            }
1763
        }
1764

    
1765
        @Override
1766
        public TableNameBuilder table() {
1767
            if( table == null ) {
1768
                table = createTableNameBuilder();
1769
            }
1770
            return table;
1771
        }
1772

    
1773
        @Override
1774
        public InsertColumnBuilder column() {
1775
            InsertColumnBuilder column = createInsertColumnBuilder();
1776
            this.columns.add(column);
1777
            return column;
1778
        }
1779

    
1780
        @Override
1781
        public String toString() {
1782
            /*
1783
             * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
1784
             * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
1785
             * output_expression [ AS output_name ] [, ...] ]
1786
             */
1787
            StringBuilder builderColumns = new StringBuilder();
1788
            StringBuilder builderValues = new StringBuilder();
1789
            
1790
            boolean first = true;
1791
            for (InsertColumnBuilder column : columns) {
1792
                if (first) {
1793
                    first = false;
1794
                } else {
1795
                    builderColumns.append(", ");
1796
                }
1797
                builderColumns.append(identifier(column.getName()));
1798
            }
1799
            first = true;
1800
            for (InsertColumnBuilder column : columns) {
1801
                if (first) {
1802
                    first = false;
1803
                } else {
1804
                    builderValues.append(", ");
1805
                }
1806
                builderValues.append(column.toString());
1807
            }
1808
            
1809
            String sql = MessageFormat.format(
1810
                    config.getString(SQLConfig.INSERT_INTO_table_columns_VALUES_values),
1811
                    this.table.toString(),
1812
                    builderColumns.toString(),
1813
                    builderValues.toString()
1814
            );
1815
            return sql;
1816

    
1817
        }
1818
    }
1819

    
1820
    public class UpdateTableStatisticsBuilderBase implements UpdateTableStatisticsBuilder {
1821

    
1822
        protected TableNameBuilder table;
1823

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

    
1834
        @Override
1835
        public TableNameBuilder table() {
1836
            if( table == null ) {
1837
                table = createTableNameBuilder();
1838
            }
1839
            return table;
1840
        }
1841

    
1842
        @Override
1843
        public String toString() {
1844
            StringBuilder builder = new StringBuilder();
1845
            boolean first = true;
1846
            for (String sql : toStrings()) {
1847
                if( StringUtils.isEmpty(sql) ) {
1848
                    continue;
1849
                }
1850
                if (first) {
1851
                    first = false;
1852
                } else {
1853
                    builder.append("; ");
1854
                }
1855
                builder.append(sql);
1856
            }
1857
            return builder.toString();
1858
        }
1859

    
1860
        @Override
1861
        public List<String> toStrings() {
1862
            List<String> sqls = new ArrayList<>();
1863
            
1864
            if( config.has_functionality(SQLConfig.UPDATE_TABLE_STATISTICS_table) ) {
1865
                String sql = MessageFormat.format(
1866
                        config.getString(SQLConfig.UPDATE_TABLE_STATISTICS_table),
1867
                        table.toString()
1868
                    );
1869
                if( !StringUtils.isEmpty(sql) ) {
1870
                    sqls.add(sql);
1871
                }
1872
            }
1873
            return sqls;
1874
        }
1875
    }
1876
    
1877
    public SQLBuilderBase() {
1878
        super();
1879
        config.set(SQLConfig.default_schema, "public");
1880
        config.set(SQLConfig.allowAutomaticValues, true);
1881
        
1882
        config.set(SQLConfig.ST_ExtentAggregate, "ST_Extent({0})");
1883
        config.set(SQLConfig.ST_UnionAggregate, "ST_Union({0})");
1884
        config.set(SQLConfig.count, "COUNT({0})");
1885
        config.set(SQLConfig.count_distinct, "COUNT(DISTINCT {0})");
1886

    
1887
        config.set(SQLConfig.type_boolean, "BOOLEAN");
1888
        config.set(SQLConfig.type_byte, "TINYINT");
1889
        config.set(SQLConfig.type_bytearray, "BYTEA");
1890
        config.set(SQLConfig.type_geometry, "TEXT");
1891
        config.set(SQLConfig.type_char, "CHARACTER(1)");
1892
        config.set(SQLConfig.type_date, "DATE");
1893
        config.set(SQLConfig.type_double, "DOUBLE PRECISION"); //float con 53 bits de mantisa, float(54)
1894
        config.set(SQLConfig.type_numeric_p, "NUMERIC({0})");
1895
        config.set(SQLConfig.type_numeric_ps, "NUMERIC({0},{1})");
1896
        config.set(SQLConfig.type_bigdecimal, "NUMERIC({0},{1})");
1897
        config.set(SQLConfig.type_float, "REAL"); //float con 24 bits de mantisa, float(24)
1898
        config.set(SQLConfig.type_int, "INT");
1899
        config.set(SQLConfig.type_long, "BIGINT");
1900
        config.set(SQLConfig.type_string, "TEXT");
1901
        config.set(SQLConfig.type_string_p, "VARCHAR({0})");
1902
        config.set(SQLConfig.type_time, "TIME");
1903
        config.set(SQLConfig.type_timestamp, "TIMESTAMP");
1904
        config.set(SQLConfig.type_version, "VARCHAR(30)");
1905
        config.set(SQLConfig.type_URI, "TEXT");
1906
        config.set(SQLConfig.type_URL, "TEXT");
1907
        config.set(SQLConfig.type_FILE, "TEXT");
1908
        config.set(SQLConfig.type_FOLDER, "TEXT");
1909

    
1910
        config.set(SQLConfig.DELETE_FROM_table_WHERE_expresion, "DELETE FROM {0} WHERE {1}");
1911
        config.set(SQLConfig.DELETE_FROM_table, "DELETE FROM {0}");
1912
        config.set(SQLConfig.INSERT_INTO_table_columns_VALUES_values, "INSERT INTO {0} ( {1} ) VALUES ( {2} )");
1913
        config.set(SQLConfig.UPDATE_TABLE_STATISTICS_table, "VACUUM ANALYZE {0}");
1914
        config.set(SQLConfig.DROP_TABLE_table, "DROP TABLE {0}");
1915
        config.set(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table, "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}");
1916
        config.set(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table, "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}");
1917
        config.set(SQLConfig.UPDATE_table_SET_columnsAndValues_WHERE_expresion, "UPDATE {0} SET {1} WHERE {2}");
1918
        config.set(SQLConfig.UPDATE_table_SET_columnsAndValues, "UPDATE {0} SET {1}");
1919
        config.set(SQLConfig.GRANT_privileges_ON_table_TO_role, "GRANT {0} ON {1} TO {2}");        
1920
    }
1921
    
1922
    @Override
1923
    public String default_schema() {
1924
        return config.getString(SQLConfig.default_schema);
1925
    }
1926

    
1927
    @Override
1928
    public boolean supportSchemas() {
1929
        return config.getBoolean(Config.support_schemas);
1930
    }
1931
    
1932
    @Override
1933
    @Deprecated
1934
    public String sqltype(int type, int p, int s) {
1935
        return this.sqltype(type, p, s, Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.UNKNOWN);
1936
    }
1937

    
1938
    @Override
1939
    public String sqltype(int type, int p, int s, int geomType, int geomSubtype) {
1940
        switch (type) {
1941
            case DataTypes.BOOLEAN:
1942
                return config.getString(SQLConfig.type_boolean);
1943
            case DataTypes.BYTE:
1944
                return config.getString(SQLConfig.type_byte);
1945
            case DataTypes.BYTEARRAY:
1946
                return config.getString(SQLConfig.type_bytearray);
1947
            case DataTypes.GEOMETRY:
1948
                return config.getString(SQLConfig.type_geometry);
1949
            case DataTypes.CHAR:
1950
                return config.getString(SQLConfig.type_char);
1951
            case DataTypes.DATE:
1952
                return config.getString(SQLConfig.type_date);
1953
            case DataTypes.DOUBLE:
1954
                  // FIXME: Si cargamos la capa "country" al exportarla a
1955
                  // SQLServer falla por:
1956
                  //  Error de desbordamiento aritm?tico al convertir float al tipo de datos numeric.
1957
                  // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
1958
                  // Algeria intenta asignarle un valor de 2320972.0 y falla.
1959
                  // Habria que repasar el proveedor de shape.
1960
                
1961
//                if (p > 1) {
1962
//                    if (s < 0) {
1963
//                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
1964
//                    }
1965
//                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
1966
//                }
1967
                return MessageFormat.format(config.getString(SQLConfig.type_double),p,s);
1968
            case DataTypes.BIGDECIMAL:
1969
                if (p < 1) {
1970
                    p = 20;
1971
                }
1972
                if (s < 0) {
1973
                    s = 10;
1974
                }
1975
                return MessageFormat.format(config.getString(SQLConfig.type_bigdecimal), p,s);
1976
            case DataTypes.FLOAT:
1977
                return MessageFormat.format(config.getString(SQLConfig.type_float), p,s);
1978
            case DataTypes.INT:
1979
                return MessageFormat.format(config.getString(SQLConfig.type_int), p,s);
1980
            case DataTypes.LONG:
1981
                return MessageFormat.format(config.getString(SQLConfig.type_long), p,s);
1982
            case DataTypes.STRING:
1983
                if (p < 0) {
1984
                    return config.getString(SQLConfig.type_string);
1985
                } else if (p < 4096) {
1986
                    return MessageFormat.format(config.getString(SQLConfig.type_string_p),p);
1987
                }
1988
                return config.getString(SQLConfig.type_string);
1989
            case DataTypes.TIME:
1990
                return config.getString(SQLConfig.type_time);
1991
            case DataTypes.TIMESTAMP:
1992
                return config.getString(SQLConfig.type_timestamp);
1993
            case DataTypes.VERSION:
1994
                return config.getString(SQLConfig.type_version);
1995
            case DataTypes.URI:
1996
                return config.getString(SQLConfig.type_URI);
1997
            case DataTypes.URL:
1998
                return config.getString(SQLConfig.type_URL);
1999
            case DataTypes.FILE:
2000
                return config.getString(SQLConfig.type_FILE);
2001
            case DataTypes.FOLDER:
2002
                return config.getString(SQLConfig.type_FOLDER);
2003
            default:
2004
                return null;
2005
        }
2006
    }
2007

    
2008
    private static Map<Pair<Integer,Integer>,String> sqlgeometrytypes = null;
2009
    
2010
    @Override
2011
    public Object sqlgeometrytype(int type, int subtype) {
2012
        // Devuelve un Object por que algunos gestores de BBDD utilizan
2013
        // identificadores numericos para el tipo y otros strings.
2014
        // Por defecto vamos a devolver strings.
2015
        if( sqlgeometrytypes==null ) {
2016
            sqlgeometrytypes = new HashMap<>();
2017
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2D), "POINT");
2018
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3D), "POINTZ");
2019
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2DM), "POINTM");
2020
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3DM), "POINTZM");
2021

    
2022
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2D), "LINESTRING");
2023
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
2024
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
2025
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
2026

    
2027
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2D), "POLYGON");
2028
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
2029
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
2030
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
2031

    
2032
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
2033
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
2034
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
2035
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
2036

    
2037
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2038
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2039
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2040
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2041

    
2042
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
2043
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
2044
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
2045
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
2046

    
2047
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2048
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2049
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2050
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2051

    
2052
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
2053
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
2054
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
2055
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
2056

    
2057
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
2058
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
2059
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
2060
            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
2061
        }
2062
        return sqlgeometrytypes.get(new ImmutablePair<>(type,subtype));
2063
    }
2064

    
2065
    @Override
2066
    public Object sqlgeometrydimension(int type, int subtype) {
2067
        // Devuelve un Object por que algunos gestortes de BBDD utilizan
2068
        // identificadores numericos para las dimensiones y otros strings.
2069
        // Por defecto vamos a devolver enteros.
2070
        switch(subtype) {
2071
            case Geometry.SUBTYPES.GEOM3D:
2072
                return 3;
2073
            case Geometry.SUBTYPES.GEOM2DM:
2074
                return 3;
2075
            case Geometry.SUBTYPES.GEOM3DM:
2076
                return 4;
2077
            case Geometry.SUBTYPES.GEOM2D:
2078
            default:
2079
                return 2;
2080
        }
2081
    }
2082
    
2083
    protected TableNameBuilder createTableNameBuilder() {
2084
        return new TableNameBuilderBase();
2085
    }
2086
    
2087
    protected SelectColumnBuilder createSelectColumnBuilder() {
2088
        return new SelectColumnBuilderBase();
2089
    }
2090
    
2091
    protected UpdateColumnBuilder createUpdateColumnBuilder() {
2092
        return new UpdateColumnBuilderBase();
2093
    }
2094
    
2095
    protected InsertColumnBuilder createInsertColumnBuilder() {
2096
        return new InsertColumnBuilderBase();
2097
    }
2098
    
2099
    protected OrderByBuilder createOrderByBuilder() {
2100
        return new OrderByBuilderBase();
2101
    }
2102

    
2103
    protected FromBuilder createFromBuilder() {
2104
        return new FromBuilderBase();
2105
    }
2106

    
2107
    protected SelectBuilder createSelectBuilder() {
2108
        return new SelectBuilderBase();
2109
    }
2110

    
2111
    protected UpdateBuilder createUpdateBuilder() {
2112
        return new UpdateBuilderBase();
2113
    }
2114

    
2115
    protected DeleteBuilder createDeleteBuilder() {
2116
        return new DeleteBuilderBase();
2117
    }
2118

    
2119
    protected GrantBuilder createGrantBuilder() {
2120
        return new GrantBuilderBase();
2121
    }
2122

    
2123
    protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
2124
        return new GrantRoleBuilderBase(table, role);
2125
    }
2126
    
2127
    protected DropTableBuilder createDropTableBuilder() {
2128
        return new DropTableBuilderBase();
2129
    }
2130

    
2131
    protected CreateTableBuilder createCreateTableBuilder() {
2132
        return new CreateTableBuilderBase();
2133
    }
2134

    
2135
    protected AlterTableBuilder createAlterTableBuilder() {
2136
        return new AlterTableBuilderBase();
2137
    }
2138

    
2139
    protected InsertBuilder createInsertBuilder() {
2140
        return new InsertBuilderBase();
2141
    }
2142

    
2143
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
2144
        return new UpdateTableStatisticsBuilderBase();
2145
    }
2146

    
2147
    protected CreateIndexBuilder createCreateIndexBuilder() {
2148
        return new CreateIndexBuilderBase();
2149
    }
2150
    
2151
    @Override
2152
    public SelectBuilder select() {
2153
        if (this.select == null) {
2154
            this.select = this.createSelectBuilder();
2155
        }
2156
        return this.select;
2157
    }
2158

    
2159
    @Override
2160
    public UpdateBuilder update() {
2161
        if (this.update == null) {
2162
            this.update = this.createUpdateBuilder();
2163
        }
2164
        return this.update;
2165
    }
2166

    
2167
    @Override
2168
    public UpdateTableStatisticsBuilder update_table_statistics() {
2169
        if (this.update_table_statistics == null) {
2170
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
2171
        }
2172
        return this.update_table_statistics;
2173
    }
2174

    
2175
    @Override
2176
    public DropTableBuilder drop_table() {
2177
        if (this.drop_table == null) {
2178
            this.drop_table = this.createDropTableBuilder();
2179
        }
2180
        return this.drop_table;
2181
    }
2182

    
2183
    @Override
2184
    public CreateIndexBuilder create_index() {
2185
        if (this.create_index == null) {
2186
            this.create_index = this.createCreateIndexBuilder();
2187
        }
2188
        return this.create_index;
2189
    }
2190

    
2191
    
2192
    @Override
2193
    public DeleteBuilder delete() {
2194
        if (this.delete == null) {
2195
            this.delete = this.createDeleteBuilder();
2196
        }
2197
        return this.delete;
2198
    }
2199

    
2200
    @Override
2201
    public InsertBuilder insert() {
2202
        if (this.insert == null) {
2203
            this.insert = this.createInsertBuilder();
2204
        }
2205
        return this.insert;
2206
    }
2207

    
2208
    @Override
2209
    public AlterTableBuilder alter_table() {
2210
        if (this.alter_table == null) {
2211
            this.alter_table = this.createAlterTableBuilder();
2212
        }
2213
        return this.alter_table;
2214
    }
2215

    
2216
    @Override
2217
    public CreateTableBuilder create_table() {
2218
        if (this.create_table == null) {
2219
            this.create_table = this.createCreateTableBuilder();
2220
        }
2221
        return this.create_table;
2222
    }
2223

    
2224
    @Override
2225
    public GrantBuilder grant() {
2226
        if (this.grant == null) {
2227
            this.grant = this.createGrantBuilder();
2228
        }
2229
        return this.grant;
2230
    }
2231

    
2232
    @Override
2233
    public void accept(Visitor visitor, VisitorFilter filter) {
2234
        if (this.select != null) {
2235
            this.select.accept(visitor, filter);
2236
        }
2237
        if (this.update != null) {
2238
            this.update.accept(visitor, filter);
2239
        }
2240
        if (this.insert != null) {
2241
            this.insert.accept(visitor, filter);
2242
        }
2243
        if (this.delete != null) {
2244
            this.delete.accept(visitor, filter);
2245
        }
2246
        if (this.alter_table != null) {
2247
            this.alter_table.accept(visitor, filter);
2248
        }
2249
        if (this.create_table != null) {
2250
            this.create_table.accept(visitor, filter);
2251
        }
2252
        if (this.drop_table != null) {
2253
            this.drop_table.accept(visitor, filter);
2254
        }
2255
    }
2256

    
2257
    
2258
    @Override
2259
    public String toString() {
2260
        if (this.select != null) {
2261
            return this.select.toString();
2262
        }
2263
        if (this.update != null) {
2264
            return this.update.toString();
2265
        }
2266
        if (this.insert != null) {
2267
            return this.insert.toString();
2268
        }
2269
        if (this.delete != null) {
2270
            return this.delete.toString();
2271
        }
2272
        if (this.alter_table != null) {
2273
            return this.alter_table.toString();
2274
        }
2275
        if (this.create_table != null) {
2276
            return this.create_table.toString();
2277
        }
2278
        if (this.drop_table != null) {
2279
            return this.drop_table.toString();
2280
        }
2281
        if (this.update_table_statistics != null) {
2282
            return this.update_table_statistics.toString();
2283
        }
2284
        if ( this.value != null ) {
2285
            return this.value.toString();
2286
        }
2287
        return ""; 
2288
    }
2289

    
2290
    @Override
2291
    public Function ST_UnionAggregate(Value geom) {
2292
        return function("ST_UnionAggregate", config.getString(SQLConfig.ST_UnionAggregate), geom);
2293
    }
2294

    
2295
    @Override
2296
    public Function ST_ExtentAggregate(Value geom) {
2297
        return function("ST_ExtentAggregate", config.getString(SQLConfig.ST_ExtentAggregate), geom);
2298
    }
2299

    
2300
    @Override
2301
    public CountBuilder count() {
2302
        return new CountBuilderBase();
2303
    }
2304

    
2305
}