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

History | View | Annotate | Download (18.9 KB)

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

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

    
11
import org.cresques.cts.IProjection;
12
import org.gvsig.expressionevaluator.ExpressionBuilder;
13
import org.gvsig.fmap.dal.DataTypes;
14
import org.gvsig.fmap.dal.exception.DataException;
15
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
16
import org.gvsig.fmap.dal.feature.EditableFeatureType;
17
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
18
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
19
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
20
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
21
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
22
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
23
import org.gvsig.fmap.geom.Geometry;
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
            int geometryType,
49
            int geometrySubtype
50
    ) {
51
        super(helper, featureType, table, primaryKeys, defaultGeometryColumn, crs, geometryType, geometrySubtype);
52
    }
53

    
54
    @Override
55
    public void fetch(JDBCConnection conn) throws DataException {
56
        super.fetch(conn);
57
    }
58
    
59
    @Override
60
    public String getSQLToRetrievePrimaryKeysFromInformationSchema() throws SQLException {
61
        OracleSQLBuilder sqlbuilder = (OracleSQLBuilder) this.createSQLBuilder();
62
        ExpressionBuilder expbuilder = sqlbuilder.expression();
63

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

    
83
        sqlbuilder.select().from().custom(
84
                "USER_TAB_COLS "
85
                + "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) "
86
                + "LEFT JOIN ALL_CONSTRAINTS on ALL_CONSTRAINTS.CONSTRAINT_NAME = ALL_CONS_COLUMNS.CONSTRAINT_NAME"
87
        );
88

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

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

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

    
130
            case java.sql.Types.BIGINT:
131
                return DataTypes.LONG;
132

    
133
            case java.sql.Types.REAL:
134
                return DataTypes.DOUBLE;
135

    
136
            case java.sql.Types.DOUBLE:
137
            case ORACLE_COLUMN_BINARY_DOUBLE_TYPECODE:
138
                return DataTypes.DOUBLE;
139

    
140
            case java.sql.Types.CHAR:
141
                return DataTypes.STRING;
142

    
143
            case java.sql.Types.NCLOB:
144
            case java.sql.Types.CLOB:
145
            case java.sql.Types.NVARCHAR:
146
            case java.sql.Types.VARCHAR:
147
            case java.sql.Types.LONGVARCHAR:
148
                return DataTypes.STRING;
149

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

    
166
            case java.sql.Types.DATE:
167
                return DataTypes.DATE;
168

    
169
            case java.sql.Types.TIME:
170
                return DataTypes.TIME;
171

    
172
            case java.sql.Types.TIMESTAMP:
173
                return DataTypes.TIMESTAMP;
174

    
175
            case java.sql.Types.BOOLEAN:
176
            case java.sql.Types.BIT:
177
                return DataTypes.BOOLEAN;
178

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

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

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

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

    
227
            ResultSet rs = null;
228
            PreparedStatement st = null;
229
            try {
230
                st = this.getConnection().prepareStatement(sql);
231
                st.setString(1, this.getTable().getSchema());
232
                st.setString(2, this.getTable().getTable().toUpperCase());
233
                st.setString(3, attr.getName().toUpperCase());
234

    
235
                rs = JDBCUtils.executeQuery(st, sql);
236

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

    
261
                rs = null;
262
                st = null;
263
                try {
264
                    st = this.getConnection().prepareStatement(sql);
265
                    st.setString(1, this.getTable().getTable().toUpperCase());
266
                    st.setString(2, attr.getName().toUpperCase());
267

    
268
                    rs = JDBCUtils.executeQuery(st, sql);
269

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

    
318
    protected GeometryType doFetchFromOgisGeometryTable(EditableFeatureAttributeDescriptor attr) {
319
        String sql = "SELECT GEOMETRY_TYPE "
320
                + "FROM MDSYS.OGIS_GEOMETRY_COLUMNS "
321
                + "WHERE F_TABLE_SCHEMA = ? AND F_TABLE_NAME = ? AND F_GEOMETRY_COLUMN = ?";
322

    
323
        ResultSet rs = null;
324
        PreparedStatement st = null;
325
        try {
326
            st = this.getConnection().prepareStatement(sql);
327
            st.setString(1, this.getTable().getSchema());
328
            st.setString(2, this.getTable().getTable());
329
            st.setString(3, attr.getName());
330

    
331
            rs = JDBCUtils.executeQuery(st, sql);
332
            int geomType;
333
            if (rs.next()) {
334
                geomType = rs.getInt(1);
335
                return GeometryTypeUtils.getGeometryTypeFromSFSTypeCode(geomType);
336
            }
337
        } catch (Exception ex) {
338
            LOGGER.debug("Can't get geometry type from MDSYS.OGIS_GEOMETRY_COLUMNS '" + attr.getName() + "'.", ex);
339
        } finally {
340
            JDBCUtils.closeQuietly(rs);
341
            JDBCUtils.closeQuietly(st);
342
        }
343
        return null;
344
    }
345

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

    
365
            ResultSet rs = null;
366
            PreparedStatement st = null;
367

    
368
            try {
369
                st = this.getConnection().prepareStatement(sql);
370
                st.setString(1, this.getTable().getSchema());
371
                st.setString(2, this.getTable().getTable());
372
                st.setString(3, geomColumnName);
373

    
374
                rs = JDBCUtils.executeQuery(st, sql);
375
                String geomType;
376
                if (rs.next()) {
377
                    geomType = rs.getString(1);
378
                    return geomType;
379
                }
380
            } finally {
381
                JDBCUtils.closeQuietly(rs);
382
                JDBCUtils.closeQuietly(st);
383
            }
384
        } catch (Exception ex) {
385
            LOGGER.debug("Can't get geometry type from column '" + geomColumnName + "'.", ex);
386
        }
387
        return null;
388
    }
389

    
390
    protected Set<String> fetchTriggers(JDBCConnection connection, String schema, String table) {
391
        if (tableTriggers == null) {
392
            String getTriggersSql = "SELECT TRIGGER_NAME FROM ALL_TRIGGERS"
393
                    + " WHERE OWNER = ? AND TABLE_NAME = ? AND STATUS = 'ENABLED'";
394

    
395
            ResultSet rs = null;
396
            PreparedStatement st = null;
397
            Set<String> triggers = new HashSet<>();
398
            try {
399
                st = connection.prepareStatement(getTriggersSql);
400
                st.setString(1, schema);
401
                st.setString(2, table);
402
                rs = JDBCUtils.executeQuery(st, getTriggersSql);
403

    
404
                while (rs.next()) {
405
                    triggers.add(rs.getString(1));
406
                }
407
            } catch (Exception ex) {
408

    
409
            } finally {
410
                JDBCUtils.closeQuietly(rs);
411
                JDBCUtils.closeQuietly(st);
412
            }
413
            tableTriggers = triggers;
414
        }
415
        return tableTriggers;
416
    }
417

    
418
    @Override
419
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(EditableFeatureType type, JDBCConnection conn,
420
            ResultSetMetaData rsMetadata, int colIndex) throws SQLException {
421
        OracleSQLBuilder sqlbuilder = (OracleSQLBuilder) this.helper.createSQLBuilder();
422
//        EditableFeatureAttributeDescriptor attr = super.getAttributeFromMetadata(type, conn, rsMetadata, colIndex);
423
        EditableFeatureAttributeDescriptor attr = type.add(
424
                rsMetadata.getColumnName(colIndex),
425
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
426
        );
427

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

    
471
        
472
        
473
        String serialTriggerName = sqlbuilder.getSerialTriggerName(this.getTable().getTable(), attr.getName());
474
        if (fetchTriggers(conn, this.getTable().getSchema(), this.getTable().getTable()).contains(serialTriggerName)) {
475
            attr.setIsAutomatic(true);
476
        }
477
        return attr;
478
    }
479

    
480
}