Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / operations / FetchFeatureTypeOperation.java @ 44678

History | View | Annotate | Download (15.4 KB)

1 43020 jjdelcerro
package org.gvsig.fmap.dal.store.jdbc2.spi.operations;
2
3
import java.sql.Connection;
4
import java.sql.DatabaseMetaData;
5
import java.sql.ResultSet;
6
import java.sql.ResultSetMetaData;
7
import java.sql.SQLException;
8
import java.sql.Statement;
9
import java.util.ArrayList;
10
import java.util.List;
11
import org.apache.commons.collections.CollectionUtils;
12
import org.apache.commons.lang3.StringUtils;
13
import org.cresques.cts.IProjection;
14 44198 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionBuilder;
15 43020 jjdelcerro
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.spi.JDBCSQLBuilderBase;
20
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
21
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
22 44058 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
23 43020 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
24
import org.gvsig.fmap.geom.GeometryLocator;
25
import org.gvsig.fmap.geom.type.GeometryType;
26 44058 jjdelcerro
import static org.gvsig.fmap.dal.store.jdbc2.spi.operations.AbstractConnectionOperation.LOGGER;
27 44678 jjdelcerro
import org.gvsig.tools.dataTypes.DataType;
28 43020 jjdelcerro
29 44253 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
30 43020 jjdelcerro
public class FetchFeatureTypeOperation extends AbstractConnectionOperation {
31
    private final EditableFeatureType featureType;
32 44376 jjdelcerro
    protected final TableReference table;
33 43020 jjdelcerro
    private final List<String> primaryKeys;
34
    private final String defaultGeometryColumn;
35
    private final IProjection crs;
36
37
    public FetchFeatureTypeOperation(
38
            JDBCHelper helper
39
        ) {
40 44058 jjdelcerro
        this(helper, null, null, null, null, null);
41 43020 jjdelcerro
    }
42
43
    public FetchFeatureTypeOperation(
44
            JDBCHelper helper,
45
            EditableFeatureType featureType,
46 43377 jjdelcerro
            String defaultGeometryColumn,
47
            IProjection crs
48
        ) {
49 44058 jjdelcerro
        this(helper, featureType, null, null, defaultGeometryColumn, crs);
50 43377 jjdelcerro
    }
51
52
    public FetchFeatureTypeOperation(
53
            JDBCHelper helper,
54
            EditableFeatureType featureType,
55 44058 jjdelcerro
            TableReference table,
56 43020 jjdelcerro
            List<String> primaryKeys,
57
            String defaultGeometryColumn,
58
            IProjection crs
59
        ) {
60
        super(helper);
61
        this.featureType = featureType;
62
        this.table = table;
63
        this.primaryKeys = primaryKeys;
64
        this.defaultGeometryColumn = defaultGeometryColumn;
65
        this.crs = crs;
66
    }
67
68
    @Override
69
    public final Object perform(Connection conn) throws DataException {
70 44678 jjdelcerro
        this.fetch(conn);
71 43020 jjdelcerro
        return true;
72
    }
73
74 44058 jjdelcerro
    protected TableReference getTable() {
75 43114 jjdelcerro
        return this.table;
76
    }
77
78 44678 jjdelcerro
    public void fetch(Connection conn) throws DataException {
79
        List<String> pks = this.primaryKeys;
80 43020 jjdelcerro
        Statement st = null;
81
        ResultSet rs = null;
82
        try {
83
            if (CollectionUtils.isEmpty(pks)) {
84 44331 jjdelcerro
                if (table.hasSubquery()) {
85
                    LOGGER.info("Searching pk in a table with a subquery ("+table.toString()+".");
86 43020 jjdelcerro
                }
87 44331 jjdelcerro
                pks = this.getPrimaryKeysFromMetadata(conn, null, table.getSchema(), table.getTable());
88
                if (CollectionUtils.isEmpty(pks)) {
89 44678 jjdelcerro
                    pks = getPrimaryKeysFromInformationSchema(conn);
90 44331 jjdelcerro
                }
91 43020 jjdelcerro
            }
92
            st = conn.createStatement();
93
            st.setFetchSize(1);
94 44678 jjdelcerro
            rs = JDBCUtils.executeQuery(st, this.getSQLToRetrieveFirstRowOfTable());
95 43020 jjdelcerro
            ResultSetMetaData rsMetadata = rs.getMetaData();
96
97 43377 jjdelcerro
            fetchFeatureTypeFromMetadata(conn, rsMetadata, pks);
98 43020 jjdelcerro
99
        } catch (SQLException ex) {
100
            throw new RuntimeException("Can't fecth feature type.",ex);
101
        } finally {
102
            JDBCUtils.closeQuietly(rs);
103
            JDBCUtils.closeQuietly(st);
104
        }
105 43377 jjdelcerro
    }
106
107 44678 jjdelcerro
    public String getSQLToRetrieveFirstRowOfTable() {
108
      JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
109
      sqlbuilder.select().column().all();
110
      sqlbuilder.select().from().table()
111
          .database(this.table.getDatabase())
112
          .schema(this.table.getSchema())
113
          .name(this.table.getTable());
114
      sqlbuilder.select().from().subquery(this.table.getSubquery());
115
      sqlbuilder.select().limit(1);
116
117
      String sql = sqlbuilder.toString();
118
      return sql;
119
    }
120
121
122 43377 jjdelcerro
    public void fetchFeatureTypeFromMetadata(Connection conn, ResultSetMetaData rsMetadata) throws SQLException {
123
        this.fetchFeatureTypeFromMetadata(conn, rsMetadata, new ArrayList<String>());
124
    }
125 43020 jjdelcerro
126 43377 jjdelcerro
    protected void fetchFeatureTypeFromMetadata(Connection conn, ResultSetMetaData rsMetadata, List<String> pks) throws SQLException {
127
        int i;
128
        int geometriesColumns = 0;
129
        String lastGeometry = null;
130
131
        EditableFeatureAttributeDescriptor attr;
132
        boolean firstGeometryAttrFound = false;
133
        for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
134
            attr = getAttributeFromMetadata(featureType, conn, rsMetadata, i);
135
            if ( isInPrimaryKeys(pks,attr) ) {
136
                attr.setIsPrimaryKey(true);
137
            }
138
            if (attr.getType() == DataTypes.GEOMETRY) {
139
                geometriesColumns++;
140
                lastGeometry = attr.getName();
141
                // Set the default geometry attribute if it is the one
142
                // given as parameter or it is the first one, just in case.
143
                if (!firstGeometryAttrFound || lastGeometry.equals(defaultGeometryColumn)) {
144
                    firstGeometryAttrFound = true;
145
                    featureType.setDefaultGeometryAttributeName(lastGeometry);
146
                }
147
            }
148
149
        }
150
        if (defaultGeometryColumn == null && geometriesColumns == 1) {
151
            featureType.setDefaultGeometryAttributeName(lastGeometry);
152
        }
153
154 43020 jjdelcerro
        if (crs != null && featureType.getDefaultGeometryAttribute() != null) {
155
            ((EditableFeatureAttributeDescriptor) featureType.getDefaultGeometryAttribute()).setSRS(crs);
156
        }
157
    }
