Statistics
| Revision:

gvsig-oracle / org.gvsig.oracle / trunk / org.gvsig.oracle / org.gvsig.oracle.provider / src / main / java / org / gvsig / oracle / dal / OracleSQLBuilder.java @ 915

History | View | Annotate | Download (51.9 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.oracle.dal;
25

    
26
import java.io.ByteArrayInputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.OutputStream;
30
import java.sql.Connection;
31
import java.sql.PreparedStatement;
32
import java.sql.SQLException;
33
import java.sql.Time;
34
import java.sql.Timestamp;
35
import java.text.MessageFormat;
36
import java.util.ArrayList;
37
import java.util.List;
38
import java.util.Objects;
39
import oracle.sql.BLOB;
40
import org.apache.commons.dbcp.DelegatingConnection;
41
import org.apache.commons.lang3.BooleanUtils;
42
import org.apache.commons.lang3.StringUtils;
43
import org.apache.commons.lang3.tuple.Pair;
44
import org.gvsig.expressionevaluator.DelegatedGeometryExpressionBuilder;
45
import org.gvsig.expressionevaluator.ExpressionBuilder;
46
import static org.gvsig.expressionevaluator.ExpressionBuilder.PARAMETER_TYPE_CONSTANT;
47
import static org.gvsig.expressionevaluator.ExpressionBuilder.PARAMETER_TYPE_VARIABLE;
48
import static org.gvsig.expressionevaluator.ExpressionBuilder.VALUE_NULL;
49
import org.gvsig.expressionevaluator.ExpressionUtils;
50
import org.gvsig.expressionevaluator.Formatter;
51
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
52
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
53
import static org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType.WKT;
54
import org.gvsig.fmap.dal.DataTypes;
55
import org.gvsig.fmap.dal.SQLBuilder;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
57
import org.gvsig.fmap.dal.feature.FeatureType;
58
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
59
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
60
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
61
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
62
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
63
import org.gvsig.fmap.geom.Geometry;
64
import org.gvsig.fmap.geom.GeometryUtils;
65
import org.gvsig.fmap.geom.primitive.Envelope;
66
import org.gvsig.oracle.dal.expressionbuilderformatter.OracleFormatter;
67
import static org.gvsig.oracle.dal.expressionbuilderformatter.OracleGeometryParameter.ORACLE_GEOMETRY_PARAMETER;
68
import org.gvsig.tools.ToolsLocator;
69
import org.gvsig.tools.dataTypes.Coercion;
70
import org.gvsig.tools.dataTypes.DataType;
71
import org.gvsig.tools.dataTypes.DataTypeUtils;
72
import org.gvsig.tools.dataTypes.DataTypesManager;
73
import org.gvsig.tools.dispose.Disposable;
74

    
75
public class OracleSQLBuilder extends JDBCSQLBuilderBase {
76

    
77
    protected static final String ADD_SERIAL_COLUMN_SEQUENCE_QUERY = "CREATE SEQUENCE \"{0}\"";
78
    protected static final String ADD_SERIAL_COLUMN_TRIGGER_QUERY = "CREATE OR REPLACE TRIGGER \"{0}\" BEFORE INSERT ON {1} FOR EACH ROW "
79
            + "BEGIN SELECT \"{3}\".NEXTVAL INTO :new.\"{2}\" FROM dual; END;";
80
    protected static final String DELETE_FROM_OGIS_GEOMETRY_COLUMNS_QUERY = "DELETE FROM MDSYS.OGIS_GEOMETRY_COLUMNS "
81
            + "WHERE F_TABLE_SCHEMA = ''{0}'' AND F_TABLE_NAME = ''{1}'' AND F_GEOMETRY_COLUMN = ''{2}''";
82
    protected static final String INSERT_OGIS_GEOMETRY_COLUMNS_QUERY = "INSERT INTO MDSYS.OGIS_GEOMETRY_COLUMNS "
83
            + "(F_TABLE_SCHEMA, F_TABLE_NAME, F_GEOMETRY_COLUMN, GEOMETRY_TYPE) VALUES "
84
            + "(''{0}'', ''{1}'', ''{2}'', {3})";
85
    private final String quote_for_identifiers;
86
    private final String quote_for_strings;
87
    public static final String ST_GEOMFROMTEXT = "SDO_GEOMETRY(({0}), ({1}))";
88
    public static final String ST_GEOMFROMWKB = "SDO_GEOMETRY(({0}), ({1}))";
89
    public static final String ST_GEOMFROMEWKB = "SDO_GEOMETRY(({0}), ({1}))";
90
    public static final String FORMAT_OPERATOR_NOTISNULL = "( (({0}) IS NOT NULL) )";
91
    public static final String FORMAT_OPERATOR_AND = "( ({0}) AND ({1}) )";
92
    public static final String FORMAT_OPERATOR_OR = "( ({0}) OR ({1}) )";
93
    public static final String FORMAT_OPERATOR_NE = "( ({0}) != ({1}) )";
94
    public static final String FORMAT_OPERATOR_ILIKE = "( LOWER({0}) LIKE LOWER({1}) )";
95
    public static final String FORMAT_OPERATOR_CONCAT = "{0} + {1}";
96

    
97
    public static final int BOOLEAN_STRING_DEFAULT_LENGTH = 1;
98

    
99
    private static final Geometry EMPTY_POINT = GeometryUtils.createPoint(0, 0);
100

    
101
    protected Formatter formatter = null;
102

    
103
    public OracleSQLBuilder(JDBCHelper helper) {
104
        super(helper);
105

    
106
        this.defaultSchema = "";
107
        this.allowAutomaticValues = true;
108
        this.geometrySupportType = this.helper.getGeometrySupportType();
109
        this.hasSpatialFunctions = this.helper.hasSpatialFunctions();
110
        this.constant_true = "TRUE";
111
        this.constant_false = "FALSE";
112
        this.quote_for_identifiers = "\"";
113
        this.quote_for_strings = "\'";
114

    
115
        this.type_boolean = "CHAR(1)";
116
        this.type_byte = "NUMBER(" + (DataType.BYTE_MAX_PRECISION) + ",0)";
117
        this.type_bytearray = "BLOB";
118
        this.type_geometry = "SDO_GEOMETRY";
119
        this.type_char = "CHAR(1)";
120
        this.type_date = "DATE";
121
        this.type_double = "BINARY_DOUBLE"; //float con 53 bits de mantisa = float(54)
122
        this.type_decimal_p = "NUMBER({0})";
123
        this.type_decimal_ps = "NUMBER({0},{1})";
124
//        this.type_bigdecimal = "NUMBER({0},{1})";
125
        this.type_float = "BINARY_FLOAT"; //float con 24 bits de mantisa = float(24)
126
        this.type_int = "NUMBER(" + (DataType.INT_MAX_PRECISION - 1) + ",0)";
127
        this.type_long = "NUMBER(" + (DataType.LONG_MAX_PRECISION - 1) + ",0)";
128
        this.type_string = "NCLOB";
129
        this.type_string_p = "NVARCHAR2({0,Number,#######})";
130
        this.type_time = "TIMESTAMP";
131
        this.type_timestamp = "TIMESTAMP";
132
        this.type_version = "VARCHAR2(30)";
133
        this.type_URI = "NVARCHAR2(2048)";
134
        this.type_URL = "NVARCHAR2(2048)";
135
        this.type_FILE = "NVARCHAR2(2048)";
136
        this.type_FOLDER = "NVARCHAR2(2048)";
137

    
138
        STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
139
        STMT_DELETE_FROM_table = "DELETE FROM {0}";
140
        STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
141
        STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}"; // FIXME: ALTER INDEX [schema.]index REBUILD  INDEXTYPE IS MDSYS.SPATIAL_INDEX PARAMETERS (''LAYER_GTYPE={3}'';
142
//        config.remove_functionality(SQLConfig.UPDATE_TABLE_STATISTICS_table; // FIXME
143
        STMT_DROP_TABLE_table = "DROP TABLE {0}";
144
        STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = null;
145
        STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = null;
146
        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
147
        STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
148
        STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
149

    
150
    }
151
    
152
    public OracleHelper getHelper() {
153
        return (OracleHelper) super.getHelper();
154
    }
155
    
156
    @Override
157
    public Formatter formatter() {
158
        if (this.formatter == null) {
159
            this.formatter = new OracleFormatter(this);
160
        }
161
        return this.formatter;
162
    }
163

    
164
    private class OracleGeometryExpressionBuilder extends DelegatedGeometryExpressionBuilder {
165

    
166
        public OracleGeometryExpressionBuilder(GeometryExpressionBuilder expressionBuilder) {
167
            super(expressionBuilder);
168
        }
169

    
170
        @Override
171
        public Formatter<Value> formatter() {
172
            return OracleSQLBuilder.this.formatter();
173
        }
174

    
175
    }
176

    
177
    private OracleGeometryExpressionBuilder oracleExpressionBuilder = null;
178

    
179
    @Override
180
    public GeometryExpressionBuilder expression() {
181
        if (this.oracleExpressionBuilder == null) {
182
            this.oracleExpressionBuilder = new OracleGeometryExpressionBuilder(super.expression());
183
        }
184
        return this.oracleExpressionBuilder;
185
    }
186

    
187
    @Override
188
    public String default_schema() {
189
        JDBCConnectionParameters params = this.helper.getConnectionParameters();
190
        if (params != null) {
191
            if (StringUtils.isBlank(params.getSchema())) {
192
                if ((StringUtils.isNotBlank(params.getUser()))) {
193
                    return params.getUser();
194
                }
195
            } else {
196
                return params.getSchema();
197
            }
198
        }
199
        return this.defaultSchema;
200
    }
201

    
202
    public class OracleUpdateTableStatisticsBuilderBase extends UpdateTableStatisticsBuilderBase {
203

    
204
        @Override
205
        public List<String> toStrings() {
206
            List<String> sqls = new ArrayList<>();
207

    
208
            String name = as_identifier(this.table.getName());
209
            if (table.has_schema()) {
210
                name = as_identifier(this.table.getSchema()) + "." + name;
211
            }
212
            String sql = MessageFormat.format(
213
                    "ANALYZE TABLE {0} COMPUTE STATISTICS",
214
                    name
215
            );
216
            if (!StringUtils.isEmpty(sql)) {
217
                sqls.add(sql);
218
            }
219

    
220
            return sqls;
221
        }
222
    }
223

    
224
    public String getSerialSequenceName(String tableName, String columnName) {
225
        return ("GVSEQ_" + tableName + "_" + columnName).toUpperCase();
226
    }
227

    
228
    public String getSerialTriggerName(String tableName, String columnName) {
229
        return ("GVSER_" + tableName + "_" + columnName).toUpperCase();
230
    }
231

    
232
    protected class OracleCreateTableBuilder extends CreateTableBuilderBase {
233

    
234
        @Override
235
        public List<String> toStrings(Formatter formatter) {
236

    
237
            List<String> sqls = new ArrayList<>();
238
            StringBuilder builder = new StringBuilder();
239

    
240
            builder.append("CREATE TABLE ");
241
            builder.append(this.table().toString());
242
            builder.append(" (");
243
            boolean first = true;
244

    
245
            ArrayList<String> pks = new ArrayList<>();
246
            boolean automaticPrimaryKey = false;
247

    
248
            for (ColumnDescriptor column : columns) {
249
                if (first) {
250
                    first = false;
251
                } else {
252
                    builder.append(", ");
253
                }
254
                if (column.isGeometry()) {
255
                    builder.append(as_identifier(column.getName())); //.toUpperCase()));
256
                    builder.append(" ");
257
                    builder.append(" SDO_GEOMETRY");
258
                    if (!column.allowNulls()) {
259
                        builder.append(" NOT NULL");
260
                    }
261
                } else {
262
                    builder.append(as_identifier(column.getName()));
263
                    builder.append(" ");
264
                    builder.append(sqltype(
265
                            column.getType(),
266
                            column.getSize(),
267
                            column.getPrecision(),
268
                            column.getScale(),
269
                            column.getGeometryType(),
270
                            column.getGeometrySubtype()));
271

    
272
//                    if (column.getDefaultValue() == null) {
273
//                        if (column.allowNulls()) {
274
//                            builder.append(" DEFAULT NULL");
275
//                        }
276
//                    } else {
277
//                        builder.append(" DEFAULT '");
278
//                        builder.append(column.getDefaultValue().toString());
279
//                        builder.append("'");
280
//                    }
281
//                    if (column.allowNulls()) {
282
//                        builder.append(" NULL");
283
//                    } else {
284
//                        builder.append(" NOT NULL");
285
//                    }
286
                }
287
                if (column.isPrimaryKey()) {
288
                    if (column.isAutomatic()) {
289
                        // if the pk is automatic, ignore any other PK
290
                        automaticPrimaryKey = true;
291
                        pks.clear();
292
                        pks.add(column.getName());
293
                    } else if (!automaticPrimaryKey) {
294
                        pks.add(column.getName());
295
                    }
296
                } else {
297
                    if (column.isAutomatic()) {
298
//                        builder.append(" AUTO_INCREMENT");
299
                        builder.append(" GENERATED ALWAYS as IDENTITY(START with 1 INCREMENT by 1)");
300
                    }
301
                    if (column.getDefaultValue() == null
302
                            || ExpressionUtils.isDynamicText(Objects.toString(column.getDefaultValue(), null))) {
303
                        if (column.allowNulls()) {
304
                            builder.append(" DEFAULT NULL");
305
                        }
306
                    } else {
307
                        switch (column.getType()) {
308
                            case DataTypes.TIMESTAMP:
309
                                builder.append(" DEFAULT ( TIMESTAMP '");
310
                                Timestamp dtimestamp = (Timestamp) DataTypeUtils.toTimestamp(column.getDefaultValue());
311
                                builder.append(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm:ss.S}", dtimestamp));
312
                                builder.append("' )");
313
                                break;
314
                            case DataTypes.TIME:
315
                                builder.append(" DEFAULT ( TIME '");
316
                                Time dtime = (Time) DataTypeUtils.toTime(column.getDefaultValue());
317
                                builder.append(MessageFormat.format("{0,date,HH:mm:ss}", dtime));
318
                                builder.append("' )");
319
                                break;
320
                            case DataTypes.DATE:
321
                                builder.append(" DEFAULT ( DATE '");
322
                                java.sql.Date ddate = (java.sql.Date) DataTypeUtils.toDate(column.getDefaultValue());
323
                                builder.append(MessageFormat.format("{0,date,yyyy-MM-dd}", ddate));
324
                                builder.append("' )");
325
                                break;
326
                            default:
327
                                builder.append(" DEFAULT '");
328
                                builder.append(Objects.toString(column.getDefaultValue(), ""));
329
                                builder.append("'");
330
                        }
331
                    }
332
                }
333
            }
334
            builder.append(" )");
335
            sqls.add(builder.toString());
336

    
337
            if (pks.size() > 0) {
338
                builder = new StringBuilder("ALTER TABLE ");
339
                builder.append(this.table().toString());
340
                builder.append(" ADD PRIMARY KEY (");
341
                for (int i = 0; i < pks.size(); i++) {
342
                    if (i != 0) {
343
                        builder.append(", ");
344
                    }
345
                    builder.append(as_identifier(pks.get(i)));
346
                }
347
                builder.append(")");
348
                sqls.add(builder.toString());
349
            }
350

    
351
            for (ColumnDescriptor column : columns) {
352
                if (column.isAutomatic()) {
353
                    String sequenceName = getSerialSequenceName(this.table.getName(), column.getName());
354
                    String sql = MessageFormat.format(
355
                            ADD_SERIAL_COLUMN_SEQUENCE_QUERY,
356
                            sequenceName
357
                    );
358
                    sqls.add(sql);
359
                    String autoTriggerName = getSerialTriggerName(this.table.getName(), column.getName());
360
                    sql = MessageFormat.format(
361
                            ADD_SERIAL_COLUMN_TRIGGER_QUERY,
362
                            autoTriggerName,
363
                            this.table().toString(),
364
                            column.getName(),
365
                            sequenceName
366
                    );
367
                    sqls.add(sql);
368
                }
369
            }
370

    
371
            for (ColumnDescriptor column : columns) {
372
                if (column.isGeometry()) {
373
                    /**
374
                     * Inserting the geomtype and column on
375
                     * OGIS_GEOMETRY_COLUMNS.
376
                     *
377
                     * It is useful to retrieve the geometry type when the
378
                     * spatial index can't be defined (for instance users
379
                     * creating tables on a different schema).
380
                     *
381
                     * Note: We don't insert the SRID because it is unusable as
382
                     * defined on OGIS_GEOMETRY_COLUMNS, as it must reference an
383
                     * existing SRID on OGIS_SPATIAL_REFERENCE_SYSTEM.
384
                     * OGIS_SPATIAL_REFERENCE_SYSTEM is empty and it has a
385
                     * trigger that duplicates on SDO_COORD_REF_SYS any SRID
386
                     * inserted on OGIS_SPATIAL_REFERENCE_SYSTEM.
387
                     * SDO_COORD_REF_SYS is not empty and we don't want to
388
                     * duplicate the SRID definitions!!
389
                     */
390
                    int gvsigType = column.getGeometryType();
391
                    int gvsigSubtype = column.getGeometrySubtype();
392
                    String sql = MessageFormat.format( // delete before inserting to avoid creating duplicates
393
                            DELETE_FROM_OGIS_GEOMETRY_COLUMNS_QUERY,
394
                            this.table().getSchema(),
395
                            this.table().getName().toUpperCase(),
396
                            column.getName()
397
                    );
398
                    sqls.add(sql);
399
                    sql = MessageFormat.format(
400
                            INSERT_OGIS_GEOMETRY_COLUMNS_QUERY,
401
                            this.table().getSchema(),
402
                            this.table().getName().toUpperCase(),
403
                            column.getName(),
404
                            Integer.toString(GeometryTypeUtils.toSFSGeometryTypeCode(gvsigType, gvsigSubtype))
405
                    );
406
                    sqls.add(sql);
407
                    Envelope tablebbox = column.getTableBBox();
408
                    if (tablebbox != null) {
409
                        sql = SpatialIndexUtils.getSQLDeleteUserMetadata(
410
                                this.table().getSchema(),
411
                                this.table().getName(),
412
                                column.getName()
413
                        );
414
                        sqls.add(sql);
415
                        sql = SpatialIndexUtils.getSQLInsertUserMetadata(
416
                                this.table().getName(),
417
                                tablebbox,
418
                                column.getName(),
419
                                (int) column.getGeometrySRSId()
420
                        );
421
                        sqls.add(sql);
422
                        sql = SpatialIndexUtils.getSQLCreateSpatialIndex(
423
                                this.table().getName(),
424
                                column.getName(),
425
                                gvsigType,
426
                                gvsigSubtype
427
                        );
428
                        sqls.add(sql);
429
                    }
430
                }
431
            }
432
            return sqls;
433
        }
434
    }
435

    
436
    public class OracleSelectBuilder extends SelectBuilderBase {
437

    
438
        @Override
439
        public String toString(Formatter<ExpressionBuilder.Value> formatter) {
440
            StringBuilder builder = new StringBuilder();
441
            if (!isValid(builder)) {
442
                throw new IllegalStateException(builder.toString());
443
            }
444
            boolean involveWithLimitOrOffset = ((this.has_offset() || this.has_limit())
445
                    && (this.has_aggregate_functions() || this.has_group_by() || this.has_order_by()));
446

    
447
            if (involveWithLimitOrOffset) {
448
                /**
449
                 * Using ROWNUM for limit & offset, compatible with any Oracle
450
                 * version This requires wrapping the original query as shown in
451
                 * the example: select * from ( select a.*, ROWNUM rnum from (
452
                 * <select statement with order by clause>
453
                 * ) a where ROWNUM <= MAX_ROW
454
                 *     ) where rnum >= MIN_ROW because ROWNUM is considered before
455
                 * applying order by and group by
456
                 */
457
                builder.append("SELECT * FROM ( ");
458
                if (this.has_offset()) {
459
                    builder.append("SELECT a.*, ROWNUM rnum FROM ( ");
460
                }
461
            }
462

    
463
            builder.append("SELECT ");
464
            if (this.distinct) {
465
                builder.append("DISTINCT ");
466
            }
467
            boolean first = true;
468
            for (SelectColumnBuilder column : columns) {
469
                if (first) {
470
                    first = false;
471
                } else {
472
                    builder.append(", ");
473
                }
474
                builder.append(column.toString(formatter));
475
            }
476

    
477
            if (this.has_from()) {
478
                builder.append(" FROM ");
479
                builder.append(this.from.toString(formatter));
480
            }
481
            if (this.has_where()) {
482
                builder.append(" WHERE ");
483
                builder.append(this.where.toString(formatter));
484
            }
485

    
486
            if (!involveWithLimitOrOffset) {
487
                if (this.has_limit() || this.has_offset()) {
488
                    if (this.has_where()) {
489
                        builder.append(" AND ");
490
                    } else {
491
                        builder.append(" WHERE ");
492
                    }
493
                }
494

    
495
                if (this.has_limit()) {
496
                    builder.append(" ROWNUM <= ");
497
                    if (this.has_offset()) {
498
                        builder.append(this.offset + this.limit);
499
                    } else {
500
                        builder.append(this.limit);
501
                    }
502
                }
503
                if (this.has_offset()) {
504
                    builder.append(" AND rnum > ");
505
                    builder.append(this.offset);
506
                }
507

    
508
                if (this.has_group_by()) {
509
                    builder.append(" GROUP BY ");
510
                    builder.append(this.groupColumn.get(0).toString(formatter));
511
                    for (int i = 1; i < groupColumn.size(); i++) {
512
                        builder.append(", ");
513
                        builder.append(this.groupColumn.get(i).toString(formatter));
514
                    }
515
                }
516

    
517
                if (this.has_order_by()) {
518
                    builder.append(" ORDER BY ");
519
                    first = true;
520
                    for (OrderByBuilder item : this.order_by) {
521
                        if (first) {
522
                            first = false;
523
                        } else {
524
                            builder.append(", ");
525
                        }
526
                        builder.append(item.toString(formatter));
527
                    }
528
                }
529

    
530
            }
531

    
532
            if (involveWithLimitOrOffset) {
533
                if (this.has_order_by()) {
534
                    builder.append(" ORDER BY ");
535
                    first = true;
536
                    for (OrderByBuilder item : this.order_by) {
537
                        if (first) {
538
                            first = false;
539
                        } else {
540
                            builder.append(", ");
541
                        }
542
                        builder.append(item.toString(formatter));
543
                    }
544
                }
545
                builder.append(") a");
546
                if (this.has_limit()) {
547
                    builder.append(" WHERE ROWNUM <= ");
548
                    if (this.has_offset()) {
549
                        builder.append(this.offset + this.limit);
550
                    } else {
551
                        builder.append(this.limit);
552
                    }
553
                }
554
                if (this.has_offset()) {
555
                    builder.append(" )");
556
                    builder.append(" WHERE rnum > ");
557
                    builder.append(this.offset);
558
                }
559

    
560
            }
561
            return builder.toString();
562
        }
563

    
564
    }
565

    
566
    @Override
567
    public TableNameBuilder createTableNameBuilder() {
568
        return new OracleTableNameBuilder();
569
    }
570

    
571
    @Override
572
    protected CreateTableBuilder createCreateTableBuilder() {
573
        return new OracleCreateTableBuilder();
574
    }
575

    
576
    @Override
577
    public SelectBuilder createSelectBuilder() {
578
        return new OracleSelectBuilder();
579
    }
580

    
581
    @Override
582
    protected FromBuilder createFromBuilder() {
583
        return new OracleFromBuilder();
584
    }
585

    
586
    @Override
587
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
588
        return new OracleUpdateTableStatisticsBuilderBase();
589
    }
