Statistics
| Revision:

gvsig-mssqlserver / trunk / org.gvsig.mssqlserver / org.gvsig.mssqlserver.provider / src / main / java / org / gvsig / mssqlserver / dal / MSSQLServerSQLBuilder.java @ 192

History | View | Annotate | Download (19.7 KB)

1
package org.gvsig.mssqlserver.dal;
2

    
3
import java.text.MessageFormat;
4
import java.util.ArrayList;
5
import java.util.List;
6
import org.cresques.cts.IProjection;
7
import org.gvsig.fmap.dal.DataTypes;
8
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
9
import org.gvsig.fmap.geom.Geometry;
10
import org.gvsig.fmap.geom.primitive.Envelope;
11

    
12
public class MSSQLServerSQLBuilder extends JDBCSQLBuilderBase {
13

    
14
    public interface MSSQLServerSQLConfig extends SQLConfig {
15
        public static final String ST_GeomFromTextEx = "ST_GeomFromTextEx";
16
        public static final String ST_GeomFromWKBEx = "ST_GeomFromWKBEx";
17
        public static final String ST_GeomFromEWKBEx = "ST_GeomFromEWKBEx";
18
        public static final String ST_ExtentAggregateEx = "ST_ExtentAggregateEx";
19
        public static final String ST_UnionAggregateEx = "ST_UnionAggregateEx";
20
    }
21
 
22
    public MSSQLServerSQLBuilder(MSSQLServerHelper helper) {
23
        super(helper);
24
        
25
        config.set(SQLConfig.default_schema, "dbo");
26
        config.set(SQLConfig.allowAutomaticValues, true);
27
        config.set(SQLConfig.geometry_type_support, helper.getGeometrySupportType());
28
        config.set(SQLConfig.has_spatial_functions, helper.hasSpatialFunctions());
29

    
30
        config.remove_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table);
31
        config.remove_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table);
32
 
33
        config.set(SQLConfig.UPDATE_TABLE_STATISTICS_table,"UPDATE STATISTICS {0}");
34

    
35
        config.set(SQLConfig.type_geometry, "GEOMETRY");
36
        
37
        config.set(SQLConfig.type_boolean, "BIT");
38
        config.set(SQLConfig.type_double, "FLOAT"); //float con 53 bits de mantisa, float(54)
39
        config.set(SQLConfig.type_numeric_p, "NUMERIC({0})");
40
        config.set(SQLConfig.type_numeric_ps, "NUMERIC({0},{1})");
41
        config.set(SQLConfig.type_bigdecimal, "NUMERIC({0},{1})");
42
        config.set(SQLConfig.type_float, "REAL"); //float con 24 bits de mantisa, float(24)
43
        config.set(SQLConfig.type_int, "INT");
44
        config.set(SQLConfig.type_long, "BIGINT");        
45
        config.set(SQLConfig.type_byte, "TINYINT");
46
        
47
        config.set(SQLConfig.type_date, "DATE");
48
        config.set(SQLConfig.type_time, "TIME");
49

    
50
        config.set(SQLConfig.type_char, "CHAR(1)");
51
        config.set(SQLConfig.type_string, "TEXT");
52
        config.set(SQLConfig.type_string_p, "VARCHAR({0})");
53

    
54
        config.set(SQLConfig.type_version, "VARCHAR(30)");
55
        config.set(SQLConfig.type_URI, "TEXT");
56
        config.set(SQLConfig.type_URL, "TEXT");
57
        config.set(SQLConfig.type_FILE, "TEXT");
58
        config.set(SQLConfig.type_FOLDER, "TEXT");
59
        
60
        config.set(SQLConfig.type_bytearray, "VARBINARY");
61
        
62
        config.set(SQLConfig.type_timestamp, "TIMESTAMP");
63

    
64
        config.set(SQLConfig.ST_SRID, "(({0}).STSrid)");
65
        config.set(SQLConfig.ST_AsText, "({0}).STAsText()");
66
        config.set(SQLConfig.ST_AsBinary, "({0}).STAsBinary()");
67
        config.set(SQLConfig.ST_AsEWKB, "({0}).STAsBinary()");
68
        config.set(SQLConfig.ST_ExtentAggregate, "geometry::EnvelopeAggregate({0})");
69
        config.set(SQLConfig.ST_UnionAggregate, "geometry::UnionAggregate({0})");
