Statistics
| Revision:

gvsig-oracle / org.gvsig.oracle / trunk / org.gvsig.oracle / org.gvsig.oracle.provider / src / main / java / org / gvsig / oracle / dal / operations / OracleFetchFeatureTypeOperation.java @ 294

History | View | Annotate | Download (18.4 KB)

1
package org.gvsig.oracle.dal.operations;
2

    
3
import java.sql.Connection;
4
import java.sql.PreparedStatement;
5
import java.sql.ResultSet;
6
import java.sql.ResultSetMetaData;
7
import java.sql.SQLException;
8
import java.util.HashSet;
9
import java.util.List;
10
import java.util.Objects;
11
import java.util.Set;
12

    
13
import org.cresques.cts.IProjection;
14
import org.gvsig.expressionevaluator.ExpressionBuilder;
15
import org.gvsig.fmap.dal.DataTypes;
16
import org.gvsig.fmap.dal.exception.DataException;
17
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
18
import org.gvsig.fmap.dal.feature.EditableFeatureType;
19
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
20
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
21
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
22
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
23
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
24
import org.gvsig.fmap.geom.type.GeometryType;
25
import org.gvsig.oracle.dal.GeometryTypeUtils;
26
import org.gvsig.oracle.dal.OracleSQLBuilder;
27
import org.gvsig.tools.dataTypes.DataType;
28

    
29
@SuppressWarnings("UseSpecificCatch")
30
public class OracleFetchFeatureTypeOperation extends FetchFeatureTypeOperation {
31

    
32
    private static final int ORACLE_COLUMN_BINARY_FLOAT_TYPECODE = 100;
33
    private static final int ORACLE_COLUMN_BINARY_DOUBLE_TYPECODE = 101;
34
    public static final String ORACLE_SRID_ATTR_TAG = "oracle_srid";
35
    protected Set<String> tableTriggers;
36

    
37
    public OracleFetchFeatureTypeOperation(JDBCHelper helper) {
38
        super(helper);
39
    }
40

    
41
    public OracleFetchFeatureTypeOperation(
42
            JDBCHelper helper,
43
            EditableFeatureType featureType,
44
            TableReference table,
45
            List<String> primaryKeys,
46
            String defaultGeometryColumn,
47
            IProjection crs
48
    ) {
49
        super(helper, featureType, table, primaryKeys, defaultGeometryColumn, crs);
50
    }
51

    
52
    @Override
53
    public void fetch(Connection conn) throws DataException {
54
        super.fetch(conn);
55
    }
56

    
57
    @Override
58
    public String getSQLToRetrievePrimaryKeysFromInformationSchema() throws SQLException {
59
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
60
        ExpressionBuilder expbuilder = sqlbuilder.expression();
61

    
62
        sqlbuilder.select().column().name(
63
                sqlbuilder.quote_for_identifiers()
64
                        +"USER_TAB_COLS"
65
                        +sqlbuilder.quote_for_identifiers()
66
                        +"."
67
                        +sqlbuilder.quote_for_identifiers()
68
                        +"COLUMN_NAME"
69
                        +sqlbuilder.quote_for_identifiers()
70
        );
71
        sqlbuilder.select().column().name(
72
                sqlbuilder.quote_for_identifiers()
73
                        +"ALL_CONSTRAINTS"
74
                        +sqlbuilder.quote_for_identifiers()
75
                        +"."
76
                        +sqlbuilder.quote_for_identifiers()
77
                        +"CONSTRAINT_TYPE"
78
                        +sqlbuilder.quote_for_identifiers()
79
        );
80

    
81
        sqlbuilder.select().from().custom(
82
                "USER_TAB_COLS "
83
                + "JOIN ALL_CONS_COLUMNS on (ALL_CONS_COLUMNS.TABLE_NAME = USER_TAB_COLS.TABLE_NAME and ALL_CONS_COLUMNS.COLUMN_NAME = USER_TAB_COLS.COLUMN_NAME) "
84
                + "LEFT JOIN ALL_CONSTRAINTS on ALL_CONSTRAINTS.CONSTRAINT_NAME = ALL_CONS_COLUMNS.CONSTRAINT_NAME"
85
        );
86

    
87
        sqlbuilder.select().where().set(
88
                expbuilder.like(
89
                        expbuilder.custom(
90
                                sqlbuilder.quote_for_identifiers()
91
                                        +"USER_TAB_COLS"
92
                                        +sqlbuilder.quote_for_identifiers()
93
                                        +"."
94
                                        +sqlbuilder.quote_for_identifiers()
95
                                        +"TABLE_NAME"
96
                                        +sqlbuilder.quote_for_identifiers()),
97
                        
98
                        expbuilder.constant(table.getTable())
99
                )
100
        );
101

    
102
        sqlbuilder.select().where().and(
103
                expbuilder.eq(
104
                        expbuilder.custom(
105
                                sqlbuilder.quote_for_identifiers()
106
                                        +"ALL_CONSTRAINTS"
107
                                        +sqlbuilder.quote_for_identifiers()
108
                                        +"."
109
                                        +sqlbuilder.quote_for_identifiers()
110
                                        +"CONSTRAINT_TYPE"
111
                                        +sqlbuilder.quote_for_identifiers()),
112
                        expbuilder.constant("'P'")
113
                )
114
        );
115
        return sqlbuilder.select().toString();
116
    }
117

    
118
    @Override
119
    protected int getDataTypeFromMetadata(
120
            ResultSetMetaData rsMetadata,
121
            int colIndex
122
    ) throws SQLException {
123
        int type = rsMetadata.getColumnType(colIndex);
124
        switch (type) {
125
            case java.sql.Types.INTEGER:
126
                return DataTypes.INT;
127

    
128
            case java.sql.Types.BIGINT:
129
                return DataTypes.LONG;
130

    
131
            case java.sql.Types.REAL:
132
                return DataTypes.DOUBLE;
133

    
134
            case java.sql.Types.DOUBLE:
135
            case ORACLE_COLUMN_BINARY_DOUBLE_TYPECODE:
136
                return DataTypes.DOUBLE;
137

    
138
            case java.sql.Types.CHAR:
139
                return DataTypes.STRING;
140

    
141
            case java.sql.Types.CLOB:
142
            case java.sql.Types.VARCHAR:
143
            case java.sql.Types.LONGVARCHAR:
144
                return DataTypes.STRING;
145

    
146
            case java.sql.Types.FLOAT:
147
            case ORACLE_COLUMN_BINARY_FLOAT_TYPECODE:
148
                return DataTypes.FLOAT;
149
                
150
            case java.sql.Types.NUMERIC:
151
            case java.sql.Types.DECIMAL:
152
                if (rsMetadata.getScale(colIndex) == 0) {
153
                    if (rsMetadata.getPrecision(colIndex) == DataType.LONG_MAX_PRECISION-1) {
154
                        return DataTypes.LONG;
155
                    }
156
                    if (rsMetadata.getPrecision(colIndex) == DataType.INT_MAX_PRECISION-1) {
157
                        return DataTypes.INTEGER;
158
                    }
159
                }
160
                return DataTypes.DECIMAL;
161

    
162
            case java.sql.Types.DATE:
163
                return DataTypes.DATE;
164

    
165
            case java.sql.Types.TIME:
166
                return DataTypes.TIME;
167

    
168
            case java.sql.Types.TIMESTAMP:
169
                return DataTypes.TIMESTAMP;
170

    
171
            case java.sql.Types.BOOLEAN:
172
            case java.sql.Types.BIT:
173
                return DataTypes.BOOLEAN;
174

    
175
            case java.sql.Types.BLOB:
176
            case java.sql.Types.BINARY:
177
            case java.sql.Types.LONGVARBINARY:
178
                return DataTypes.BYTEARRAY;
179
                
180
            default:
181
                String typeName = rsMetadata.getColumnTypeName(colIndex);
182
                if ("MDSYS.SDO_GEOMETRY".equalsIgnoreCase(typeName)) {
183
                    return DataTypes.GEOMETRY;
184
                }
185
                return DataTypes.OBJECT;
186
        }
187
    }
188

    
189
    @Override
190
    protected void fetchGeometryTypeAndSRS(
191
            EditableFeatureAttributeDescriptor attr,
192
            ResultSetMetaData rsMetadata,
193
            int colIndex
194
    ) {
195
        if (attr.getType() != DataTypes.GEOMETRY) {
196
            return;
197
        }
198
        doFetchFromMetadataView(attr, rsMetadata, colIndex);
199
    }
200

    
201
    /**
202
     * Fetches the SRID and geom type from several Oracle metadata tables:
203
     * ALL_SDO_GEOM_METADATA, ALL_SDO_INDEX_METADATA, ALL_SDO_INDEX_INFO
204
     *
205
     * @param attr
206
     * @param rsMetadata
207
     * @param colIndex
208
     */
209
    protected void doFetchFromMetadataView(
210
            EditableFeatureAttributeDescriptor attr,
211
            ResultSetMetaData rsMetadata,
212
            int colIndex
213
    ) {
214

    
215
        int srid = -1;
216
        int dimensions = 2;
217
        try {
218
            String sql = "SELECT SRID, "
219
                    + "( SELECT count(*) FROM TABLE(t1.diminfo) ) dimensions "
220
                    + "FROM ALL_SDO_GEOM_METADATA t1 "
221
                    + "WHERE OWNER = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?";
222

    
223
            ResultSet rs = null;
224
            PreparedStatement st = null;
225
            try {
226
                st = this.getConnection().prepareStatement(sql);
227
                st.setString(1, this.getTable().getSchema());
228
                st.setString(2, this.getTable().getTable().toUpperCase());
229
                st.setString(3, attr.getName().toUpperCase());
230

    
231
                rs = JDBCUtils.executeQuery(st, sql);
232

    
233
                if (rs.next()) {
234
                    srid = rs.getInt(1);
235
                    dimensions = rs.getInt(2);
236
                }
237
                if (srid != -1) {
238
                    IProjection proj = this.helper.getSRSSolver().getProjection(conn, srid);
239
                    attr.setSRS(proj);
240
                    if(this.helper.getSRSSolver().hasDatabaseCode(conn, srid)){
241
                        attr.getTags().set(ORACLE_SRID_ATTR_TAG, srid);
242
                    }
243
                }
244
            } catch (Exception ex) {
245
                LOGGER.debug("Can't get srs for column '" + attr.getName() + "'.", ex);
246
            } finally {
247
                JDBCUtils.closeQuietly(rs);
248
                JDBCUtils.closeQuietly(st);
249
            }
250
            
251
            if(srid == -1) {
252
                sql = "SELECT SRID, "
253
                        + "( SELECT count(*) FROM TABLE(t1.diminfo) ) dimensions "
254
                        + "FROM USER_SDO_GEOM_METADATA t1 "
255
                        + "WHERE TABLE_NAME = ? AND COLUMN_NAME = ?";
256

    
257
                rs = null;
258
                st = null;
259
                try {
260
                    st = this.getConnection().prepareStatement(sql);
261
                    st.setString(1, this.getTable().getTable().toUpperCase());
262
                    st.setString(2, attr.getName().toUpperCase());
263

    
264
                    rs = JDBCUtils.executeQuery(st, sql);
265

    
266
                    if (rs.next()) {
267
                        srid = rs.getInt(1);
268
                        dimensions = rs.getInt(2);
269
                    }
270
                    
271
                    if (srid != -1) {
272
                        IProjection proj = this.helper.getSRSSolver().getProjection(conn, srid);
273
                        attr.setSRS(proj);
274
                    }
275
                } catch (Exception ex) {
276
                    LOGGER.debug("Can't get srs for column '" + attr.getName() + "'.", ex);
277
                } finally {
278
                    JDBCUtils.closeQuietly(rs);
279
                    JDBCUtils.closeQuietly(st);
280
                }
281
            }
282
        } catch (Exception ex) {
283
            LOGGER.debug("Can't get geometry type and srs from column '" + attr.getName() + "'.", ex);
284
        }
285
        String oracleGeomType = doFetchFromSpatialIndex(attr.getName());
286
        GeometryType gt;
287
        if (oracleGeomType != null) {
288
            gt = GeometryTypeUtils.getGeometryTypeFromOracleName(oracleGeomType, dimensions);
289
        } else {
290
            gt = doFetchFromOgisGeometryTable(attr);
291
        }
292
        if (gt == null) {
293
            switch (dimensions) {
294
                case 4:
295
                    gt = GeometryTypeUtils.getGeometryTypeFromDatabaseTypeName("GEOMETRYZM");
296
                    break;
297
                case 3:
298
                    gt = GeometryTypeUtils.getGeometryTypeFromDatabaseTypeName("GEOMETRYZ");
299
                    break;
300
                default:
301
                    gt = GeometryTypeUtils.getGeometryTypeFromDatabaseTypeName("GEOMETRY");
302
                    break;
303
            }
304
        }
305
        attr.setGeometryType(gt);
306
    }
307

    
308
    protected GeometryType doFetchFromOgisGeometryTable(EditableFeatureAttributeDescriptor attr) {
309
        String sql = "SELECT GEOMETRY_TYPE "
310
                + "FROM MDSYS.OGIS_GEOMETRY_COLUMNS "
311
                + "WHERE F_TABLE_SCHEMA = ? AND F_TABLE_NAME = ? AND F_GEOMETRY_COLUMN = ?";
312

    
313
        ResultSet rs = null;
314
        PreparedStatement st = null;
315
        try {
316
            st = this.getConnection().prepareStatement(sql);
317
            st.setString(1, this.getTable().getSchema());
318
            st.setString(2, this.getTable().getTable());
319
            st.setString(3, attr.getName());
320

    
321
            rs = JDBCUtils.executeQuery(st, sql);
322
            int geomType;
323
            if (rs.next()) {
324
                geomType = rs.getInt(1);
325
                return GeometryTypeUtils.getGeometryTypeFromSFSTypeCode(geomType);
326
            }
327
        } catch (Exception ex) {
328
            LOGGER.debug("Can't get geometry type from MDSYS.OGIS_GEOMETRY_COLUMNS '" + attr.getName() + "'.", ex);
329
        } finally {
330
            JDBCUtils.closeQuietly(rs);
331
            JDBCUtils.closeQuietly(st);
332
        }
333
        return null;
334
    }
335

    
336
    /**
337
     * Fetches the geometry type from the spatial index definition. Note that
338
     * this method does not allow to distinguish XYZ geoms from XYM geoms, so
339
     * XYM is reported as XYZ.
340
     *
341
     * @param geomColumnName the name of the column containing the geometry
342
     * @return An Oracle geometry type name, or "DEFAULT" if an spatial index is
343
     * not defined for the geom
344
     */
345
    protected String doFetchFromSpatialIndex(
346
            String geomColumnName
347
    ) {
348
        try {
349
            String sql = "SELECT SDO_LAYER_GTYPE "
350
                    + "FROM ALL_SDO_INDEX_METADATA tmd, ALL_SDO_INDEX_INFO tinfo "
351
                    + "WHERE tmd.SDO_INDEX_OWNER = tinfo.SDO_INDEX_OWNER "
352
                    + "AND tmd.SDO_INDEX_NAME = tinfo.INDEX_NAME "
353
                    + "AND TABLE_OWNER = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?";
354

    
355
            ResultSet rs = null;
356
            PreparedStatement st = null;
357

    
358
            try {
359
                st = this.getConnection().prepareStatement(sql);
360
                st.setString(1, this.getTable().getSchema());
361
                st.setString(2, this.getTable().getTable());
362
                st.setString(3, geomColumnName);
363

    
364
                rs = JDBCUtils.executeQuery(st, sql);
365
                String geomType;
366
                if (rs.next()) {
367
                    geomType = rs.getString(1);
368
                    return geomType;
369
                }
370
            } finally {
371
                JDBCUtils.closeQuietly(rs);
372
                JDBCUtils.closeQuietly(st);
373
            }
374
        } catch (Exception ex) {
375
            LOGGER.debug("Can't get geometry type from column '" + geomColumnName + "'.", ex);
376
        }
377
        return null;
378
    }
379

    
380
    protected Set<String> fetchTriggers(Connection connection, String schema, String table) {
381
        if (tableTriggers == null) {
382
            String getTriggersSql = "SELECT TRIGGER_NAME FROM ALL_TRIGGERS"
383
                    + " WHERE OWNER = ? AND TABLE_NAME = ? AND STATUS = 'ENABLED'";
384

    
385
            ResultSet rs = null;
386
            PreparedStatement st = null;
387
            Set<String> triggers = new HashSet<>();
388
            try {
389
                st = connection.prepareStatement(getTriggersSql);
390
                st.setString(1, schema);
391
                st.setString(2, table);
392
                rs = JDBCUtils.executeQuery(st, getTriggersSql);
393

    
394
                while (rs.next()) {
395
                    triggers.add(rs.getString(1));
396
                }
397
            } catch (Exception ex) {
398

    
399
            } finally {
400
                JDBCUtils.closeQuietly(rs);
401
                JDBCUtils.closeQuietly(st);
402
            }
403
            tableTriggers = triggers;
404
        }
405
        return tableTriggers;
406
    }
407

    
408
    @Override
409
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(EditableFeatureType type, Connection conn,
410
            ResultSetMetaData rsMetadata, int colIndex) throws SQLException {
411
        OracleSQLBuilder sqlbuilder = (OracleSQLBuilder) this.helper.createSQLBuilder();
412
//        EditableFeatureAttributeDescriptor attr = super.getAttributeFromMetadata(type, conn, rsMetadata, colIndex);
413
        EditableFeatureAttributeDescriptor attr = type.add(
414
                rsMetadata.getColumnName(colIndex),
415
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
416
        );
417

    
418
        attr.setAllowNull(
419
            rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable
420
        );
421
        attr.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
422
        attr.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
423
        switch(attr.getType()) {
424
            case DataTypes.STRING:
425
              attr.setSize(rsMetadata.getPrecision(colIndex));
426
              attr.setPrecision(DataType.PRECISION_NONE);
427
              attr.setScale(DataType.SCALE_NONE);
428
              break;
429
            case DataTypes.BYTE:
430
              attr.setDisplaySize(rsMetadata.getColumnDisplaySize(colIndex));
431
              attr.setPrecision(DataType.BYTE_DEFAULT_PRECISION);
432
              attr.setScale(DataType.SCALE_NONE);
433
              break;
434
            case DataTypes.INT:
435
            case DataTypes.LONG:
436
              attr.setPrecision(rsMetadata.getPrecision(colIndex));
437
              attr.setScale(DataType.SCALE_NONE);
438
              break;
439
            case DataTypes.FLOAT:
440
            case DataTypes.DOUBLE:
441
            case DataTypes.DECIMAL:
442
              attr.setDisplaySize(rsMetadata.getColumnDisplaySize(colIndex));
443
              attr.setScale(rsMetadata.getScale(colIndex));
444
              attr.setPrecision(rsMetadata.getPrecision(colIndex));
445
              break;
446
            case DataTypes.OBJECT:
447
                attr.setAdditionalInfo(
448
                        "SQLType",
449
                        rsMetadata.getColumnType(colIndex)
450
                );
451
                attr.setAdditionalInfo(
452
                        "SQLTypeName",
453
                        rsMetadata.getColumnTypeName(colIndex)
454
                );
455
                break;
456
            case DataTypes.GEOMETRY:
457
                this.fetchGeometryTypeAndSRS(attr, rsMetadata, colIndex);
458
                break;
459
        }
460

    
461
        
462
        
463
        String serialTriggerName = sqlbuilder.getSerialTriggerName(this.getTable().getTable(), attr.getName());
464
        if (fetchTriggers(conn, this.getTable().getSchema(), this.getTable().getTable()).contains(serialTriggerName)) {
465
            attr.setIsAutomatic(true);
466
        }
467
        return attr;
468
    }
469

    
470
}