590

    
591
    protected class OracleTableNameBuilder extends TableNameBuilderBase {
592

    
593
        @Override
594
        public boolean has_database() {
595
            return false;
596
        }
597

    
598
        @Override
599
        public String toString() {
600
            return this.toString(formatter());
601
        }
602

    
603
        protected String databaseName2provider() {
604
            return null;
605
        }
606

    
607
        protected String schemaName2provider() {
608
            return this.schemaName;
609
        }
610

    
611
        protected String tableName2provider() {
612
            boolean forceUpperCase = true;
613
            OracleConnectionParameters params = getHelper().getConnectionParameters();
614
            if (params != null) {
615
                forceUpperCase = params.getForceUppercaseInTableName();
616
            }
617
            if( forceUpperCase ) {
618
                return StringUtils.upperCase(this.tableName);
619
            }
620
            return this.tableName;
621
        }
622

    
623

    
624
        @Override
625
        public String toString(Formatter<ExpressionBuilder.Value> formatter) {
626
            if (formatter != null && formatter.canApply(this)) {
627
                return formatter.format(this);
628
            }
629
            if (this.has_schema()) {
630
                return as_identifier(this.schemaName2provider()) + "."
631
                        + as_identifier(this.tableName2provider());
632
            }
633

    
634
            OracleConnectionParameters params = getHelper().getConnectionParameters();
635
            if (params != null) {
636
                if ((StringUtils.isNotBlank(params.getUser()))) {
637
                    return as_identifier(params.getUser()) + "."
638
                            + as_identifier(this.tableName2provider());
639
                }
640
            }
641
            return as_identifier(this.tableName2provider());
642
        }
643
    }