70
        config.set(SQLConfig.ST_Contains, "(({0}).STContains({1})=1)");
71
        config.set(SQLConfig.ST_Crosses, "(({0}).STCrosses({1})=1)");
72
        config.set(SQLConfig.ST_Disjoint, "(({0}).STDisjoint({1})=1)");
73
        config.set(SQLConfig.ST_Equals, "(({0}).STEquals({1})=1)");
74
        config.set(SQLConfig.ST_IsClosed, "(({0}).STIsClosed()=1)");
75
        config.set(SQLConfig.ST_Overlaps, "(({0}).STOverlaps({1})=1)");
76
        config.set(SQLConfig.ST_Touches, "(({0}).STTouches({1})=1)");
77
        config.set(SQLConfig.ST_Within, "(({0}).STWithin ({1})=1)");
78
        config.set(SQLConfig.ST_Envelope, "({0}).STEnvelope()");
79
        config.set(SQLConfig.ST_Intersects, "(({0}).STIntersects({1})=1)");
80
        config.set(SQLConfig.ST_GeomFromText, "geometry::STGeomFromText({0}, {1})");
81
        config.set(SQLConfig.ST_GeomFromWKB, "geometry::STGeomFromWKB({0}, {1})");
82
        config.set(SQLConfig.ST_GeomFromEWKB, "geometry::STGeomFromWKB({0}, {1})");
83
        config.set(SQLConfig.ST_Simplify, "({0}).Reduce({1})");
84
        config.set(SQLConfig.lcase, "LOWER({0})");
85
        config.set(SQLConfig.ucase, "UPPER({0})");
86
        config.set(SQLConfig.operator_ILIKE, "LOWER({0}) LIKE LOWER({1})");
87
        config.set(SQLConfig.notIsNull,"( ({0}) IS NOT NULL )" );
88

    
89
        config.set(MSSQLServerSQLConfig.ST_ExtentAggregateEx, "{1}::EnvelopeAggregate({0})");
90
        config.set(MSSQLServerSQLConfig.ST_UnionAggregateEx, "{1}::UnionAggregate({0})");
91
        config.set(MSSQLServerSQLConfig.ST_GeomFromTextEx, "{2}::STGeomFromText({0}, {1})");
92
        config.set(MSSQLServerSQLConfig.ST_GeomFromWKBEx, "{2}::STGeomFromWKB({0}, {1})");
93
        config.set(MSSQLServerSQLConfig.ST_GeomFromEWKBEx, "{2}::STGeomFromWKB({0}, {1})");
94

    
95
    }
96

    
97
    @Override
98
    public MSSQLServerSQLConfig getConfig() {
99
        return (MSSQLServerSQLConfig) super.config;
100
    }
101

    
102
    @Override
103
    public MSSQLServerHelper getHelper() {
104
        return (MSSQLServerHelper) helper;
105
    }
