Search in sources :

Example 1 with ResourceDefinition

use of org.apache.sis.storage.sql.ResourceDefinition in project sis by apache.

the class PostgresTest method testSpatialFeatures.

/**
 * Tests reading and writing features and rasters.
 *
 * @throws Exception if an error occurred while testing the database.
 */
@Test
public void testSpatialFeatures() throws Exception {
    try (TestDatabase database = TestDatabase.createOnPostgreSQL(SQLStoreTest.SCHEMA, true)) {
        database.executeSQL(PostgresTest.class, "file:SpatialFeatures.sql");
        final StorageConnector connector = new StorageConnector(database.source);
        connector.setOption(OptionKey.GEOMETRY_LIBRARY, GeometryLibrary.JTS);
        final ResourceDefinition table = ResourceDefinition.table(null, SQLStoreTest.SCHEMA, "SpatialData");
        try (SQLStore store = new SQLStore(new SQLStoreProvider(), connector, table)) {
            /*
                 * Invoke the private `model()` method. We have to use reflection because the class
                 * is not in the same package and we do not want to expose the method in public API.
                 */
            final Method modelAccessor = SQLStore.class.getDeclaredMethod("model");
            modelAccessor.setAccessible(true);
            final Postgres<?> pg = (Postgres<?>) modelAccessor.invoke(store);
            try (Connection connection = database.source.getConnection();
                ExtendedInfo info = new ExtendedInfo(pg, connection)) {
                testInfoStatements(info);
                testGeometryGetter(info, connection);
                testRasterReader(TestRaster.USHORT, info, connection);
            }
            /*
                 * Tests through public API.
                 */
            final FeatureSet resource = store.findResource("SpatialData");
            try (Stream<AbstractFeature> features = resource.features(false)) {
                features.forEach(PostgresTest::validate);
            }
            final Envelope envelope = resource.getEnvelope().get();
            assertEquals(envelope.getMinimum(0), -72, 1);
            assertEquals(envelope.getMaximum(1), 43, 1);
        }
    }
}
Also used : StorageConnector(org.apache.sis.storage.StorageConnector) SQLStore(org.apache.sis.storage.sql.SQLStore) SQLStoreProvider(org.apache.sis.storage.sql.SQLStoreProvider) TestDatabase(org.apache.sis.test.sql.TestDatabase) ResourceDefinition(org.apache.sis.storage.sql.ResourceDefinition) Connection(java.sql.Connection) AbstractFeature(org.apache.sis.feature.AbstractFeature) Method(java.lang.reflect.Method) Envelope(org.opengis.geometry.Envelope) FeatureSet(org.apache.sis.storage.FeatureSet) Test(org.junit.Test) GeometryGetterTest(org.apache.sis.internal.sql.feature.GeometryGetterTest) SQLStoreTest(org.apache.sis.storage.sql.SQLStoreTest)

Example 2 with ResourceDefinition

use of org.apache.sis.storage.sql.ResourceDefinition in project sis by apache.

the class Database method analyze.

/**
 * Creates a model about the specified tables in the database.
 * This method shall be invoked exactly once after {@code Database} construction.
 * It requires a list of tables to include in the model, but this list should not
 * include the dependencies; this method will follow foreigner keys automatically.
 *
 * <p>The table names shall be qualified names of 1, 2 or 3 components.
 * The components are {@code <catalog>.<schema pattern>.<table pattern>} where:</p>
 *
 * <ul>
 *   <li>{@code <catalog>}, if present, shall be the name of a catalog as it is stored in the database.</li>
 *   <li>{@code <schema pattern>}, if present, shall be the pattern of a schema.
 *       The pattern can use {@code '_'} and {@code '%'} wildcards characters.</li>
 *   <li>{@code <table pattern>} (mandatory) shall be the pattern of a table.
 *       The pattern can use {@code '_'} and {@code '%'} wildcards characters.</li>
 * </ul>
 *
 * @param  store       the data store for which we are creating a model. Used only in case of error.
 * @param  connection  connection to the database. Sometime the caller already has a connection at hand.
 * @param  tableNames  qualified name of the tables. Specified by users at construction time.
 * @param  queries     additional resources associated to SQL queries. Specified by users at construction time.
 * @param  customizer  user-specified modification to the features, or {@code null} if none.
 * @throws SQLException if a database error occurred while reading metadata.
 * @throws DataStoreException if a logical error occurred while analyzing the database structure.
 */
