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

History | View | Annotate | Download (17.4 KB)

1

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

    
4
import java.sql.Connection;
5
import java.sql.PreparedStatement;
6
import java.sql.ResultSet;
7
import java.sql.ResultSetMetaData;
8
import java.sql.SQLException;
9
import java.sql.Statement;
10
import java.util.HashMap;
11
import java.util.HashSet;
12
import java.util.List;
13
import java.util.Map;
14

    
15
import org.cresques.cts.IProjection;
16
import org.gvsig.fmap.dal.DataTypes;
17
import org.gvsig.fmap.dal.exception.DataException;
18
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
19
import org.gvsig.fmap.dal.feature.EditableFeatureType;
20
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
21
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
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.Geometry;
25
import org.gvsig.fmap.geom.GeometryLocator;
26
import org.gvsig.fmap.geom.GeometryManager;
27
import org.gvsig.fmap.geom.type.GeometryType;
28

    
29
public class OracleFetchFeatureTypeOperation extends FetchFeatureTypeOperation {
30

    
31
    private static Map<String,GeometryType>databaseGeometryTypes = null;
32
    private static Map<Integer,GeometryType>databaseGeometryTypeNumbers = null;
33
    
34
    private static final int UNKNOWN_GEOMETRY = 0;
35
    private static final int POINT = 1;
36
    private static final int LINE_OR_CURVE = 2;
37
    private static final int POLYGON = 3;
38
    private static final int COLLECTION = 4;
39
    private static final int MULTIPOINT = 5;
40
    private static final int MULTILINE_OR_MULTICURVE = 6;
41
    private static final int MULTIPOLYGON = 7;
42
    
43
    public OracleFetchFeatureTypeOperation(
44
            JDBCHelper helper
45
        ) {
46
        super(helper);
47
    }
48

    
49
    private GeometryType getGT(
50
            GeometryManager manager, 
51
            int type, 
52
            int subtype
53
        ) {
54
        try {
55
            return manager.getGeometryType(type, subtype);
56
        } catch (Exception ex) {
57
            return null;
58
        }
59
    }
60
    
61
    public OracleFetchFeatureTypeOperation(
62
            JDBCHelper helper,
63
            EditableFeatureType featureType,
64
            String dbname,
65
            String schema,
66
            String table,
67
            List<String> primaryKeys,
68
            String defaultGeometryColumn,
69
            IProjection crs
70
        ) {
71
        super(helper, featureType, dbname, schema, table, primaryKeys, defaultGeometryColumn, crs);
72
    }            
73

    
74
    @Override
75
    public void fetch(EditableFeatureType featureType, Connection conn, String dbname, String schema, String table, List<String> pks, String defaultGeometryColumn, IProjection crs) throws DataException {
76
        super.fetch(featureType, conn, dbname, schema, table, pks, defaultGeometryColumn, crs);
77
    }
78

    
79
    @Override
80
    protected int getDataTypeFromMetadata(
81
            ResultSetMetaData rsMetadata,
82
            int colIndex
83
        ) throws SQLException {
84
            int type = rsMetadata.getColumnType(colIndex);
85
            if (type>=2000 && type<=4449) {
86
                    return DataTypes.GEOMETRY;
87
            }
88
        switch (type) {
89
        case java.sql.Types.INTEGER:
90
            return DataTypes.INT;
91

    
92
        case java.sql.Types.BIGINT:
93
            return DataTypes.LONG;
94

    
95
        case java.sql.Types.REAL:
96
            return DataTypes.DOUBLE;
97

    
98
        case java.sql.Types.DOUBLE:
99
            return DataTypes.DOUBLE;
100

    
101
        case java.sql.Types.CHAR:
102
            return DataTypes.STRING;
103

    
104
        case java.sql.Types.VARCHAR:
105
        case java.sql.Types.LONGVARCHAR:
106
            return DataTypes.STRING;
107

    
108
        case java.sql.Types.FLOAT:
109
            return DataTypes.DOUBLE;
110

    
111
        case java.sql.Types.NUMERIC:
112
                if (rsMetadata.getScale(colIndex)==0) {
113
                        if (rsMetadata.getPrecision(colIndex)>9) {
114
                                return DataTypes.LONG;
115
                        }
116
                }
117
            return DataTypes.DOUBLE;
118

    
119
        case java.sql.Types.DECIMAL:
120
            return DataTypes.FLOAT;
121

    
122
        case java.sql.Types.DATE:
123
            return DataTypes.DATE;
124

    
125
        case java.sql.Types.TIME:
126
            return DataTypes.TIME;
127

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

    
131
        case java.sql.Types.BOOLEAN:
132
        case java.sql.Types.BIT:
133
            return DataTypes.BOOLEAN;
134

    
135
        case java.sql.Types.BLOB:
136
        case java.sql.Types.BINARY:
137
        case java.sql.Types.LONGVARBINARY:
138
            return DataTypes.BYTEARRAY;
139
        default:
140
            String typeName = rsMetadata.getColumnTypeName(colIndex);
141
            if( "MDSYS.SDO_GEOMETRY".equalsIgnoreCase(typeName) ) {
142
                return DataTypes.GEOMETRY;
143
            }
144
            return DataTypes.OBJECT;
145
        }
146
    }
147

    
148
        
149
    @Override
150
    protected void fetchGeometryTypeAndSRS(
151
            EditableFeatureAttributeDescriptor attr,
152
            ResultSetMetaData rsMetadata,
153
            int colIndex
154
        ) {
155
        if( attr.getType()!=DataTypes.GEOMETRY ) {
156
            return;
157
        }
158
        doFetchFromMetadata(attr, rsMetadata, colIndex);
159
    }
160
    
161
    
162
    /**
163
     * Fetches the SRID and geom type from several Oracle metadata
164
     * tables:
165
     * ALL_SDO_GEOM_METADATA, ALL_SDO_INDEX_METADATA, ALL_SDO_INDEX_INFO
166
     * 
167
     * @param attr
168
     * @param rsMetadata
169
     * @param colIndex
170
     */
171
    protected void doFetchFromMetadata(
172
            EditableFeatureAttributeDescriptor attr,
173
            ResultSetMetaData rsMetadata,
174
            int colIndex
175
        ) {
176
            
177
            int srid = -1;
178
        int dimensions = 2;
179
            try {
180
                    String sql = "SELECT SRID, "
181
                                + "( SELECT count(*) FROM TABLE(t1.diminfo) ) dimensions "
182
                                + "FROM ALL_SDO_GEOM_METADATA t1 "
183
                                + "WHERE OWNER = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?" ;
184
                               
185
                ResultSet rs = null;
186
                PreparedStatement st = null;
187
            try {
188
                    st = this.getConnection().prepareStatement(sql);
189
                    st.setString(1, this.getSchema());
190
                    st.setString(2, this.getTablename());
191
                    st.setString(3, attr.getName());
192

    
193
                rs = JDBCUtils.executeQuery(st, sql);
194
                
195
                if (rs.next()) {
196
                        srid = rs.getInt(1);
197
                        dimensions = rs.getInt(2);
198
                }
199
                    if( srid!=-1 ) {
200
                        attr.setSRS(this.helper.getProjectionFromDatabaseCode(new Integer(srid).toString()));
201
                    }
202
            } catch (Exception ex) {
203
                logger.debug("Can't get srs for column '"+attr.getName()+"'.",ex);
204
            }
205
            finally {
206
                JDBCUtils.closeQuietly(rs);
207
                JDBCUtils.closeQuietly(st);
208
            }
209
        } catch (Exception ex) {
210
            logger.debug("Can't get geometry type and srs from column '"+attr.getName()+"'.",ex);
211
        }
212
            String oracleGeomType = doFetchFromSpatialIndex(attr.getName());
213
            GeometryType gt = getGeometryTypeFromOracleName(oracleGeomType, dimensions); 
214
        attr.setGeometryType(gt);
215
    }
216
    
217
    protected GeometryType getGeometryTypeFromOracleName(String geomType, int dimensions) {
218
            String geomTypeWKT;
219
            geomType = geomType.toUpperCase();
220
            if ("POINT".equals((geomType))) {
221
                    geomTypeWKT = "POINT";
222
            }
223
            else if ("LINE".equals(geomType) || "CURVE".equals(geomType)) {
224
                    geomTypeWKT = "LINESTRING";
225
            }
226
            else if ("POLYGON".equals(geomType) || "SURFACE".equals(geomType)) {
227
                    geomTypeWKT = "POLYGON";
228
            }
229
            else if ("MULTIPOINT".equals(geomType)) {
230
                    geomTypeWKT = "MULTIPOINT";
231
            }
232
            else if ("MULTILINE".equals(geomType) || "MULTICURVE".equals(geomType)) {
233
                    geomTypeWKT = "MULTILINESTRING";
234
            }
235
            else if ("MULTIPOLYGON".equals(geomType) || "MULTISURFACE".equals(geomType)) {
236
                    geomTypeWKT = "MULTIPOLYGON";
237
            }
238
            else {
239
                    geomTypeWKT = "GEOMETRY";
240
            }
241
            if (dimensions==3) {
242
                    geomTypeWKT = geomTypeWKT + "Z";
243
            }
244
            if (dimensions==4) {
245
                    geomTypeWKT = geomTypeWKT + "ZM";
246
            }
247
            return getGeometryTypeFromDatabaseTypeName(geomTypeWKT);
248
    }
249

    
250
    /**
251
     * Fetches the geometry type from the spatial index definition.
252
     * Note that this method does not allow to distinguish XYZ geoms
253
     * from XYM geoms, so XYM is reported as XYZ.
254
     *
255
     * @param geomColumnName the name of the column containing the geometry
256
     * @return An Oracle geometry type name, or "DEFAULT" if an spatial index
257
     * is not defined for the geom
258
     */
259
    protected String doFetchFromSpatialIndex(
260
                    String geomColumnName
261
        ) {
262
        try {
263
                String sql = "SELECT SDO_LAYER_GTYPE "
264
                                + "FROM ALL_SDO_INDEX_METADATA tmd, ALL_SDO_INDEX_INFO tinfo "
265
                                + "WHERE tmd.SDO_INDEX_OWNER = tinfo.SDO_INDEX_OWNER "
266
                                + "AND tmd.SDO_INDEX_NAME = tinfo.INDEX_NAME "
267
                                + "AND TABLE_OWNER = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?" ;
268
                               
269
                ResultSet rs = null;
270
                PreparedStatement st = null;
271
                
272
            HashSet<Integer> sridList = new HashSet<Integer>();
273
            HashSet<Integer> geometryCodeList = new HashSet<Integer>();
274
            try {
275
                    st = this.getConnection().prepareStatement(sql);
276
                    st.setString(1, this.getSchema());
277
                    st.setString(2, this.getTablename());
278
                    st.setString(3, geomColumnName);
279

    
280
                rs = JDBCUtils.executeQuery(st, sql);
281
                String geomType = null;
282
                if (rs.next()) {
283
                        geomType = rs.getString(1);
284
                        return geomType;
285
                }
286
            } finally {
287
                JDBCUtils.closeQuietly(rs);
288
                JDBCUtils.closeQuietly(st);
289
            }
290
        } catch (Exception ex) {
291
            logger.debug("Can't get geometry type from column '"+geomColumnName+"'.",ex);
292
        }
293
        return "DEFAULT";
294
    }
295

    
296
    /**
297
     * Fetchs the geom and srid type by directly querying the table.
298
     * Warning: This will perform a full scan on the table, so it is an
299
     * expensive method.
300
     * 
301
     * @param attr
302
     * @param rsMetadata
303
     * @param colIndex
304
     */
305
    protected void doFetchFromTableFullScan(
306
            EditableFeatureAttributeDescriptor attr,
307
            ResultSetMetaData rsMetadata,
308
            int colIndex
309
        ) {
310
        try {
311
            JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
312
            sqlbuilder.select().distinct();
313
            
314
            sqlbuilder.select().column().value(sqlbuilder.function("SDO_GTYPE", "({0}).SDO_GTYPE", sqlbuilder.variable(attr.getName())));
315
            sqlbuilder.select().column().value(sqlbuilder.ST_SRID(sqlbuilder.variable(attr.getName())));
316
            sqlbuilder.select().from().table().schema(this.getSchema());
317
            sqlbuilder.select().from().table().name(this.getTablename());
318

    
319
            Statement st = null;
320
            ResultSet rs = null;
321
            
322
            HashSet<Integer> sridList = new HashSet<Integer>();
323
            HashSet<Integer> geometryCodeList = new HashSet<Integer>();
324
            try {
325
                st = this.getConnection().createStatement();
326
                rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
327
                while (rs.next()) {
328
                        geometryCodeList.add(rs.getInt(1));
329
                        sridList.add(rs.getInt(2));
330
                }
331
            } finally {
332
                JDBCUtils.closeQuietly(rs);
333
                JDBCUtils.closeQuietly(st);
334
            }
335
            try {
336
                    if( sridList.size()==1 ) {
337
                            Integer srsCode = sridList.iterator().next();
338
                        attr.setSRS(this.helper.getProjectionFromDatabaseCode(srsCode.toString()));
339
                    }
340
                    else if (sridList.size()>1)  {
341
                            logger.error("More than one CRS detected on the layer: "+sridList.toArray().toString()+". Some geometries will be incorrectly handled.");
342
                    }
343
            } catch (Exception ex) {
344
                logger.debug("Can't get srs from column '"+attr.getName()+"'.",ex);
345
            }
346
            if( geometryCodeList.size() == 1 ) {
347
                    Integer geomCode = geometryCodeList.iterator().next();
348
                GeometryType gt = getGeometryTypeFromDatabaseTypeNumber(geomCode);
349
                attr.setGeometryType(gt);
350
            }
351
            return;
352
        } catch (Exception ex) {
353
            logger.debug("Can't get geometry type and srs from column '"+attr.getName()+"'.",ex);
354
        }
355
        attr.setGeometryType(getGeometryTypeFromDatabaseTypeName("GEOMETRY"));
356
    }
357
    
358
    private GeometryType getGeometryTypeFromDatabaseTypeName(String typeName) {
359
        if( databaseGeometryTypes==null ) {
360
            GeometryManager manager = GeometryLocator.getGeometryManager();
361
            databaseGeometryTypes = new HashMap<>();
362
            databaseGeometryTypes.put("POINT", getGT(manager, Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2D));
363
            databaseGeometryTypes.put("POINTZ", getGT(manager, Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3D));
364
            databaseGeometryTypes.put("POINTM", getGT(manager, Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2DM));
365
            databaseGeometryTypes.put("POINTZM", getGT(manager, Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3DM));
366
            
367
            databaseGeometryTypes.put("LINESTRING", getGT(manager, Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2D));
368
            databaseGeometryTypes.put("LINESTRINGZ", getGT(manager, Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3D));
369
            databaseGeometryTypes.put("LINESTRINGM", getGT(manager, Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2DM));
370
            databaseGeometryTypes.put("LINESTRINGZM", getGT(manager, Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3DM));
371
            
372
            databaseGeometryTypes.put("POLYGON", getGT(manager, Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2D));
373
            databaseGeometryTypes.put("POLYGONZ", getGT(manager, Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3D));
374
            databaseGeometryTypes.put("POLYGONM", getGT(manager, Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2DM));
375
            databaseGeometryTypes.put("POLYGONZM", getGT(manager, Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3DM));
376

    
377
            databaseGeometryTypes.put("MULTIPOINT", getGT(manager, Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2D));
378
            databaseGeometryTypes.put("MULTIPOINTZ", getGT(manager, Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3D));
379
            databaseGeometryTypes.put("MULTIPOINTM", getGT(manager, Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2DM));
380
            databaseGeometryTypes.put("MULTIPOINTZM", getGT(manager, Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3DM));
381

    
382
            databaseGeometryTypes.put("MULTILINESTRING", getGT(manager, Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2D));
383
            databaseGeometryTypes.put("MULTILINESTRINGZ", getGT(manager, Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3D));
384
            databaseGeometryTypes.put("MULTILINESTRINGM", getGT(manager, Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2DM));
385
            databaseGeometryTypes.put("MULTILINESTRINGZM", getGT(manager, Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3DM));
386

    
387
            databaseGeometryTypes.put("MULTIPOLYGON", getGT(manager, Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2D));
388
            databaseGeometryTypes.put("MULTIPOLYGONZ", getGT(manager, Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3D));
389
            databaseGeometryTypes.put("MULTIPOLYGONM", getGT(manager, Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2DM));
390
            databaseGeometryTypes.put("MULTIPOLYGONZM", getGT(manager, Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3DM));
391

    
392
            databaseGeometryTypes.put("GEOMETRY", getGT(manager, Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2D));
393
            databaseGeometryTypes.put("GEOMETRYZ", getGT(manager, Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3D));
394
            databaseGeometryTypes.put("GEOMETRYM", getGT(manager, Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2DM));
395
            databaseGeometryTypes.put("GEOMETRYZM", getGT(manager, Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3DM));
396
        }
397
        return databaseGeometryTypes.get(typeName);
398
    }
399

    
400
    private GeometryType getGeometryTypeFromDatabaseTypeNumber(int typeCode) {
401
            int dimensions = typeCode/1000;
402
            int typeCodeRemainder = typeCode - 1000*dimensions;
403
            int mDimPos = typeCodeRemainder/100;
404
            int geomType = typeCodeRemainder - 100*mDimPos;
405
            
406
            String baseType;
407
            switch(geomType) {
408
            case POINT:
409
                    baseType = "POINT";
410
                    break;
411
            case LINE_OR_CURVE:
412
                    baseType = "LINESTRING";
413
                    break;
414
            case POLYGON:
415
                    baseType = "POLYGON";
416
                    break;
417
            case MULTIPOINT:
418
                    baseType = "MULTIPOINT";
419
                    break;
420
            case MULTILINE_OR_MULTICURVE:
421
                    baseType = "MULTILINESTRING";
422
                    break;
423
            case MULTIPOLYGON:
424
                    baseType = "MULTIPOLYGON";
425
                    break;
426
            default:
427
                    baseType = "GEOMETRY";
428
                    break;
429
            }
430
                if (dimensions==3) {
431
                        if (mDimPos>0) {
432
                                return getGeometryTypeFromDatabaseTypeName(baseType+"M");
433
                        }
434
                        return getGeometryTypeFromDatabaseTypeName(baseType+"Z");
435
                }
436
                if (dimensions==4) {
437
                        return getGeometryTypeFromDatabaseTypeName(baseType+"ZM");
438
                        
439
                }
440
                return getGeometryTypeFromDatabaseTypeName(baseType);
441

    
442
    }
443

    
444
}