106

    
107
    public class MSSQLServerCreateIndexBuilder extends CreateIndexBuilderBase {
108

    
109
        private Envelope boundingBox;
110
        
111
        public MSSQLServerCreateIndexBuilder() {
112
            super();
113
            this.boundingBox = null;
114
        }
115
        
116
        public void setBoundingBox(Envelope boundingBox) {
117
            this.boundingBox = boundingBox;
118
        }
119
        
120
        private double getXMin() {
121
            // https://alastaira.wordpress.com/2011/07/26/determining-the-geographic-extent-of-spatial-features-in-a-sql-server-table/
122
            return Math.min(boundingBox.getUpperCorner().getX(), boundingBox.getLowerCorner().getX());
123
        }
124
        
125
        private double getYMin() {
126
            return Math.min(boundingBox.getUpperCorner().getY(), boundingBox.getLowerCorner().getY());
127
        }
128
        
129
        private double getXMax() {
130
            return Math.max(boundingBox.getUpperCorner().getX(), boundingBox.getLowerCorner().getX());
131
        }
132
        
133
        private double getYMax() {
134
            return Math.max(boundingBox.getUpperCorner().getY(), boundingBox.getLowerCorner().getY());
135
        }
136
        
137
        @Override
138
        public List<String> toStrings() {
139
            StringBuilder builder = new StringBuilder();
140
            if( this.isSpatial ) {
141
                builder.append("CREATE SPATIAL INDEX ");
142
                builder.append(identifier(this.indexName));
143
                builder.append(" ON ");
144
                builder.append(this.table.toString());
145
                builder.append(" ( ");
146
                boolean is_first_column = true;
147
                for( String column : this.columns) {
148
                    if( is_first_column ) {
149
                        is_first_column = false;
150
                    } else {
151
                        builder.append(", ");
152
                    }
153
                    builder.append(column);
154
                }
155
                builder.append(" ) ");
156
                builder.append("USING GEOMETRY_GRID ");
157
                builder.append("WITH( ");
158
                builder.append("BOUNDING_BOX  = ( ");
159
                builder.append("xmin  = ").append(this.getXMin()).append(", ");
160
                builder.append("ymin  = ").append(this.getYMin()).append(", ");
161
                builder.append("xmax  = ").append(this.getXMax()).append(", ");
162
                builder.append("ymax  = ").append(this.getYMax());
163
                builder.append(" )");
164
//                builder.append(", DROP_EXISTING = ON");
165
//                builder.append(", GRIDS  = ( LEVEL_1  = MEDIUM, LEVEL_2  = MEDIUM, LEVEL_3  = MEDIUM, LEVEL_4  = MEDIUM)");
166
//                builder.append(", CELLS_PER_OBJECT  = 16");
167
//                builder.append(", STATISTICS_NORECOMPUTE = OFF");
168
//                builder.append(", ALLOW_ROW_LOCKS = ON");
169
//                builder.append(", ALLOW_PAGE_LOCKS = ON");
170
                builder.append(" ) ");
171
            } else {
172
                builder.append("CREATE ");
173
                if( this.isUnique ) {
174
                    builder.append("UNIQUE ");
175
                }
176
                builder.append("INDEX ");
177
//                if( this.ifNotExist ) {
178
//                    builder.append("IF NOT EXISTS ");
179
//                }
180
                builder.append(identifier(this.indexName));
181
                builder.append(" ON ");
182
                builder.append(this.table.toString());
183
                builder.append(" ( ");
184
                boolean is_first_column = true;
185
                for( String column : this.columns) {
186
                    if( is_first_column ) {
187
                        is_first_column = false;
188
                    } else {
189
                        builder.append(", ");
190
                    }
191
                    builder.append(column);
192
                }
193
                builder.append(" )");
194
            }
195
            List<String> sqls = new ArrayList<>();
196
            sqls.add(builder.toString());
197
            return sqls;
198
        }
199
        
200
    }
201
    
202
    public class MSSQLServerParameter extends ParameterBase {
203

    
204
        public MSSQLServerParameter() {
205
            super();
206
        }
207

    
208
        @Override
209
        public String toString() {
210
            if( this.type == ParameterType.Geometry ) {
211
                String spatialType = getHelper().getSpatialType(this.getName());
212
                switch( config.getGeometryTypeSupport() ) {
213
                    case EWKB:
214
                        return MessageFormat.format(
215
                                config.getString(MSSQLServerSQLConfig.ST_GeomFromEWKBEx),
216
                                "?",
217
                                String.valueOf(this.srs.toString()),
218
                                custom(spatialType)
219
                        );
220
                    case NATIVE:
221
                    case WKB:
222
                        return MessageFormat.format(
223
                                config.getString(MSSQLServerSQLConfig.ST_GeomFromWKBEx),
224
                                "?",
225
                                String.valueOf(this.srs.toString()),
226
                                custom(spatialType)
227
                        );
228
                    case WKT:
229
                    default:
230
                        return MessageFormat.format(
231
                                config.getString(MSSQLServerSQLConfig.ST_GeomFromTextEx),
232
                                "?",
233
                                String.valueOf(this.srs.toString()),
234
                                custom(spatialType)
235
                        );                        
236
                }                            
237
            }
238
            return super.toString();
239
        }
240
    }
241
    