158
159 43114 jjdelcerro
    protected boolean isInPrimaryKeys(List<String> pks, EditableFeatureAttributeDescriptor attr) {
160 43786 jjdelcerro
        if( pks == null || attr == null ) {
161
            return false;
162
        }
163 43355 jjdelcerro
        // En algunos gestores de BBDD, los nombres obtenidos de las pks de los
164
        // metadados no coinciden con los nombres de los campos ya que unos estan
165
        // en mayusculas y otros en minusculas, asi que en lugar de usar un "contains"
166
        // nos los recorremos y comparamos con IgnoreCase.
167
        for (String pk : pks) {
168
            if( StringUtils.equalsIgnoreCase(pk, attr.getName()) ) {
169
                return true;
170
            }
171
        }
172
        return false;
173 43114 jjdelcerro
    }
174
175 43020 jjdelcerro
    protected List<String> getPrimaryKeysFromMetadata(
176
            Connection conn,
177
            String catalog,
178
            String schema,
179
            String table) throws SQLException {
180
181
        ResultSet rsPrimaryKeys = null;
182
        ResultSet rs = null;
183
        try {
184
            DatabaseMetaData metadata = conn.getMetaData();
185
            rs = metadata.getTables(catalog, schema, table, null);
186
187
            if (!rs.next()) {
188
                // No tables found with default values, ignoring catalog
189
                rs.close();
190
                catalog = null;
191
                schema = null;
192
                rs = metadata.getTables(catalog, schema, table, null);
193
                if (!rs.next()) {
194
                    // table not found
195
                    return null;
196
                } else if (rs.next()) {
197
                    // More that one, cant identify
198
                    return null;
199
                }
200
201
            } else if (rs.next()) {
202
                // More that one, cant identify
203
                return null;
204
            }
205
            rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, table);
206
            List pks = new ArrayList();
207
            while (rsPrimaryKeys.next()) {
208
                pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
209
            }
210
            return pks;
211
212
        } catch (SQLException e) {
213
            return null;
214
215
        } finally {
216
            JDBCUtils.closeQuietly(rs);
217
            JDBCUtils.closeQuietly(rsPrimaryKeys);
218
        }