644

    
645
    public class OracleFromBuilder extends FromBuilderBase {
646

    
647
        @Override
648
        public String toString(Formatter<ExpressionBuilder.Value> formatter) {
649
            if (formatter != null && formatter.canApply(this)) {
650
                return formatter.format(this);
651
            }
652
            if (!StringUtils.isEmpty(passthrough)) {
653
                return passthrough;
654
            }
655
            if (!StringUtils.isEmpty(subquery)) {
656
                return "( " + this.subquery + ") " + quote_for_identifiers() + "_subquery_alias_" + quote_for_identifiers() + " ";
657
            }
658
            if (this.joins == null || this.joins.isEmpty()) {
659
                return this.tableName.toString(formatter);
660
            }
661
            StringBuilder builder = new StringBuilder();
662
            builder.append(this.tableName.toString(formatter));
663
            for (JoinBuilder join : this.joins) {
664
                builder.append(" ");
665
                builder.append(join.toString(formatter));
666
            }
667
            return builder.toString();
668
        }
669
    }
670

    
671
    public class DisposableBlobs implements Disposable {
672

    
673
        private final ArrayList<BLOB> blobList = new ArrayList<>();
674

    
675
        public void add(BLOB blob) {
676
            blobList.add(blob);
677
        }
678

    
679
        @Override
680
        public void dispose() {
681
            blobList.forEach((blob) -> {
682
                try {
683
                    blob.freeTemporary();
684
                } catch (SQLException ex) {
685
                    LOGGER.warn("Can't dispose blob " + blob.toString(), ex);
686
                }
687
            });
688
        }
689

    
690
    }