242
    public class MSSQLServerGeometryValue extends GeometryValueBase {
243
        
244
        public MSSQLServerGeometryValue(Geometry geometry, IProjection projection) {
245
            super(geometry, projection);
246
        }
247
        
248
        @Override
249
        public String toString() {
250
            try {
251
                String spatialType = getHelper().getSpatialType();
252
                switch( config.getGeometryTypeSupport() ) {
253
                    case EWKB:
254
                        return MessageFormat.format(
255
                                config.getString(MSSQLServerSQLConfig.ST_GeomFromEWKBEx),
256
                                bytearray(this.geometry.convertToEWKB()),
257
                                String.valueOf(getSRSId(this.projection)),
258
                                custom(spatialType)
259
                        );
260
                    case NATIVE:
261
                    case WKB:
262
                        return MessageFormat.format(
263
                                config.getString(MSSQLServerSQLConfig.ST_GeomFromWKBEx),
264
                                bytearray(this.geometry.convertToWKB()),
265
                                String.valueOf(getSRSId(this.projection)),
266
                                custom(spatialType)
267
                        );
268
                    case WKT:
269
                    default:
270
                        return MessageFormat.format(
271
                                config.getString(MSSQLServerSQLConfig.ST_GeomFromTextEx),
272
                                string(this.geometry.convertToWKT()),
273
                                String.valueOf(getSRSId(this.projection)),
274
                                custom(spatialType)
275
                        );                        
276
                }
277
            } catch (Exception ex) {
278
                throw new RuntimeException("Can't convert geometry to string.",ex);
279
            }
280
        }
281
    }
282

    
283
    protected class MSSQLServerSelectBuilder extends SelectBuilderBase {
284

    
285
        @Override
286
        public String toString() {
287
            // MSSQLServer usa TOP en lugar de LIMIT y la sintaxis para OFFSET
288
            // es ligeramente distinta de la que hay en SelectBuilderBase
289
            StringBuilder builder = new StringBuilder();
290

    
291
            builder.append("SELECT ");
292
            if( this.distinct ) {
293
                builder.append("DISTINCT ");
294
            }
295
            if (this.has_limit() && !this.has_offset() ) {
296
                builder.append("TOP ");
297
                builder.append(this.limit);
298
                builder.append(" ");
299
           }
300
            boolean first = true;
301
            for (SelectColumnBuilder column : columns) {
302
                if (first) {
303
                    first = false;
304
                } else {
305
                    builder.append(", ");
306
                }
307
                builder.append(column.toString());
308
            }
309

    
310
            if (this.has_from()) {
311
                builder.append(" FROM ");
312
                builder.append(this.from.toString());
313
            }
314
            if (this.has_where()) {
315
                builder.append(" WHERE ");
316
                builder.append(this.where.toString());
317
            }
318

    
319
            if( this.has_order_by() ) {
320
                builder.append(" ORDER BY ");
321
                first = true;
322
                for (OrderByBuilder item : this.order_by) {
323
                    if (first) {
324
                        first = false;
325
                    } else {
326
                        builder.append(", ");
327
                    }
328
                    builder.append(item.toString());
329
                }
330
            }
331

    
332
            if (this.has_offset()) {
333
                // Require SQLSeerver >= 2012
334
                builder.append(" OFFSET ");
335
                builder.append(this.offset);
336
                builder.append(" ROWS");
337
                if( this.has_limit() ) {
338
                    builder.append(" FETCH NEXT ");
339
                    builder.append(this.limit);
340
                    builder.append(" ROWS ONLY ");
341
                }
342
            }
343
            return builder.toString();
344
        }
345
    }
346

    
347
    protected class MSSQLServerCreateTableBuilder extends CreateTableBuilderBase {
348

    
349
        @Override
350
        public List<String> toStrings() {
351
            //
352
            // Respecto al base cambia la declaracion de campo automaticos
353
            // SQLServer usa IDENTITY en lugar de SERIAL.
354
            //
355
            List<String> sqls = new ArrayList<>();
356
            StringBuilder builder = new StringBuilder();
357

    
358
            builder.append("CREATE TABLE ");
359
            builder.append(this.table.toString());
360
            builder.append(" (");
361
            boolean first = true;
362
            for (ColumnDescriptor column : columns) {
363
                if (first) {
364
                    first = false;
365
                } else {
366
                    builder.append(", ");
367
                }
368
                builder.append(identifier(column.getName()));
369
                builder.append(" ");
370
                if( column.isAutomatic() && column.getType() == DataTypes.INT ) {
371
                    builder.append("INT");
372
                    builder.append(" IDENTITY(1,1)");
373
                } else if( column.isAutomatic() && column.getType() == DataTypes.LONG ) {
374
                    builder.append("BIGINT");
375
                    builder.append(" IDENTITY(1,1)");
376
                } else {
377
                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
378
                }
379
                if (column.getDefaultValue() == null) {
380
                    if (column.allowNulls()) {
381
                        builder.append(" DEFAULT NULL");
382
                    }
383
                } else {
384
                    builder.append(" DEFAULT '");
385
                    builder.append(column.getDefaultValue().toString());
386
                    builder.append("'");
387
                }
388
                if (column.allowNulls()) {
389
                    builder.append(" NULL");
390
                } else {
391
                    builder.append(" NOT NULL");
392
                }
393
                if (column.isPrimaryKey()) {
394
                    builder.append(" PRIMARY KEY");
395
                }
396
            }
397
            builder.append(" )");
398
            sqls.add(builder.toString());
399

    
400
            return sqls;
401
        }
402
    }