219
220
    }
221
222 44678 jjdelcerro
    protected List<String> getPrimaryKeysFromInformationSchema(Connection conn) throws SQLException {
223 43020 jjdelcerro
224 44678 jjdelcerro
        String sql = getSQLToRetrievePrimaryKeysFromInformationSchema();
225 44058 jjdelcerro
226
        Statement st = null;
227
        ResultSet rs = null;
228
        List<String> pks = new ArrayList();
229
        try {
230
            st = conn.createStatement();
231
            rs = JDBCUtils.executeQuery(st, sql);
232
            while (rs.next()) {
233
                pks.add(rs.getString(1));
234
            }
235
            if (pks.isEmpty()) {
236
                return null;
237
            }
238
            return pks;
239
240
        } catch (Exception ex) {
241
            return pks;
242
243
        } finally {
244
            JDBCUtils.closeQuietly(rs);
245
            JDBCUtils.closeQuietly(st);
246
        }
247
    }
248
249 44678 jjdelcerro
    public String getSQLToRetrievePrimaryKeysFromInformationSchema() throws SQLException {
250 43020 jjdelcerro
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
251 44198 jjdelcerro
        ExpressionBuilder expbuilder = sqlbuilder.expression();
252 43020 jjdelcerro
253
        sqlbuilder.select().column().name("COLUMN_NAME");
254
        sqlbuilder.select().column().name("CONSTRAINT_TYPE");
255
        sqlbuilder.select().from().custom(
256
                "INFORMATION_SCHEMA.table_constraints t_cons "
257
                + "inner join INFORMATION_SCHEMA.key_column_usage c on "
258
                + "c.constraint_catalog = t_cons.constraint_catalog and "
259
                + "c.table_schema = t_cons.table_schema and "
260
                + "c.table_name = t_cons.table_name and "
261
                + "c.constraint_name = t_cons.constraint_name "
262
        );
263
        sqlbuilder.select().where().set(
264 44198 jjdelcerro
                expbuilder.like(
265
                        expbuilder.custom("c.TABLE_NAME"),
266 44678 jjdelcerro
                        expbuilder.constant(table.getTable())
267 43020 jjdelcerro
                )
268
        );
269 44678 jjdelcerro
        if( table.hasSchema() ) {
270 43020 jjdelcerro
            sqlbuilder.select().where().and(
271 44198 jjdelcerro
                    expbuilder.like(
272
                            expbuilder.custom("c.TABLE_SCHEMA"),
273 44678 jjdelcerro
                            expbuilder.constant(table.getSchema())
274 43020 jjdelcerro
                    )
275
            );
276
        }
277 44678 jjdelcerro
//        if (catalog != null) {
278
//            sqlbuilder.select().where().and(
279
//                    expbuilder.like(
280
//                            expbuilder.custom("c.CONSTRAINT_CATALOG"),
281
//                            expbuilder.constant(catalog)
282
//                    )
283
//            );
284
//        }
285 43020 jjdelcerro
        sqlbuilder.select().where().and(
286 44198 jjdelcerro
                expbuilder.eq(
287
                        expbuilder.column("CONSTRAINT_TYPE"),
288
                        expbuilder.constant("PRIMARY KEY")
289 43020 jjdelcerro
                )
290
        );
291 44058 jjdelcerro
        return sqlbuilder.toString();
292 43020 jjdelcerro
    }
293 44058 jjdelcerro
294
295 43020 jjdelcerro
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(
296
            EditableFeatureType type,
297
            Connection conn,
298
            ResultSetMetaData rsMetadata,
299
            int colIndex
300
        ) throws SQLException {
301
302
        EditableFeatureAttributeDescriptor attr = type.add(
303
                rsMetadata.getColumnName(colIndex),
304
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
305
        );
306
        attr.setAllowNull(
307
            rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable
308
        );
309
        attr.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
310
        attr.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
311 44678 jjdelcerro
        attr.setSize(rsMetadata.getColumnDisplaySize(colIndex));
312
        attr.setScale(rsMetadata.getScale(colIndex));
313 43020 jjdelcerro
        attr.setPrecision(rsMetadata.getPrecision(colIndex));
314
        switch(attr.getType()) {
315 44678 jjdelcerro
            case DataTypes.BYTE:
316
              attr.setPrecision(DataType.BYTE_DEFAULT_PRECISION);
317
              attr.setScale(DataType.SCALE_NONE);
318
              break;
319
            case DataTypes.INT:
320
              attr.setPrecision(DataType.INT_DEFAULT_PRECISION);
321
              attr.setScale(DataType.SCALE_NONE);
322
              break;
323
            case DataTypes.LONG:
324
              attr.setPrecision(DataType.LONG_DEFAULT_PRECISION);
325
              attr.setScale(DataType.SCALE_NONE);
326
              break;
327
            case DataTypes.FLOAT:
328
              attr.setPrecision(DataType.FLOAT_DEFAULT_PRECISION);
329
              attr.setScale(DataType.FLOAT_DEFAULT_SCALE);
330
              break;
331
            case DataTypes.DOUBLE:
332
              attr.setPrecision(DataType.DOUBLE_DEFAULT_PRECISION);
333
              attr.setScale(DataType.DOUBLE_DEFAULT_SCALE);
334
              break;
335 43020 jjdelcerro
            case DataTypes.OBJECT:
336
                attr.setAdditionalInfo(
337
                        "SQLType",
338
                        rsMetadata.getColumnType(colIndex)
339
                );
340
                attr.setAdditionalInfo(
341
                        "SQLTypeName",
342
                        rsMetadata.getColumnTypeName(colIndex)
343
                );
344
                break;
345
            case DataTypes.GEOMETRY:
346 43114 jjdelcerro
                this.fetchGeometryTypeAndSRS(attr, rsMetadata, colIndex);
347 43020 jjdelcerro
                break;
348
        }
349
        return attr;
350
    }