691

    
692
    protected void setBlob(PreparedStatement st, int columnIndex,
693
            byte[] bytes, DisposableBlobs blobList) throws SQLException, IOException {
694
        Connection conn = st.getConnection();
695
        if (conn instanceof DelegatingConnection) {
696
            conn = ((DelegatingConnection) conn).getInnermostDelegate();
697
        }
698
        BLOB blob = BLOB.createTemporary(conn, false, BLOB.DURATION_SESSION);
699
        blobList.add(blob);
700
        InputStream inputStream;
701
        try (OutputStream outputStream = blob.setBinaryStream(0L)) {
702
            inputStream = new ByteArrayInputStream(bytes);
703
            byte[] buffer = new byte[blob.getBufferSize()];
704
            int byteread;
705
            while ((byteread = inputStream.read(buffer)) != -1) {
706
                outputStream.write(buffer, 0, byteread);
707
            }
708
        }
709
        inputStream.close();
710
        st.setBlob(columnIndex, blob);
711
    }
712

    
713
    @Override
714
    public Disposable setStatementParameters(
715
            PreparedStatement st,
716
            List values,
717
            List<Integer> types, //Can be null
718
            GeometrySupportType geometrySupportType) throws SQLException {
719

    
720
        DisposableBlobs blobList = new DisposableBlobs();
721
        if (values == null) {
722
            return blobList;
723
        }
724
        try {
725
            byte[] bytes;
726
            int columnIndex = 1;
727
            for (Object value : values) {
728
                if (value instanceof Geometry) {
729
                    switch (geometrySupportType) {
730
                        case WKT:
731
                            value = ((Geometry) value).convertToWKT();
732
                            st.setObject(columnIndex, value);
733
                            break;
734
                        case NATIVE:
735
                        case WKB:
736
                            bytes = ((Geometry) value).convertToWKB();
737
                            setBlob(st, columnIndex, bytes, blobList);
738
                            break;
739
                        case EWKB:
740
                            bytes = ((Geometry) value).convertToEWKB();
741
                            setBlob(st, columnIndex, bytes, blobList);
742
                            break;
743
                    }
744
                } else {
745
                    if (types == null) {
746
                        st.setObject(columnIndex, value);
747
                    } else {
748
                        this.setStatementValue(st, columnIndex, types.get(columnIndex - 1), value);
749
                    }
750
                }
751
                columnIndex++;
752
            }
753
        } catch (Exception ex) {
754
            throw new SQLException("Can't set values for the prepared statement.", ex);
755
        }
756
        return blobList;
757
    }