private void analyze(final SQLStore store, final Connection connection, final GenericName[] tableNames, final ResourceDefinition[] queries, final SchemaModifier customizer) throws Exception {
    final DatabaseMetaData metadata = connection.getMetaData();
    final String[] tableTypes = getTableTypes(metadata);
    /*
         * The following tables are defined by ISO 19125 / OGC Simple feature access part 2.
         * Note that the standard specified those names in upper-case letters, which is also
         * the default case specified by the SQL standard.  However some databases use lower
         * cases instead.
         */
    String tableCRS = InfoStatements.SPATIAL_REF_SYS;
    String tableGeom = InfoStatements.GEOMETRY_COLUMNS;
    if (metadata.storesLowerCaseIdentifiers()) {
        tableCRS = tableCRS.toLowerCase(Locale.US).intern();
        tableGeom = tableGeom.toLowerCase(Locale.US).intern();
    }
    final Map<String, Boolean> ignoredTables = new HashMap<>(8);
    ignoredTables.put(tableCRS, Boolean.TRUE);
    ignoredTables.put(tableGeom, Boolean.TRUE);
    addIgnoredTables(ignoredTables);
    isSpatial = hasTable(metadata, tableTypes, ignoredTables);
    /*
         * Collect the names of all tables specified by user, ignoring the tables
         * used for database internal working (for example by PostGIS).
         */
    final Analyzer analyzer = new Analyzer(this, connection, metadata, customizer);
    final Set<TableReference> declared = new LinkedHashSet<>();
    for (final GenericName tableName : tableNames) {
        final String[] names = TableReference.splitName(tableName);
        try (ResultSet reflect = metadata.getTables(names[2], names[1], names[0], tableTypes)) {
            while (reflect.next()) {
                final String table = analyzer.getUniqueString(reflect, Reflection.TABLE_NAME);
                if (ignoredTables.containsKey(table)) {
                    continue;
                }
                declared.add(new TableReference(analyzer.getUniqueString(reflect, Reflection.TABLE_CAT), analyzer.getUniqueString(reflect, Reflection.TABLE_SCHEM), table, analyzer.getUniqueString(reflect, Reflection.REMARKS)));
            }
        }
    }
    /*
         * At this point we got the list of tables requested by the user. Now create the Table objects for each
         * specified name. During this iteration, we may discover new tables to analyze because of dependencies
         * (foreigner keys).
         */
    final List<Table> tableList;
    tableList = new ArrayList<>(tableNames.length);
    for (final TableReference reference : declared) {
        // Adds only the table explicitly required by the user.
        tableList.add(analyzer.table(reference, reference.getName(analyzer), null));
    }
    /*
         * Add queries if any.
         */
    for (final ResourceDefinition resource : queries) {
        // Optional value should always be present in this context.
        tableList.add(analyzer.query(resource.getName(), resource.getQuery().get()));
    }
    /*
         * At this point we finished to create the tables explicitly requested by the user.
         * Register all tables only at this point, because other tables (dependencies) may
         * have been analyzed as a side-effect of above loop.
         */
    for (final Table table : analyzer.finish()) {
        tablesByNames.add(store, table.featureType.getName(), table);
        hasGeometry |= table.hasGeometry;
        hasRaster |= table.hasRaster;
    }
    tables = tableList.toArray(new Table[tableList.size()]);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) TreeTable(org.apache.sis.util.collection.TreeTable) HashMap(java.util.HashMap) WeakHashMap(java.util.WeakHashMap) ResourceDefinition(org.apache.sis.storage.sql.ResourceDefinition) DatabaseMetaData(java.sql.DatabaseMetaData) GenericName(org.opengis.util.GenericName) ResultSet(java.sql.ResultSet)

Aggregations

ResourceDefinition (org.apache.sis.storage.sql.ResourceDefinition)2 Method (java.lang.reflect.Method)1 Connection (java.sql.Connection)1 DatabaseMetaData (java.sql.DatabaseMetaData)1 ResultSet (java.sql.ResultSet)1 HashMap (java.util.HashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 WeakHashMap (java.util.WeakHashMap)1 AbstractFeature (org.apache.sis.feature.AbstractFeature)1 GeometryGetterTest (org.apache.sis.internal.sql.feature.GeometryGetterTest)1 FeatureSet (org.apache.sis.storage.FeatureSet)1 StorageConnector (org.apache.sis.storage.StorageConnector)1 SQLStore (org.apache.sis.storage.sql.SQLStore)1 SQLStoreProvider (org.apache.sis.storage.sql.SQLStoreProvider)1 SQLStoreTest (org.apache.sis.storage.sql.SQLStoreTest)1 TestDatabase (org.apache.sis.test.sql.TestDatabase)1 TreeTable (org.apache.sis.util.collection.TreeTable)1 Test (org.junit.Test)1 Envelope (org.opengis.geometry.Envelope)1 GenericName (org.opengis.util.GenericName)1