351
352
    protected int getDataTypeFromMetadata(
353
            ResultSetMetaData rsMetadata,
354
            int colIndex
355
        ) throws SQLException {
356
357
        switch (rsMetadata.getColumnType(colIndex)) {
358 44678 jjdelcerro
            case java.sql.Types.TINYINT:
359
                return DataTypes.BYTE;
360
361 43020 jjdelcerro
            case java.sql.Types.INTEGER:
362
                return DataTypes.INT;
363
364
            case java.sql.Types.BIGINT:
365
                return DataTypes.LONG;
366
367
            case java.sql.Types.REAL:
368 44678 jjdelcerro
            case java.sql.Types.FLOAT:
369
                return DataTypes.FLOAT;
370 43020 jjdelcerro
371
            case java.sql.Types.DOUBLE:
372
                return DataTypes.DOUBLE;
373
374 44678 jjdelcerro
            case java.sql.Types.NUMERIC:
375
            case java.sql.Types.DECIMAL:
376
                return DataTypes.DECIMAL;
377
378 43020 jjdelcerro
            case java.sql.Types.CHAR:
379
            case java.sql.Types.VARCHAR:
380
            case java.sql.Types.LONGVARCHAR:
381
                return DataTypes.STRING;
382
383
            case java.sql.Types.DATE:
384
                return DataTypes.DATE;
385
386
            case java.sql.Types.TIME:
387
                return DataTypes.TIME;
388
389
            case java.sql.Types.TIMESTAMP:
390
                return DataTypes.TIMESTAMP;
391
392
            case java.sql.Types.BOOLEAN:
393
            case java.sql.Types.BIT:
394
                return DataTypes.BOOLEAN;
395
396
            case java.sql.Types.BLOB:
397
            case java.sql.Types.BINARY:
398
            case java.sql.Types.LONGVARBINARY:
399
                return DataTypes.BYTEARRAY;
400
401
            default:
402
                String typeName = rsMetadata.getColumnTypeName(colIndex);
403
                if( "geometry".equalsIgnoreCase(typeName) ) {
404
                    return DataTypes.GEOMETRY;
405
                }
406
                return DataTypes.OBJECT;
407
        }
408
    }
409
410 43114 jjdelcerro
    /**
411
     * Inicializa el tipo, subtipo y SRS del attributo de tipo geometria.
412
     *
413
     * @param attr
414
     * @param rsMetadata
415
     * @param colIndex
416
     */
417
    protected void fetchGeometryTypeAndSRS(
418
            EditableFeatureAttributeDescriptor attr,
419 43020 jjdelcerro
            ResultSetMetaData rsMetadata,
420 43114 jjdelcerro
            int colIndex
421
        ) {
422
        if( attr.getType()!=DataTypes.GEOMETRY ) {
423
            return;
424
        }
425
        try {
426
            GeometryType geomType = GeometryLocator.getGeometryManager().getGeometryType(
427
                    Geometry.TYPES.GEOMETRY,
428
                    Geometry.SUBTYPES.GEOM2D
429
            );
430
            attr.setGeometryType(geomType);
431 44253 jjdelcerro
            attr.setSRS((IProjection)null);
432 43114 jjdelcerro
        } catch (Exception ex) {
433 44058 jjdelcerro
            LOGGER.warn("Can't get default geometry type.",ex);
434 43114 jjdelcerro
        }
435 43020 jjdelcerro
    }
436 43114 jjdelcerro
437 43020 jjdelcerro
}