758

    
759
    @Override
760
    public List<Object> getParameters(FeatureProvider feature) {
761
        return getParameters(feature, null);
762
    }
763

    
764
    @Override
765
    public List<Object> getParameters(FeatureProvider feature, List<Integer> types) {
766
        try {
767
            FeatureType type = feature.getType();
768
            FeatureType providerType = this.getHelper().getProviderFeatureType();
769
            List<Object> values = new ArrayList<>();
770
            Object value;
771
            DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
772
            for (ExpressionBuilder.Parameter parameter : this.parameters()) {
773
                if (parameter.is_constant()) {
774
                    value = parameter.value();
775
                    values.add(value);
776
                    if (types != null) {
777
                        if (value == null) {
778
                            if (values.get(values.size() - 2) == EMPTY_POINT) {
779
                                types.add(DataTypes.INTEGER);
780
                            } else {
781
                                types.add(DataTypes.OBJECT);
782
                            }
783
                        } else {
784
                            DataType dataType = dataTypesManager.getDataType(value.getClass());
785
                            types.add(dataType.getType());
786
                        }
787
                    }
788
                } else {
789
                    String name = parameter.name();
790
                    value = feature.get(name);
791
                    FeatureAttributeDescriptor attrDesc = type.getAttributeDescriptor(name);
792
                    Coercion convert = null;
793
                    if (providerType != null) {
794
                        FeatureAttributeDescriptor attrDescProvider = providerType.getAttributeDescriptor(name);
795
                        if (attrDescProvider != null && attrDescProvider.getType() != attrDesc.getType()) {
796
                            convert = attrDescProvider.getDataType().getCoercion();
797
                        }
798
                    }
799
                    switch (attrDesc.getType()) {
800
                        case org.gvsig.fmap.dal.DataTypes.GEOMETRY:
801
                            Geometry geom = this.forceGeometryType(
802
                                    attrDesc.getGeomType(),
803
                                    (Geometry) value
804
                            );
805
                            if (BooleanUtils.isTrue((Boolean) parameter.getProperty(ORACLE_GEOMETRY_PARAMETER))) {
806
                                //Es muy guarro pero es para evitar un error de NullPointerException en Oracle
807
                                if (geom == null) {
808
                                    //NVL2((NULL),SDO_GEOMETRY((EMPTY_POINT), (?)),NULL)
809
                                    values.add(null);
810
                                    values.add(EMPTY_POINT);
811
                                } else {
812
                                    //NVL2((1),SDO_GEOMETRY((WKB), (?)),NULL)
813
                                    values.add(1);
814
                                    values.add(geom);
815
                                }
816
                                if (types != null) {
817
                                    types.add(DataTypes.INTEGER);
818
                                    types.add(DataTypes.GEOMETRY);
819
                                }
820
                            }
821
                            break;
822
                        case org.gvsig.fmap.dal.DataTypes.BOOLEAN:
823
                            if (value == null) {
824
                                values.add(null);
825
                            } else {
826
                                if (convert == null) {
827
                                    values.add(value);
828
                                } else {
829
                                    String s = (String) convert.coerce(value);
830
                                    values.add(s == null ? null : s.substring(0, 1));
831
                                }
832
                            }
833
                            if (types != null) {
834
                                types.add(DataTypes.STRING);
835
                            }
836
                            break;
837
                        default:
838
                            if (convert == null) {
839
                                values.add(value);
840
                            } else {
841
                                values.add(convert.coerce(value));
842
                            }
843
                            if (types != null) {
844
                                int t = attrDesc.getDataType().getType();
845
                                types.add(t);
846
                                if (t == DataTypes.INTEGER) {
847
                                    Object x = values.get(values.size() - 1);
848
                                    if (x != null && !(x instanceof Integer)) {
849
                                        LOGGER.debug("Esto est? mal");
850
                                    }
851
                                }
852

    
853
                            }
854
                            break;
855
                    }
856
                }
857
            }
858

    
859
            return values;
860
        } catch (Exception ex) {
861
            String f = "unknow";
862
            try {
863
                f = feature.toString();
864
            } catch (Exception ex2) {
865
                // Do nothing
866
            }
867
            throw new RuntimeException("Can't get parameters to prepared statement from the feature (" + f + ")", ex);
868
        }
869
    }