403

    
404
    @Override
405
    protected SelectBuilder createSelectBuilder() {
406
        return new MSSQLServerSelectBuilder();
407
    }
408

    
409
    @Override
410
    protected CreateTableBuilder createCreateTableBuilder() {
411
        return new MSSQLServerCreateTableBuilder();
412
    }
413

    
414
    @Override
415
    protected CreateIndexBuilder createCreateIndexBuilder() {
416
        return new MSSQLServerCreateIndexBuilder();
417
    }
418
    
419
    @Override
420
    public String identifier(String id) {
421
        // En SQLServer se aceptan las comillas dobles pero se prefiere
422
        // corchetes [xx]. Asi que si hay comillas dobles las quitamos
423
        // y ponemos los corchetes.
424
        String quote = config.getString(Config.quote_for_identifiers);
425
        if (id.startsWith(quote)) {
426
            id = id.substring(1, id.length()-1);
427
        } else if( id.startsWith("[") ) {
428
            return id;
429
        }
430
        if( id.contains("(") ) {
431
            logger.warn("Suspicious use of 'identifier' in sql.");
432
        }
433
        return "[" + id + "]";
434
    }
435

    
436
    @Override
437
    public GeometryValue geometry(Geometry geom, IProjection projection) {
438
        return new MSSQLServerGeometryValue(geom, projection);
439
    }
440

    
441
    @Override
442
    public Parameter parameter() {
443
        return new MSSQLServerParameter();
444
    }
445
    
446
    @Override
447
    public Function ST_ExtentAggregate(Value geom) {
448
        String spatialType = getHelper().getSpatialType();
449
        return builtin_function("ST_ExtentAggregate", 
450
                config.getString(MSSQLServerSQLConfig.ST_ExtentAggregateEx), 
451
                geom,
452
                custom(spatialType)
453
        );
454
    }
455

    
456
    @Override
457
    public Function ST_UnionAggregate(Value geom) {
458
        String spatialType = getHelper().getSpatialType();
459
        return builtin_function("ST_UnionAggregate", 
460
                config.getString(MSSQLServerSQLConfig.ST_UnionAggregateEx), 
461
                geom,
462
                custom(spatialType)
463
        );
464
    }
465

    
466
    @Override
467
    public Function ST_GeomFromText(Value geom, Value crs) {
468
        String spatialType = getHelper().getSpatialType();
469
        return builtin_function("ST_GeomFromText", 
470
                config.getString(MSSQLServerSQLConfig.ST_GeomFromTextEx), 
471
                geom, 
472
                crs,
473
                custom(spatialType)
474
        );
475
    }
476

    
477
    @Override
478
    public Function ST_GeomFromWKB(Value geom, Value crs) {
479
        String spatialType = getHelper().getSpatialType();
480
        return builtin_function("ST_GeomFromWKB", 
481
                config.getString(MSSQLServerSQLConfig.ST_GeomFromWKBEx), 
482
                geom, 
483
                crs,
484
                custom(spatialType)
485
        );
486
    }
487

    
488
    @Override
489
    public Function ST_GeomFromEWKB(Value geom, Value crs) {
490
        String spatialType = getHelper().getSpatialType();
491
        return builtin_function("ST_GeomFromEWKB", 
492
                config.getString(MSSQLServerSQLConfig.ST_GeomFromEWKBEx), 
493
                geom, 
494
                crs,
495
                custom(spatialType)
496
        );
497
    }
498

    
499
}