870

    
871
    @Override
872
    public List<String> parameters_names() {
873
        List<String> params = new ArrayList<>();
874
        for (ExpressionBuilder.Parameter param : parameters()) {
875
            String s;
876
            switch (param.type()) {
877
                case PARAMETER_TYPE_CONSTANT:
878
                    Object theValue = param.value();
879
                    if (theValue == null) {
880
                        s = "null";
881
                    } else if (theValue instanceof String) {
882
                        s = "'" + (String) theValue + "'";
883
                    } else {
884
                        s = theValue.toString();
885
                    }
886
                    break;
887
                case PARAMETER_TYPE_VARIABLE:
888
                default:
889
                    s = "\"" + param.name() + "\"";
890
            }
891
            params.add(s);
892
            if (BooleanUtils.isTrue((Boolean) param.getProperty(ORACLE_GEOMETRY_PARAMETER))) {
893
                params.add(s);
894
            }
895

    
896
        }
897
        return params;
898
    }
899

    
900
    public String blob(byte[] data) {
901
        StringBuilder builder = new StringBuilder();
902
        builder.append("TO_BLOB(HEXTORAW('");
903
        for (byte abyte : data) {
904
            int v = abyte & 0xff;
905
            builder.append(String.format("%02x", v));
906
        }
907
        builder.append("'))");
908
        return builder.toString();
909
    }
910

    
911
    @Override
912
    public String as_clob(String s) {
913
        int chunkSize = 1024;
914
        StringBuilder builder = new StringBuilder();
915
        builder.append("(TO_CLOB('");
916
        for (int i = 0; i < s.length(); i += chunkSize) {
917
            String chunk = s.substring(i, Math.min(s.length(), i + chunkSize));
918
            if( i>0 ) {
919
                builder.append("') || TO_CLOB('");
920
            }
921
            builder.append(StringUtils.replace(chunk, "'", "''"));
922
        }
923
        builder.append("'))");
924
        return builder.toString();
925
    }
926
    
927
    public class OracleCreateIndexBuilder extends CreateIndexBuilderBase {
928

    
929
        @Override
930
        public List<String> toStrings() {
931
            List<String> sqls = new ArrayList<>();
932
            if (!this.isSpatial) {
933
                // Spatial index is created in a different way because it requires some queries based on the results of other queries
934
                // See OracleUpdateSpatialIndexAndMetadata class
935
                StringBuilder builder = new StringBuilder();
936
                builder.append("CREATE ");
937
                if (this.isUnique) {
938
                    builder.append("UNIQUE ");
939
                }
940
                builder.append("INDEX ");
941
//                if (this.ifNotExist) {
942
//                    builder.append("IF NOT EXISTS ");
943
//                }
944
                builder.append(as_identifier(this.indexName));
945
                builder.append(" ON ");
946
                builder.append(this.table.toString());
947
                builder.append(" ( ");
948
                boolean is_first_column = true;
949
                for (String column : this.columns) {
950
                    if (is_first_column) {
951
                        is_first_column = false;
952
                    } else {
953
                        builder.append(", ");
954
                    }
955
                    builder.append(as_identifier(column));
956
                }
957
                builder.append(" )");
958
                sqls.add(builder.toString());
959
            }
960
            return sqls;
961
        }
962
    }
963

    
964
    public class OracleAlterTableBuilder extends AlterTableBuilderBase {
965

    
966
        public OracleAlterTableBuilder(SQLBuilderBase sqlbuilder) {
967
            super(sqlbuilder);
968
        }
969
        
970
        @Override
971
        public List<String> toStrings() {
972
            List<String> sqls = new ArrayList<>();
973
            List<String> pks = new ArrayList<>();
974

    
975
            for (String column : drops) {
976
                StringBuilder builder = new StringBuilder();
977
                builder.append("ALTER TABLE ");
978
                builder.append(this.table.toString());
979
                builder.append(" DROP COLUMN ");
980
                builder.append(as_identifier(column));
981
                sqls.add(builder.toString());
982
            }
983
            for (ColumnDescriptor column : adds) {
984
                StringBuilder builder = new StringBuilder();
985
                builder.append("ALTER TABLE ");
986
                builder.append(this.table.toString());
987
                builder.append(" ADD "); //COLUMN ");
988
                builder.append(as_identifier(column.getName()));
989
                builder.append(" ");
990
                builder.append(sqltype(
991
                        column.getType(),
992
                        column.getSize(),
993
                        column.getPrecision(),
994
                        column.getScale(),
995
                        column.getGeometryType(),
996
                        column.getGeometrySubtype()
997
                )
998
                );
999
                if (column.getDefaultValue() == null) {
1000
                    if (column.allowNulls()) {
1001
                        builder.append(" DEFAULT NULL");
1002
                    }
1003
                } else {
1004
                    builder.append(" DEFAULT '");
1005
                    builder.append(column.getDefaultValue().toString());
1006
                    builder.append("'");
1007
                }
1008
                if (column.allowNulls()) {
1009
                    builder.append(" NULL");
1010
                } else {
1011
                    builder.append(" NOT NULL");
1012
                }
1013
                if (column.isPrimaryKey()) {
1014
                    pks.add(column.getName());
1015
                }
1016
                sqls.add(builder.toString());
1017
                if (pks.size() > 0) {
1018
                    builder = new StringBuilder("ALTER TABLE ");
1019
                    builder.append(this.table.toString());
1020
                    builder.append(" ADD PRIMARY KEY (");
1021
                    for (int i = 0; i < pks.size(); i++) {
1022
                        if (i != 0) {
1023
                            builder.append(", ");
1024
                        }
1025
                        builder.append(as_identifier(pks.get(i)));
1026
                    }
1027
                    builder.append(")");
1028
                    sqls.add(builder.toString());
1029
                }
1030
                if (column.isAutomatic()) {
1031
                    String sequenceName = getSerialSequenceName(this.table.getName(), column.getName());
1032
                    String sql = MessageFormat.format(
1033
                            ADD_SERIAL_COLUMN_SEQUENCE_QUERY,
1034
                            sequenceName
1035
                    );
1036
                    sqls.add(sql);
1037
                    String autoTriggerName = getSerialTriggerName(this.table.getName(), column.getName());
1038
                    sql = MessageFormat.format(
1039
                            ADD_SERIAL_COLUMN_TRIGGER_QUERY,
1040
                            autoTriggerName,
1041
                            this.table.toString(formatter),
1042
                            column.getName(),
1043
                            sequenceName
1044
                    );
1045
                    sqls.add(sql);
1046
                }
1047

    
1048
                if (column.isGeometry()) {
1049
                    /**
1050
                     * Inserting the geomtype and column on
1051
                     * OGIS_GEOMETRY_COLUMNS.
1052
                     *
1053
                     * It is useful to retrieve the geometry type when the
1054
                     * spatial index can't be defined (for instance users
1055
                     * creating tables on a different schema).
1056
                     *
1057
                     * Note: We don't insert the SRID because it is unusable as
1058
                     * defined on OGIS_GEOMETRY_COLUMNS, as it must reference an
1059
                     * existing SRID on OGIS_SPATIAL_REFERENCE_SYSTEM.
1060
                     * OGIS_SPATIAL_REFERENCE_SYSTEM is empty and it has a
1061
                     * trigger that duplicates on SDO_COORD_REF_SYS any SRID
1062
                     * inserted on OGIS_SPATIAL_REFERENCE_SYSTEM.
1063
                     * SDO_COORD_REF_SYS is not empty and we don't want to
1064
                     * duplicate the SRID definitions!!
1065
                     */
1066
                    int gvsigType = column.getGeometryType();
1067
                    int gvsigSubtype = column.getGeometryType();
1068
                    String sql = MessageFormat.format( // delete before inserting to avoid creating duplicates
1069
                            DELETE_FROM_OGIS_GEOMETRY_COLUMNS_QUERY,
1070
                            this.table().getSchema(),
1071
                            this.table().getName(),
1072
                            column.getName());
1073
                    sqls.add(sql);
1074
                    sql = MessageFormat.format(
1075
                            INSERT_OGIS_GEOMETRY_COLUMNS_QUERY,
1076
                            this.table().getSchema(),
1077
                            this.table().getName(),
1078
                            column.getName(),
1079
                            Integer.toString(GeometryTypeUtils.toSFSGeometryTypeCode(gvsigType, gvsigSubtype)));
1080
                    sqls.add(sql);
1081
                    // Note: The spatial index will be created after inserting/updating layer metadata.
1082
                    //       See OracleUpdateSpatialIndexAndMetadata class
1083
                }
1084
            }
1085
            for (ColumnDescriptor column : alters) {
1086
                if (!column.isGeometry()) { // FIXME: can't modify geom column. It could be done by adding a temporary one, copying values and then droping and renaming
1087
                    StringBuilder builder = new StringBuilder();
1088
                    builder.append("ALTER TABLE ");
1089
                    builder.append(this.table.toString());
1090
                    builder.append(" MODIFY (");
1091
                    builder.append(as_identifier(column.getName()));
1092
                    builder.append(" ");
1093
                    builder.append(sqltype(
1094
                            column.getType(),
1095
                            column.getSize(),
1096
                            column.getPrecision(),
1097
                            column.getScale(),
1098
                            column.getGeometryType(),
1099
                            column.getGeometrySubtype()
1100
                    )
1101
                    );
1102
                    if (column.getDefaultValue() == null) {
1103
                        builder.append(" DEFAULT NULL");
1104
                    } else {
1105
                        builder.append(" DEFAULT '");
1106
                        builder.append(column.getDefaultValue().toString());
1107
                        builder.append("'");
1108
                    }
1109
                    builder.append(")");
1110
                    sqls.add(builder.toString());
1111
                }
1112
            }
1113
            for (Pair<String, String> pair : renames) {
1114
                StringBuilder builder = new StringBuilder();
1115
                builder.append("ALTER TABLE ");
1116
                builder.append(this.table.toString());
1117
                builder.append(" RENAME COLUMN ");
1118
                builder.append(as_identifier(pair.getLeft()));
1119
                builder.append(" TO ");
1120
                builder.append(as_identifier(pair.getRight()));
1121
                sqls.add(builder.toString());
1122
            }
1123
            return sqls;
1124
        }
1125
    }
1126

    
1127
    @Override
1128
    protected AlterTableBuilder createAlterTableBuilder() {
1129
        return new OracleAlterTableBuilder(this);
1130
    }
1131

    
1132
    @Override
1133
    public CreateIndexBuilder createCreateIndexBuilder() {
1134
        return new OracleCreateIndexBuilder();
1135
    }
1136

    
1137
    @Override
1138
    public String quote_for_identifiers() {
1139
        return this.quote_for_identifiers;
1140
    }
1141

    
1142
    @Override
1143
    public String quote_for_strings() {
1144
        return this.quote_for_strings;
1145
    }
1146

    
1147
    @Override
1148
    protected SelectColumnBuilder createSelectColumnBuilder() {
1149
        return new OracleSelectColumnBuilder(this);
1150
    }
1151

    
1152
    public class OracleSelectColumnBuilder extends SelectColumnBuilderBase {
1153

    
1154
        public OracleSelectColumnBuilder(SQLBuilder sqlbuilder) {
1155
            super(sqlbuilder);
1156
        }
1157

    
1158
        @Override
1159
        public String toString(Formatter<ExpressionBuilder.Value> formatter) {
1160
            if (formatter != null && formatter.canApply(this)) {
1161
                return formatter.format(this);
1162
            }
1163
            StringBuilder builder = new StringBuilder();
1164
            if (this.asGeometry) {
1165
                if(this.value == VALUE_NULL){
1166
                    builder.append(this.value.toString(formatter));
1167
                } else {
1168
                    builder.append(expression().ST_AsBinary(this.name).toString(formatter));
1169
                }
1170
            } else {
1171
                if (this.value == null) {
1172
                    builder.append(this.name.toString(formatter));
1173
                } else {
1174
                    builder.append(this.value.toString(formatter));
1175
                }
1176
            }
1177
            if (this.alias != null) {
1178
                builder.append(" ");
1179
                builder.append(as_identifier(this.alias));
1180
            }
1181
            return builder.toString();
1182
        }
1183
    }
1184

    
1185
    @Override
1186
    public SelectBuilder select() {
1187
        if (this.select == null) {
1188
            this.select = this.createSelectBuilder();
1189
        }
1190
        return this.select;
1191
    }
1192

    
1193
    @Override
1194
    public UpdateBuilder update() {
1195
        if (this.update == null) {
1196
            this.update = this.createUpdateBuilder();
1197
        }
1198
        return this.update;
1199
    }
1200

    
1201
    @Override
1202
    public UpdateTableStatisticsBuilder update_table_statistics() {
1203
        if (this.update_table_statistics == null) {
1204
            this.update_table_statistics = this.createUpdateTableStatisticsBuilder();
1205
        }
1206
        return this.update_table_statistics;
1207
    }
1208

    
1209
    @Override
1210
    public DropTableBuilder drop_table() {
1211
        if (this.drop_table == null) {
1212
            this.drop_table = this.createDropTableBuilder();
1213
        }
1214
        return this.drop_table;
1215
    }
1216

    
1217
    @Override
1218
    public CreateIndexBuilder create_index() {
1219
        if (this.create_index == null) {
1220
            this.create_index = this.createCreateIndexBuilder();
1221
        }
1222
        return this.create_index;
1223
    }
1224

    
1225
    @Override
1226
    public DeleteBuilder delete() {
1227
        if (this.delete == null) {
1228
            this.delete = this.createDeleteBuilder();
1229
        }
1230
        return this.delete;
1231
    }
1232

    
1233
    @Override
1234
    public InsertBuilder insert() {
1235
        if (this.insert == null) {
1236
            this.insert = this.createInsertBuilder();
1237
        }
1238
        return this.insert;
1239
    }
1240

    
1241
    @Override
1242
    public TableNameBuilder table_name() {
1243
        if (this.table_name == null) {
1244
            this.table_name = this.createTableNameBuilder();
1245
        }
1246
        return this.table_name;
1247
    }
1248

    
1249
    @Override
1250
    public AlterTableBuilder alter_table() {
1251
        if (this.alter_table == null) {
1252
            this.alter_table = this.createAlterTableBuilder();
1253
        }
1254
        return this.alter_table;
1255
    }
1256

    
1257
    @Override
1258
    public CreateTableBuilder create_table() {
1259
        if (this.create_table == null) {
1260
            this.create_table = this.createCreateTableBuilder();
1261
        }
1262
        return this.create_table;
1263
    }
1264

    
1265
    @Override
1266
    public GrantBuilder grant() {
1267
        if (this.grant == null) {
1268
            this.grant = this.createGrantBuilder();
1269
        }
1270
        return this.grant;
1271
    }
1272

    
1273
    @Override
1274
    public String sqltype(int type, int size, int precision, int scale, int geomType, int geomSubtype) {
1275
        switch (type) {
1276
            case DataTypes.DECIMAL:
1277
                if (precision > 38 && scale < 0) {
1278
                    if (precision > 126) {
1279
                        precision = 126;
1280
                    }
1281
                    return String.format("FLOAT(%d)", precision);
1282
                }
1283
                if (precision < 1) {
1284
                    precision = DataType.DECIMAL_DEFAULT_PRECISION;
1285
                }
1286
                if (scale < 1) {
1287
                    return MessageFormat.format(type_decimal_p, precision);
1288
                }
1289
                return MessageFormat.format(type_decimal_ps, precision, scale);
1290
            default:
1291
                return super.sqltype(type, size, precision, scale, geomType, geomSubtype);
1292
        }
1293
    }
1294

    
1295
    @Override
1296
    public int getMaxRecomendedSQLLength() {
1297
        return 2048;
1298
    }
1299
    
1300
}