This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 748e998 Rename some sis-sql internal classes. Leverage
functionalities available in other SIS modules. Reduce the number of fields in
Database class.
748e998 is described below
commit 748e998b9f42e75aa929dfbea8b21f6d43e546f9
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Jul 5 16:55:14 2018 +0200
Rename some sis-sql internal classes. Leverage functionalities available in
other SIS modules. Reduce the number of fields in Database class.
---
.../apache/sis/internal/metadata/sql/Dialect.java | 3 +-
.../sis/internal/metadata/sql/SQLUtilities.java | 5 +-
.../referencing/factory/sql/EPSGDataAccess.java | 2 +-
.../feature/{ColumnMetaModel.java => Column.java} | 10 +-
.../feature/{DataBaseModel.java => Database.java} | 234 ++++++++-------------
.../apache/sis/internal/sql/feature/MetaModel.java | 97 ++++++---
.../sis/internal/sql/feature/PrimaryKey.java | 6 +-
.../sis/internal/sql/feature/QueryFeatureSet.java | 4 +-
.../{RelationMetaModel.java => Relation.java} | 15 +-
.../feature/{SchemaMetaModel.java => Schema.java} | 29 +--
.../{Dialect.java => SpatialFunctions.java} | 55 ++++-
.../feature/{TableMetaModel.java => Table.java} | 34 ++-
.../sis/internal/sql/feature/package-info.java | 3 +-
.../sis/internal/sql/postgres/PostgresDialect.java | 86 --------
.../sis/internal/sql/postgres/PostgresStore.java | 88 --------
.../sql/postgres/PostgresStoreProvider.java | 74 -------
.../java/org/apache/sis/storage/sql/SQLStore.java | 18 +-
17 files changed, 269 insertions(+), 494 deletions(-)
diff --git
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Dialect.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Dialect.java
index fb834c9..76e1236 100644
---
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Dialect.java
+++
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Dialect.java
@@ -88,9 +88,10 @@ public enum Dialect {
/**
* Returns the presumed SQL dialect.
+ * If this method can not guess the dialect, than {@link #ANSI} is
presumed.
*
* @param metadata the database metadata.
- * @return the presumed SQL dialect.
+ * @return the presumed SQL dialect (never {@code null}).
* @throws SQLException if an error occurred while querying the metadata.
*/
public static Dialect guess(final DatabaseMetaData metadata) throws
SQLException {
diff --git
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLUtilities.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLUtilities.java
index 40bef8b..107a76d 100644
---
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLUtilities.java
+++
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLUtilities.java
@@ -63,14 +63,17 @@ public final class SQLUtilities extends Static {
/**
* Converts the given string to a boolean value, or returns {@code null}
if the value is unrecognized.
* This method recognizes "true", "false", "yes", "no", "t", "f", 0 and 1
(case insensitive).
+ * An empty string is interpreted as {@code null}.
*
* @param text the characters to convert to a boolean value, or {@code
null}.
* @return the given characters as a boolean value, or {@code null} if the
given text was null or empty.
* @throws SQLDataException if the given text is non-null and non-empty
but not recognized.
*
+ * @see Boolean#parseBoolean(String)
+ *
* @since 0.8
*/
- public static Boolean toBoolean(final String text) throws SQLException {
+ public static Boolean parseBoolean(final String text) throws SQLException {
if (text == null) {
return null;
}
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index f909d98..d3d465c 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -2549,7 +2549,7 @@ next: while (r.next()) {
b = r.getBoolean(1);
if (r.wasNull()) b = null;
} else {
- b = SQLUtilities.toBoolean(r.getString(1)); //
May throw SQLException - see above comment.
+ b = SQLUtilities.parseBoolean(r.getString(1)); //
May throw SQLException - see above comment.
}
if (b != null) {
isReversible = b ? SignReversalComment.OPPOSITE :
SignReversalComment.SAME;
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/ColumnMetaModel.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Column.java
similarity index 94%
rename from
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/ColumnMetaModel.java
rename to
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Column.java
index 0d11928..85afb3a 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/ColumnMetaModel.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Column.java
@@ -36,7 +36,7 @@ import org.apache.sis.internal.metadata.sql.SQLBuilder;
* @since 1.0
* @module
*/
-public final class ColumnMetaModel {
+final class Column {
/**
* Description of the attribute telling whether a field is unique in the
database.
*/
@@ -47,9 +47,9 @@ public final class ColumnMetaModel {
/**
* Property information, if the field is a relation.
*/
- static final AttributeType<RelationMetaModel> JDBC_PROPERTY_RELATION = new
DefaultAttributeType<>(
+ static final AttributeType<Relation> JDBC_PROPERTY_RELATION = new
DefaultAttributeType<>(
Collections.singletonMap(DefaultAttributeType.NAME_KEY,
"relation"),
- RelationMetaModel.class, 1, 1, null);
+ Relation.class, 1, 1, null);
/**
* Whether values in a column are generated by the database, computed from
a sequence of supplied.
@@ -123,7 +123,7 @@ public final class ColumnMetaModel {
* @param type if the column is a primary key, specify how the
value is generated.
* @param sequenceName if the column is a primary key, optional sequence
name.
*/
- ColumnMetaModel(final String schema, final String table, final String name,
+ Column(final String schema, final String table, final String name,
final int sqlType, final String sqlTypeName, final Class<?> clazz,
final Type type, final String sequenceName)
{
@@ -146,7 +146,7 @@ public final class ColumnMetaModel {
* @throws SQLException if a JDBC error occurred while executing a
statement.
* @throws DataStoreException if another error occurred while fetching the
next value.
*/
- public Object nextValue(final Dialect dialect, final Connection cx) throws
SQLException, DataStoreException {
+ public Object nextValue(final SpatialFunctions dialect, final Connection
cx) throws SQLException, DataStoreException {
Object next = null;
if (type == Type.AUTO || type == Type.SEQUENCED) {
// Delegate to the database for next value.
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/DataBaseModel.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Database.java
similarity index 70%
rename from
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/DataBaseModel.java
rename to
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Database.java
index d20f49d..bfdd113 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/DataBaseModel.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Database.java
@@ -41,18 +41,18 @@ import org.apache.sis.feature.builder.AttributeRole;
import org.apache.sis.feature.builder.AttributeTypeBuilder;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
import org.apache.sis.feature.builder.PropertyTypeBuilder;
+import org.apache.sis.internal.metadata.sql.SQLUtilities;
import org.apache.sis.internal.metadata.sql.Reflection;
import org.apache.sis.internal.feature.Geometries;
import org.apache.sis.storage.sql.SQLStore;
-import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.FeatureNaming;
+import org.apache.sis.storage.IllegalNameException;
import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.logging.WarningListeners;
/**
- * Represent the structure of the database.
+ * Represent the structure of features in the database.
* The work done here is similar to reverse engineering.
*
* @author Johann Sorel (Geomatys)
@@ -60,12 +60,13 @@ import org.apache.sis.util.logging.WarningListeners;
* @since 1.0
* @module
*/
-public final class DataBaseModel {
-
- private static final String TYPE_TABLE = "TABLE";
- private static final String TYPE_VIEW = "VIEW";
- private static final String VALUE_YES = "YES";
- private static final String VALUE_NO = "NO";
+public final class Database {
+ /**
+ * Possible value for the {@value Reflection#TABLE_TYPE} column in the
{@link ResultSet}
+ * returned by {@link DatabaseMetaData#getTables(String, String, String,
String[])}.
+ * Also a possible value for the last argument of above-cited method.
+ */
+ private static final String TABLE = "TABLE", VIEW = "VIEW";
/**
* Feature type used to mark types which are sub-types of others.
@@ -78,113 +79,57 @@ public final class DataBaseModel {
SUBTYPE = ftb.build();
}
- private final SQLStore store;
- private final Dialect dialect;
- private final String databaseSchema;
- private final String databaseTable;
-
- private FeatureNaming<PrimaryKey> pkIndex = new FeatureNaming<>();
- private Set<GenericName> typeNames = new HashSet<>();
- private FeatureNaming<FeatureType> typeIndex = new FeatureNaming<>();
- private Map<String,SchemaMetaModel> schemas;
- private Set<GenericName> nameCache;
-
- //various cache while analyzing model
- private DatabaseMetaData metadata;
- //this set contains schema names which are needed to rebuild relations
- private Set<String> visitedSchemas;
- private Set<String> requieredSchemas;
-
- private final WarningListeners<DataStore> listeners;
+ private final SpatialFunctions functions;
+ private final FeatureNaming<PrimaryKey> pkIndex;
+ private final FeatureNaming<FeatureType> typeIndex;
+ private final Map<String,Schema> schemas;
- public DataBaseModel(final SQLStore store, final Dialect dialect, final
String schema, final String table, final WarningListeners<DataStore> listeners)
{
+ public Database(final SQLStore store, final SpatialFunctions functions,
final String schema, final String table,
+ final List<String> addWarningsTo) throws SQLException,
IllegalNameException
+ {
if (table != null) {
ArgumentChecks.ensureNonEmpty("table", table);
}
- this.store = store;
- this.dialect = dialect;
- this.databaseSchema = schema;
- this.databaseTable = table;
- this.listeners = listeners;
+ this.functions = functions;
+ pkIndex = new FeatureNaming<>();
+ typeIndex = new FeatureNaming<>();
+ schemas = new HashMap<>();
+ analyze(store, schema, table, addWarningsTo);
}
- private Collection<SchemaMetaModel> getSchemaMetaModels() throws
SQLException, DataStoreException {
- if (schemas == null) {
- analyze();
- }
+ private Collection<Schema> getSchemaMetaModels() {
return schemas.values();
}
- private SchemaMetaModel getSchemaMetaModel(String name) throws
SQLException, DataStoreException {
- if (schemas == null) {
- analyze();
- }
+ private Schema getSchemaMetaModel(String name) {
return schemas.get(name);
}
- /**
- * Clear the model cache. A new database analyze will be made the next
time it is needed.
- */
- private synchronized void clearCache() {
- pkIndex = new FeatureNaming<>();
- typeIndex = new FeatureNaming<>();
- typeNames = new HashSet<>();
- nameCache = null;
- schemas = null;
- }
-
- private PrimaryKey getPrimaryKey(final String featureTypeName) throws
SQLException, DataStoreException {
- if (schemas == null) {
- analyze();
- }
+ private PrimaryKey getPrimaryKey(final SQLStore store, final String
featureTypeName) throws IllegalNameException {
return pkIndex.get(store, featureTypeName);
}
- private synchronized Set<GenericName> getNames() throws SQLException,
DataStoreException {
- Set<GenericName> ref = nameCache;
- if (ref == null) {
- analyze();
- final Set<GenericName> names = new HashSet<>();
- for (GenericName name : typeNames) {
- final FeatureType type = typeIndex.get(store, name.toString());
- if (SUBTYPE.isAssignableFrom(type)) continue;
- if (dialect.isTableIgnored(name.tip().toString())) continue;
- names.add(name);
- }
- ref = Collections.unmodifiableSet(names);
- nameCache = ref;
- }
- return ref;
- }
-
- public FeatureType getFeatureType(final String typeName) throws
SQLException, DataStoreException {
- if (schemas == null) {
- analyze();
- }
+ public FeatureType getFeatureType(final SQLStore store, final String
typeName) throws IllegalNameException {
return typeIndex.get(store, typeName);
}
/**
* Explores all tables and views then recreate a complex feature model
from relations.
*/
- private synchronized void analyze() throws SQLException,
DataStoreException {
- if (schemas != null) {
- return; // Already analyzed
- }
- clearCache();
- schemas = new HashMap<>();
- visitedSchemas = new HashSet<>();
- requieredSchemas = new HashSet<>();
-
+ private synchronized void analyze(final SQLStore store, final String
schemaName, final String tableName, final List<String> addWarningsTo)
+ throws SQLException, IllegalNameException
+ {
try (Connection cx = store.getDataSource().getConnection()) {
- metadata = cx.getMetaData();
+ final DatabaseMetaData metadata = cx.getMetaData();
+ final Set<String> requieredSchemas = new HashSet<>();
+ final Set<String> visitedSchemas = new HashSet<>();
/*
* Schema names available in the database:
* 1. TABLE_SCHEM : String => schema name
* 2. TABLE_CATALOG : String => catalog name (may be null)
*/
- if (databaseSchema != null) {
- requieredSchemas.add(databaseSchema);
+ if (schemaName != null) {
+ requieredSchemas.add(schemaName);
} else try (ResultSet reflect = metadata.getSchemas()) {
while (reflect.next()) {
requieredSchemas.add(reflect.getString(Reflection.TABLE_SCHEM)); //
TODO: use schemas in getTables instead.
@@ -198,41 +143,35 @@ public final class DataBaseModel {
visitedSchemas.add(sn);
requieredSchemas.remove(sn);
// TODO: escape with metadata.getSearchStringEscape().
- final SchemaMetaModel schema = analyzeSchema(sn,
databaseTable);
+ final Schema schema = analyzeSchema(metadata, sn, tableName,
requieredSchemas, visitedSchemas, addWarningsTo);
schemas.put(schema.name, schema);
}
- reverseSimpleFeatureTypes();
- } finally {
- metadata = null;
- visitedSchemas = null;
- requieredSchemas = null;
+ reverseSimpleFeatureTypes(metadata);
}
/*
* Build indexes.
*/
- final String baseSchemaName = databaseSchema;
- final Collection<SchemaMetaModel> candidates;
- if (baseSchemaName == null) {
+ final Collection<Schema> candidates;
+ if (schemaName == null) {
candidates = getSchemaMetaModels(); // Take all
schemas.
} else {
- candidates =
Collections.singleton(getSchemaMetaModel(baseSchemaName));
+ candidates = Collections.singleton(getSchemaMetaModel(schemaName));
}
- for (SchemaMetaModel schema : candidates) {
+ for (Schema schema : candidates) {
if (schema != null) {
- for (TableMetaModel table : schema.getTables()) {
+ for (Table table : schema.getTables()) {
- final FeatureTypeBuilder ft =
table.getType(TableMetaModel.View.SIMPLE_FEATURE_TYPE);
+ final FeatureTypeBuilder ft =
table.getType(Table.View.SIMPLE_FEATURE_TYPE);
final GenericName name = ft.getName();
pkIndex.add(store, name, table.key);
if (table.isSubType()) {
// We don't show subtype, they are part of other
feature types, add a flag to identify then
ft.setSuperTypes(SUBTYPE);
}
- typeNames.add(name);
typeIndex.add(store, name, ft.build());
}
} else {
- throw new DataStoreException("Specifed schema " +
baseSchemaName + " does not exist.");
+ throw new SQLException("Specifed schema " + schemaName + "
does not exist.");
}
}
}
@@ -240,41 +179,47 @@ public final class DataBaseModel {
/**
* @param schemaPattern schema name with "%" and "_" interpreted as
wildcards, or {@code null} for all schemas.
*/
- private SchemaMetaModel analyzeSchema(final String schemaPattern, final
String tableNamePattern) throws SQLException, DataStoreException {
- final SchemaMetaModel schema = new SchemaMetaModel(schemaPattern);
+ private Schema analyzeSchema(final DatabaseMetaData metadata, final String
schemaPattern, final String tableNamePattern,
+ final Set<String> requieredSchemas, final Set<String>
visitedSchemas, final List<String> addWarningsTo)
+ throws SQLException, IllegalNameException
+ {
+ final Schema schema = new Schema(schemaPattern);
/*
* Description of the tables available:
* 1. TABLE_SCHEM : String => table schema (may be null)
* 2. TABLE_NAME : String => table name
* 3. TABLE_TYPE : String => table type (typically "TABLE" or
"VIEW").
*/
- try (ResultSet reflect = metadata.getTables(null, schemaPattern,
tableNamePattern, new String[] {TYPE_TABLE, TYPE_VIEW})) { // TODO: use
metadata.getTableTypes()
+ try (ResultSet reflect = metadata.getTables(null, schemaPattern,
tableNamePattern, new String[] {TABLE, VIEW})) { // TODO: use
metadata.getTableTypes()
while (reflect.next()) {
- final TableMetaModel table = analyzeTable(reflect);
+ final Table table = analyzeTable(metadata, reflect,
requieredSchemas, visitedSchemas, addWarningsTo);
schema.tables.put(table.name, table);
}
}
return schema;
}
- private TableMetaModel analyzeTable(final ResultSet tableSet) throws
SQLException, DataStoreException {
+ private Table analyzeTable(final DatabaseMetaData metadata, final
ResultSet tableSet,
+ final Set<String> requieredSchemas, final Set<String>
visitedSchemas, final List<String> addWarningsTo)
+ throws SQLException, IllegalNameException
+ {
final String schemaName = tableSet.getString(Reflection.TABLE_SCHEM);
final String tableName = tableSet.getString(Reflection.TABLE_NAME);
final String tableType = tableSet.getString(Reflection.TABLE_TYPE);
- final TableMetaModel table = new TableMetaModel(tableName, tableType);
+ final Table table = new Table(tableName, tableType);
final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
/*
* Explore all columns.
*/
try (ResultSet reflect = metadata.getColumns(null, schemaName,
tableName, null)) {
while (reflect.next()) {
- analyzeColumn(reflect, ftb.addAttribute(Object.class));
+ analyzeColumn(metadata, reflect,
ftb.addAttribute(Object.class));
}
}
/*
* Find primary keys.
*/
- final List<ColumnMetaModel> cols = new ArrayList<>();
+ final List<Column> cols = new ArrayList<>();
try (ResultSet rp = metadata.getPrimaryKeys(null, schemaName,
tableName)) {
while (rp.next()) {
final String columnNamePattern =
rp.getString(Reflection.COLUMN_NAME);
@@ -283,24 +228,24 @@ public final class DataBaseModel {
while (reflect.next()) {
// Should loop exactly once.
final int sqlType =
reflect.getInt(Reflection.DATA_TYPE);
final String sqlTypeName =
reflect.getString(Reflection.TYPE_NAME);
- Class<?> columnType = dialect.getJavaType(sqlType,
sqlTypeName);
+ Class<?> columnType = functions.getJavaType(sqlType,
sqlTypeName);
if (columnType == null) {
- listeners.warning("No class for SQL type " +
sqlType, null);
+ addWarningsTo.add("No class for SQL type " +
sqlType);
columnType = Object.class;
}
- ColumnMetaModel col;
- final String str =
reflect.getString(Reflection.IS_AUTOINCREMENT);
- if (VALUE_YES.equalsIgnoreCase(str)) {
- col = new ColumnMetaModel(schemaName, tableName,
columnNamePattern, sqlType, sqlTypeName, columnType, ColumnMetaModel.Type.AUTO,
null);
+ Column col;
+ final Boolean b =
SQLUtilities.parseBoolean(reflect.getString(Reflection.IS_AUTOINCREMENT));
+ if (b != null && b) {
+ col = new Column(schemaName, tableName,
columnNamePattern, sqlType, sqlTypeName, columnType, Column.Type.AUTO, null);
} else {
// TODO: need to distinguish "NO" and empty string.
- final String sequenceName =
dialect.getColumnSequence(metadata.getConnection(), schemaName, tableName,
columnNamePattern);
+ final String sequenceName =
functions.getColumnSequence(metadata.getConnection(), schemaName, tableName,
columnNamePattern);
if (sequenceName != null) {
- col = new ColumnMetaModel(schemaName,
tableName, columnNamePattern, sqlType,
- sqlTypeName, columnType,
ColumnMetaModel.Type.SEQUENCED,sequenceName);
+ col = new Column(schemaName, tableName,
columnNamePattern, sqlType,
+ sqlTypeName, columnType,
Column.Type.SEQUENCED,sequenceName);
} else {
- col = new ColumnMetaModel(schemaName,
tableName, columnNamePattern, sqlType,
- sqlTypeName, columnType,
ColumnMetaModel.Type.PROVIDED, null);
+ col = new Column(schemaName, tableName,
columnNamePattern, sqlType,
+ sqlTypeName, columnType,
Column.Type.PROVIDED, null);
}
}
cols.add(col);
@@ -352,7 +297,7 @@ public final class DataBaseModel {
for (PropertyTypeBuilder desc : ftb.properties()) {
if (desc.getName().tip().toString().equals(columnName)) {
final AttributeTypeBuilder<?> atb =
(AttributeTypeBuilder) desc;
-
atb.addCharacteristic(ColumnMetaModel.JDBC_PROPERTY_UNIQUE).setDefaultValue(Boolean.TRUE);
+
atb.addCharacteristic(Column.JDBC_PROPERTY_UNIQUE).setDefaultValue(Boolean.TRUE);
}
}
}
@@ -367,9 +312,9 @@ public final class DataBaseModel {
if (names.contains(columnName)) {
final int sqlType =
reflect.getInt(Reflection.DATA_TYPE);
final String sqlTypeName =
reflect.getString(Reflection.TYPE_NAME);
- final Class<?> columnType =
dialect.getJavaType(sqlType, sqlTypeName);
- final ColumnMetaModel col = new
ColumnMetaModel(schemaName, tableName, columnName,
- sqlType, sqlTypeName, columnType,
ColumnMetaModel.Type.PROVIDED, null);
+ final Class<?> columnType =
functions.getJavaType(sqlType, sqlTypeName);
+ final Column col = new Column(schemaName, tableName,
columnName,
+ sqlType, sqlTypeName, columnType,
Column.Type.PROVIDED, null);
cols.add(col);
/*
* Set as identifier
@@ -386,8 +331,8 @@ public final class DataBaseModel {
}
}
if (cols.isEmpty()) {
- if (TYPE_TABLE.equals(tableType)) {
- listeners.warning("No primary key found for " + tableName,
null);
+ if (TABLE.equals(tableType)) {
+ addWarningsTo.add("No primary key found for " + tableName);
}
}
table.key = new PrimaryKey(tableName, cols);
@@ -395,7 +340,7 @@ public final class DataBaseModel {
* Mark primary key columns.
*/
for (PropertyTypeBuilder desc : ftb.properties()) {
- for (ColumnMetaModel col : cols) {
+ for (Column col : cols) {
if (desc.getName().tip().toString().equals(col.name)) {
final AttributeTypeBuilder<?> atb = (AttributeTypeBuilder)
desc;
atb.addRole(AttributeRole.IDENTIFIER_COMPONENT);
@@ -416,14 +361,14 @@ public final class DataBaseModel {
final String refColumnName =
reflect.getString(Reflection.PKCOLUMN_NAME);
final int deleteRule = reflect.getInt(Reflection.DELETE_RULE);
final boolean deleteCascade =
DatabaseMetaData.importedKeyCascade == deleteRule;
- final RelationMetaModel relation = new
RelationMetaModel(relationName,localColumn,
+ final Relation relation = new
Relation(relationName,localColumn,
refSchemaName, refTableName, refColumnName, true,
deleteCascade);
table.importedKeys.add(relation);
if (refSchemaName!=null &&
!visitedSchemas.contains(refSchemaName)) requieredSchemas.add(refSchemaName);
for (PropertyTypeBuilder desc : ftb.properties()) {
if (desc.getName().tip().toString().equals(localColumn)) {
final AttributeTypeBuilder<?> atb =
(AttributeTypeBuilder) desc;
-
atb.addCharacteristic(ColumnMetaModel.JDBC_PROPERTY_RELATION).setDefaultValue(relation);
+
atb.addCharacteristic(Column.JDBC_PROPERTY_RELATION).setDefaultValue(relation);
break;
}
}
@@ -442,7 +387,7 @@ public final class DataBaseModel {
final String refColumnName =
reflect.getString(Reflection.FKCOLUMN_NAME);
final int deleteRule = reflect.getInt(Reflection.DELETE_RULE);
final boolean deleteCascade =
DatabaseMetaData.importedKeyCascade == deleteRule;
- table.exportedKeys.add(new RelationMetaModel(relationName,
localColumn,
+ table.exportedKeys.add(new Relation(relationName, localColumn,
refSchemaName, refTableName, refColumnName, false,
deleteCascade));
if (refSchemaName != null &&
!visitedSchemas.contains(refSchemaName)) {
@@ -455,7 +400,7 @@ public final class DataBaseModel {
return table;
}
- private AttributeType<?> analyzeColumn(final ResultSet columnSet, final
AttributeTypeBuilder<?> atb) throws SQLException {
+ private AttributeType<?> analyzeColumn(final DatabaseMetaData metadata,
final ResultSet columnSet, final AttributeTypeBuilder<?> atb) throws
SQLException {
final String schemaName =
columnSet.getString(Reflection.TABLE_SCHEM);
final String tableName =
columnSet.getString(Reflection.TABLE_NAME);
final String columnName =
columnSet.getString(Reflection.COLUMN_NAME);
@@ -465,9 +410,10 @@ public final class DataBaseModel {
final String columnNullable =
columnSet.getString(Reflection.IS_NULLABLE);
atb.setName(columnName);
atb.setMaximalLength(columnSize);
- dialect.decodeColumnType(atb, metadata.getConnection(),
columnTypeName, columnDataType, schemaName, tableName, columnName);
+ functions.decodeColumnType(atb, metadata.getConnection(),
columnTypeName, columnDataType, schemaName, tableName, columnName);
// TODO: need to distinguish "YES" and empty string?
- atb.setMinimumOccurs(VALUE_NO.equalsIgnoreCase(columnNullable) ? 1 :
0);
+ final Boolean b = SQLUtilities.parseBoolean(columnNullable);
+ atb.setMinimumOccurs(b != null && !b ? 1 : 0);
atb.setMaximumOccurs(1);
return atb.build();
}
@@ -490,12 +436,12 @@ public final class DataBaseModel {
// Search if we already have this property
PropertyType desc = null;
- final SchemaMetaModel schema = getSchemaMetaModel(schemaName);
+ final Schema schema = getSchemaMetaModel(schemaName);
if (schema != null) {
- TableMetaModel table = schema.getTable(tableName);
+ Table table = schema.getTable(tableName);
if (table != null) {
try {
- desc =
table.getType(TableMetaModel.View.SIMPLE_FEATURE_TYPE).build().getProperty(columnName);
+ desc =
table.getType(Table.View.SIMPLE_FEATURE_TYPE).build().getProperty(columnName);
} catch (PropertyNotFoundException ex) {
// ok
}
@@ -512,7 +458,7 @@ public final class DataBaseModel {
atb.setMinimumOccurs(nullable ==
ResultSetMetaData.columnNullable ? 0 : 1);
atb.setMaximumOccurs(1);
atb.setName(columnLabel);
- atb.setValueClass(dialect.getJavaType(sqlType, sqlTypeName));
+ atb.setValueClass(functions.getJavaType(sqlType, sqlTypeName));
}
}
return ftb.build();
@@ -521,9 +467,9 @@ public final class DataBaseModel {
/**
* Rebuild simple feature types for each table.
*/
- private void reverseSimpleFeatureTypes() throws SQLException {
- for (final SchemaMetaModel schema : schemas.values()) {
- for (final TableMetaModel table : schema.getTables()) {
+ private void reverseSimpleFeatureTypes(final DatabaseMetaData metadata)
throws SQLException {
+ for (final Schema schema : schemas.values()) {
+ for (final Table table : schema.getTables()) {
final FeatureTypeBuilder ftb = new
FeatureTypeBuilder(table.tableType.build());
final String featureName = ftb.getName().tip().toString();
ftb.setName(featureName);
@@ -542,7 +488,7 @@ public final class DataBaseModel {
// TODO: escape columnNamePattern with
metadata.getSearchStringEscape().
try (ResultSet reflect = metadata.getColumns(null,
schema.name, table.name, name)) {
while (reflect.next()) { // Should loop
exactly once.
- CoordinateReferenceSystem crs =
dialect.createGeometryCRS(reflect);
+ CoordinateReferenceSystem crs =
functions.createGeometryCRS(reflect);
atb.setCRS(crs);
if (isGeometry & !defaultGeomSet) {
atb.addRole(AttributeRole.DEFAULT_GEOMETRY);
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/MetaModel.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/MetaModel.java
index 880437e..fd7975d 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/MetaModel.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/MetaModel.java
@@ -16,12 +16,18 @@
*/
package org.apache.sis.internal.sql.feature;
-import java.util.Iterator;
-import org.apache.sis.util.CharSequences;
+import java.util.Collection;
+import java.sql.DatabaseMetaData;
+import org.apache.sis.util.Debug;
+import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.util.collection.DefaultTreeTable;
/**
- * Base class of descriptions about a database entity (table or schema).
+ * Description about a database entity (schema, table, relation, <i>etc</i>).
+ * The information provided by subclasses are inferred from {@link
DatabaseMetaData}
+ * and stored as structures from the {@link org.apache.sis.feature} package.
*
* @author Johann Sorel (Geomatys)
* @version 1.0
@@ -30,50 +36,75 @@ import org.apache.sis.util.CharSequences;
*/
abstract class MetaModel {
/**
- * The schema or table name.
+ * The entity (schema, table, <i>etc</i>) name.
*/
final String name;
/**
- * Creates a new object describing a database table or a schema.
+ * Creates a new object describing a database entity (schema, table,
<i>etc</i>).
*
- * @param name the schema or table name.
+ * @param name the database entity name.
*/
MetaModel(final String name) {
this.name = name;
}
/**
- * Formats a graphical representation of the specified objects. This
representation can be
- * printed to the {@linkplain System#out standard output stream} (for
example) if it uses
- * a monospaced font and supports Unicode.
+ * Creates a tree representation of this object for debugging purpose.
+ * The default implementation adds a single node with the {@link #name} of
this entity
+ * and returns that node. Subclasses can override for appending additional
information.
*
- * @param root the root name of the tree to format, or {@code null}
if none.
- * @param objects the objects to format as root children, or {@code
null} if none.
- * @param sb where to format the tree.
+ * @param parent the parent node where to add the tree representation.
+ * @return the node added by this method.
*/
- static void appendTree(final String root, final Iterable<?> objects, final
StringBuilder sb, final String lineSeparator) {
- if (root != null) {
- sb.append(root);
- }
- if (objects != null) {
- final Iterator<?> it = objects.iterator();
- boolean hasNext;
- if (it.hasNext()) do {
- sb.append(lineSeparator);
- final Object next = it.next();
- hasNext = it.hasNext();
- sb.append(hasNext ? "├─ " : "└─ ");
+ @Debug
+ TreeTable.Node appendTo(final TreeTable.Node parent) {
+ return newChild(parent, name);
+ }
+
+ /**
+ * Add a child of the given name to the given node.
+ *
+ * @param parent the node where to add a child.
+ * @param name the name to assign to the child.
+ * @return the child node.
+ */
+ @Debug
+ private static TreeTable.Node newChild(final TreeTable.Node parent, final
String name) {
+ final TreeTable.Node child = parent.newChild();
+ child.setValue(TableColumn.NAME, name);
+ return child;
+ }
- final CharSequence[] parts =
CharSequences.splitOnEOL(String.valueOf(next));
- sb.append(parts[0]);
- for (int k=1; k < parts.length; k++) {
- sb.append(lineSeparator)
- .append(hasNext ? '│' : ' ')
- .append(" ")
- .append(parts[k]);
- }
- } while (hasNext);
+ /**
+ * Appends all children to the given parent. The children are added under
a node of the given name.
+ * If the collection of children is empty, then no node of the given
{@code name} is inserted.
+ *
+ * @param parent the node where to add children.
+ * @param name the name of a node to insert between the parent and
the children, or {@code null} if none.
+ * @param children the children to add, or an empty collection if none.
+ */
+ @Debug
+ static void appendAll(TreeTable.Node parent, final String name, final
Collection<? extends MetaModel> children) {
+ if (!children.isEmpty()) {
+ if (name != null) {
+ parent = newChild(parent, name);
+ }
+ for (final MetaModel child : children) {
+ child.appendTo(parent);
+ }
}
}
+
+ /**
+ * Formats a graphical representation of this object for debugging
purpose. This representation can
+ * be printed to the {@linkplain System#out standard output stream} (for
example) if the output device
+ * uses a monospaced font and supports Unicode.
+ */
+ @Override
+ public String toString() {
+ final DefaultTreeTable table = new DefaultTreeTable(TableColumn.NAME);
+ appendTo(table.getRoot());
+ return table.toString();
+ }
}
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/PrimaryKey.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/PrimaryKey.java
index ff2667a..a4e9139 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/PrimaryKey.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/PrimaryKey.java
@@ -36,9 +36,9 @@ import org.apache.sis.storage.DataStoreException;
final class PrimaryKey {
final String table;
- final List<ColumnMetaModel> columns;
+ final List<Column> columns;
- PrimaryKey(final String table, List<ColumnMetaModel> columns) {
+ PrimaryKey(final String table, List<Column> columns) {
this.table = table;
if (columns == null) {
columns = Collections.emptyList();
@@ -93,7 +93,7 @@ final class PrimaryKey {
* @throws SQLException if a JDBC error occurred while executing a
statement.
* @throws DataStoreException if another error occurred while fetching the
next value.
*/
- Object[] nextValues(final Dialect dialect, final Connection cx) throws
SQLException, DataStoreException {
+ Object[] nextValues(final SpatialFunctions dialect, final Connection cx)
throws SQLException, DataStoreException {
final Object[] parts = new Object[columns.size()];
for (int i=0; i<parts.length; i++) {
parts[i] = columns.get(i).nextValue(dialect, cx);
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java
index d2ce7d0..15dd6c9 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java
@@ -43,12 +43,12 @@ import org.opengis.metadata.Metadata;
*/
public final class QueryFeatureSet implements FeatureSet {
- private final DataBaseModel model;
+ private final Database model;
private final SQLStore store;
private final SQLQuery query;
private FeatureType type;
- public QueryFeatureSet(final SQLStore store, final DataBaseModel model,
final SQLQuery query) {
+ public QueryFeatureSet(final SQLStore store, final Database model, final
SQLQuery query) {
this.store = store;
this.model = model;
this.query = query;
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/RelationMetaModel.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Relation.java
similarity index 75%
rename from
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/RelationMetaModel.java
rename to
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Relation.java
index bc83e29..a395f63 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/RelationMetaModel.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Relation.java
@@ -16,8 +16,6 @@
*/
package org.apache.sis.internal.sql.feature;
-import org.apache.sis.util.ArgumentChecks;
-
/**
* Description of a relation between two tables.
@@ -27,9 +25,8 @@ import org.apache.sis.util.ArgumentChecks;
* @since 1.0
* @module
*/
-final class RelationMetaModel {
+final class Relation extends MetaModel {
- final String relationName;
final String currentColumn;
final String foreignSchema;
final String foreignTable;
@@ -37,15 +34,11 @@ final class RelationMetaModel {
final boolean isImported;
final boolean cascadeOnDelete;
- RelationMetaModel(final String relationName, final String currentColumn,
final String foreignSchema,
+ Relation(final String name, final String currentColumn, final String
foreignSchema,
final String foreignTable, final String foreignColumn,
final boolean isImported, final boolean cascadeOnDelete)
{
- ArgumentChecks.ensureNonNull("relationName", relationName);
- ArgumentChecks.ensureNonNull("currentColumn", currentColumn);
- ArgumentChecks.ensureNonNull("foreignTable", foreignTable);
- ArgumentChecks.ensureNonNull("foreignColumn", foreignColumn);
- this.relationName = relationName;
+ super(name);
this.currentColumn = currentColumn;
this.foreignSchema = foreignSchema;
this.foreignTable = foreignTable;
@@ -57,7 +50,7 @@ final class RelationMetaModel {
@Override
public String toString() {
return new StringBuilder(currentColumn)
- .append((isImported) ? " → " : " ← ")
+ .append(isImported ? " → " : " ← ")
.append(foreignSchema).append('.')
.append(foreignTable).append('.').append(foreignColumn)
.toString();
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/SchemaMetaModel.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Schema.java
similarity index 71%
rename from
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/SchemaMetaModel.java
rename to
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Schema.java
index 21b4a60..0d0d7a2 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/SchemaMetaModel.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Schema.java
@@ -16,9 +16,11 @@
*/
package org.apache.sis.internal.sql.feature;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
+import java.util.HashMap;
+import java.util.Collection;
+import org.apache.sis.util.Debug;
+import org.apache.sis.util.collection.TreeTable;
/**
@@ -29,17 +31,17 @@ import java.util.Map;
* @since 1.0
* @module
*/
-final class SchemaMetaModel extends MetaModel {
+final class Schema extends MetaModel {
/**
* The tables in the schema.
*/
- final Map<String,TableMetaModel> tables;
+ final Map<String,Table> tables;
/**
* Creates a new schema of the given name.
* It is caller responsibility to populate the {@link #tables} map.
*/
- SchemaMetaModel(final String name) {
+ Schema(final String name) {
super(name);
tables = new HashMap<>();
}
@@ -47,24 +49,27 @@ final class SchemaMetaModel extends MetaModel {
/**
* Returns all tables in this schema.
*/
- Collection<TableMetaModel> getTables() {
+ Collection<Table> getTables() {
return tables.values();
}
/**
* Returns the table of the given name, or {@code null} if none.
*/
- TableMetaModel getTable(final String name){
+ Table getTable(final String name){
return tables.get(name);
}
/**
- * Returns a string representation of this schema for debugging purposes.
+ * Creates a tree representation of this object for debugging purpose.
+ *
+ * @param parent the parent node where to add the tree representation.
*/
+ @Debug
@Override
- public String toString() {
- final StringBuilder sb = new StringBuilder(100);
- appendTree(name, getTables(), sb, System.lineSeparator());
- return sb.toString();
+ TreeTable.Node appendTo(final TreeTable.Node parent) {
+ final TreeTable.Node node = super.appendTo(parent);
+ appendAll(parent, null, getTables());
+ return node;
}
}
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Dialect.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java
similarity index 68%
rename from
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Dialect.java
rename to
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java
index 102886a..e53966b 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Dialect.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java
@@ -16,39 +16,74 @@
*/
package org.apache.sis.internal.sql.feature;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Locale;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.feature.builder.AttributeTypeBuilder;
+import org.apache.sis.internal.metadata.sql.Dialect;
import org.apache.sis.storage.DataStoreException;
/**
- * Description or handling of syntax elements specific to a database.
- * The dialect provides descriptions and methods implementing the different
- * functionalities required by the data store to generate SQL statements.
+ * Access to functions provided by geospatial databases.
+ * Those functions may depend on the actual database product (PostGIS, etc).
*
* @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
* @version 1.0
* @since 1.0
* @module
*/
-public abstract class Dialect {
+abstract class SpatialFunctions {
/**
- * For subclass constructors.
+ * The tables to be ignored when inspecting the tables in a database
schema.
+ * Those tables are used for database (e.g. PostGIS) internal working.
*/
- protected Dialect() {
+ private final Set<String> ignoredTables;
+
+ /**
+ * Creates a new accessor to geospatial functions for the database
described by given metadata.
+ */
+ SpatialFunctions(final DatabaseMetaData metadata) throws SQLException {
+ ignoredTables = new HashSet<>(4);
+ /*
+ * 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 crs = "SPATIAL_REF_SYS";
+ String geom = "GEOMETRY_COLUMNS";
+ if (metadata.storesLowerCaseIdentifiers()) {
+ crs = crs .toLowerCase(Locale.US).intern();
+ geom = geom.toLowerCase(Locale.US).intern();
+ }
+ ignoredTables.add(crs);
+ ignoredTables.add(geom);
+ final Dialect dialect = Dialect.guess(metadata);
+ if (dialect == Dialect.POSTGRESQL) {
+ ignoredTables.add("geography_columns"); // Postgis 1+
+ ignoredTables.add("raster_columns"); // Postgis 2
+ ignoredTables.add("raster_overviews");
+ }
}
/**
- * Indicates whether a table will be used as a {@code FeatureType}.
+ * Indicates whether a table is reserved for the database internal working.
+ * If this method returns {@code false}, then the given table is a
candidate
+ * for use as a {@code FeatureType}.
*
- * @param name database table name.
+ * @param name database table name to test.
* @return {@code true} if the named table should be ignored when looking
for feature types.
*/
- public abstract boolean isTableIgnored(String name);
+ final boolean isIgnoredTable(final String name) {
+ return ignoredTables.contains(name);
+ }
/**
* Gets the Java class mapped to a given SQL type.
@@ -70,7 +105,7 @@ public abstract class Dialect {
* @throws SQLException if a JDBC error occurred while executing a
statement.
* @throws DataStoreException if another error occurred while fetching the
next value.
*/
- public abstract Object nextValue(ColumnMetaModel column, Connection cx)
throws SQLException, DataStoreException;
+ public abstract Object nextValue(Column column, Connection cx) throws
SQLException, DataStoreException;
/**
* Gets the value sequence name used by a column.
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/TableMetaModel.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Table.java
similarity index 72%
rename from
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/TableMetaModel.java
rename to
storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Table.java
index efb4239..ecdf264 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/TableMetaModel.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/Table.java
@@ -18,6 +18,8 @@ package org.apache.sis.internal.sql.feature;
import java.util.ArrayList;
import java.util.Collection;
+import org.apache.sis.util.Debug;
+import org.apache.sis.util.collection.TreeTable;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
@@ -29,7 +31,7 @@ import org.apache.sis.feature.builder.FeatureTypeBuilder;
* @since 1.0
* @module
*/
-final class TableMetaModel extends MetaModel {
+final class Table extends MetaModel {
enum View {
TABLE,
SIMPLE_FEATURE_TYPE,
@@ -49,19 +51,19 @@ final class TableMetaModel extends MetaModel {
/**
* those are 0:1 relations
*/
- final Collection<RelationMetaModel> importedKeys = new ArrayList<>();
+ final Collection<Relation> importedKeys = new ArrayList<>();
/**
* those are 0:N relations
*/
- final Collection<RelationMetaModel> exportedKeys = new ArrayList<>();
+ final Collection<Relation> exportedKeys = new ArrayList<>();
/**
* inherited tables
*/
final Collection<String> parents = new ArrayList<>();
- TableMetaModel(final String name, final String type) {
+ Table(final String name, final String type) {
super(name);
this.type = type;
}
@@ -78,7 +80,7 @@ final class TableMetaModel extends MetaModel {
* @todo a subtype of what?
*/
boolean isSubType() {
- for (RelationMetaModel relation : importedKeys) {
+ for (Relation relation : importedKeys) {
if (relation.cascadeOnDelete) {
return true;
}
@@ -97,20 +99,16 @@ final class TableMetaModel extends MetaModel {
}
/**
- * Returns a string representation of this schema for debugging purposes.
+ * Creates a tree representation of this object for debugging purpose.
+ *
+ * @param parent the parent node where to add the tree representation.
*/
+ @Debug
@Override
- public String toString() {
- final String lineSeparator = System.lineSeparator();
- final StringBuilder sb = new StringBuilder(100).append(name);
- if (!importedKeys.isEmpty()) {
- appendTree(" Imported Keys", importedKeys,
sb.append(lineSeparator), lineSeparator);
- sb.append(lineSeparator);
- }
- if (!exportedKeys.isEmpty()) {
- appendTree(" Exported Keys", exportedKeys,
sb.append(lineSeparator), lineSeparator);
- sb.append(lineSeparator);
- }
- return sb.toString();
+ TreeTable.Node appendTo(final TreeTable.Node parent) {
+ final TreeTable.Node node = super.appendTo(parent);
+ appendAll(parent, "Imported Keys", importedKeys);
+ appendAll(parent, "Exported Keys", exportedKeys);
+ return node;
}
}
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/package-info.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/package-info.java
index 4b8369b..80a2211 100644
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/package-info.java
+++
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/feature/package-info.java
@@ -17,7 +17,8 @@
/**
- * A set of helper classes for the SIS implementation of SQL data stores.
+ * Build {@link org.opengis.feature.FeatureType}s by inspection of a database
schema.
+ * The work done here is similar to reverse engineering.
*
* <STRONG>Do not use!</STRONG>
*
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresDialect.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresDialect.java
deleted file mode 100644
index f18fee2..0000000
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresDialect.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.sql.postgres;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.internal.sql.feature.ColumnMetaModel;
-import org.apache.sis.internal.sql.feature.Dialect;
-import org.apache.sis.feature.builder.AttributeTypeBuilder;
-import org.apache.sis.storage.DataStoreException;
-
-
-/**
- * Implements PostgreSQL-specific functionalities.
- *
- * @author Johann Sorel (Geomatys)
- * @version 1.0
- * @since 1.0
- * @module
- */
-final class PostgresDialect extends Dialect {
-
- private static final Set<String> IGNORE_TABLES = new HashSet<>(8);
- static {
- // Postgis 1+ geometry and referencing
- IGNORE_TABLES.add("spatial_ref_sys");
- IGNORE_TABLES.add("geometry_columns");
- IGNORE_TABLES.add("geography_columns");
- // Postgis 2 raster
- IGNORE_TABLES.add("raster_columns");
- IGNORE_TABLES.add("raster_overviews");
- }
-
- @Override
- public boolean isTableIgnored(String name) {
- return IGNORE_TABLES.contains(name.toLowerCase());
- }
-
- @Override
- public Class<?> getJavaType(int sqlType, String sqlTypeName) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public Object nextValue(ColumnMetaModel column, Connection cx) throws
SQLException, DataStoreException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public String getColumnSequence(Connection cx, String schemaName, String
tableName, String columnName) throws SQLException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public void decodeColumnType(AttributeTypeBuilder<?> atb, Connection cx,
String typeName, int datatype, String schemaName, String tableName, String
columnName) throws SQLException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public void decodeGeometryColumnType(AttributeTypeBuilder<?> atb,
Connection cx, ResultSet rs, int columnIndex, boolean customquery) throws
SQLException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public CoordinateReferenceSystem createGeometryCRS(ResultSet reflect)
throws SQLException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-}
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresStore.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresStore.java
deleted file mode 100644
index 5174621..0000000
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresStore.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.sql.postgres;
-
-import org.opengis.metadata.Metadata;
-import org.opengis.parameter.ParameterValueGroup;
-import org.apache.sis.storage.sql.SQLStore;
-import org.apache.sis.storage.sql.SQLQuery;
-import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.event.ChangeEvent;
-import org.apache.sis.storage.event.ChangeListener;
-import org.apache.sis.internal.sql.feature.DataBaseModel;
-import org.apache.sis.internal.sql.feature.QueryFeatureSet;
-import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.StorageConnector;
-
-
-/**
- * A data store backed by a PostgreSQL database.
- *
- * @author Johann Sorel (Geomatys)
- * @version 1.0
- * @since 1.0
- * @module
- */
-final class PostgresStore extends SQLStore {
- private final PostgresDialect dialect = new PostgresDialect();
-
- private final String schema;
- private final String table;
-
- private final DataBaseModel model;
-
- public PostgresStore(final PostgresStoreProvider provider, final
StorageConnector connector,
- final String schema, final String table) throws DataStoreException
- {
- super(provider, connector);
- this.schema = schema;
- this.table = table;
- this.model = new DataBaseModel(this, dialect, schema, table,
listeners);
- }
-
- @Override
- public ParameterValueGroup getOpenParameters() {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public Metadata getMetadata() throws DataStoreException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- /**
- * Executes a query directly on the database.
- *
- * @param query the query to execute (can not be null).
- * @return the features obtained by the given given query.
- */
- public FeatureSet query(SQLQuery query) {
- return new QueryFeatureSet(this, model, query);
- }
-
- @Override
- public void close() throws DataStoreException {
- }
-
- @Override
- public <T extends ChangeEvent> void addListener(ChangeListener<? super T>
listener, Class<T> eventType) {
- }
-
- @Override
- public <T extends ChangeEvent> void removeListener(ChangeListener<? super
T> listener, Class<T> eventType) {
- }
-}
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresStoreProvider.java
b/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresStoreProvider.java
deleted file mode 100644
index d88e644..0000000
---
a/storage/sis-sql/src/main/java/org/apache/sis/internal/sql/postgres/PostgresStoreProvider.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.sql.postgres;
-
-import org.apache.sis.storage.sql.SQLStoreProvider;
-import org.apache.sis.storage.DataStore;
-import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.ProbeResult;
-import org.apache.sis.storage.StorageConnector;
-import org.opengis.parameter.ParameterDescriptorGroup;
-
-
-/**
- * The provider of {@link PostgresStore}.
- *
- * @author Johann Sorel (Geomatys)
- * @version 1.0
- * @since 1.0
- * @module
- *
- * @todo We should not have specialized data store provider for PostgreSQL.
- * Instead we should detect from the data source or the connection.
- */
-final class PostgresStoreProvider extends SQLStoreProvider {
- /**
- * Name of the data store.
- */
- private static final String NAME = "PostgreSQL";
-
- /**
- * Creates a new provider.
- */
- public PostgresStoreProvider() {
- }
-
- /**
- * Returns a short name for the data store, which is {@value #NAME}.
- *
- * @return {@value #NAME}.
- */
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public ParameterDescriptorGroup getOpenParameters() {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public ProbeResult probeContent(StorageConnector connector) throws
DataStoreException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public DataStore open(StorageConnector connector) throws
DataStoreException {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-}
diff --git
a/storage/sis-sql/src/main/java/org/apache/sis/storage/sql/SQLStore.java
b/storage/sis-sql/src/main/java/org/apache/sis/storage/sql/SQLStore.java
index 991c4b1..9eaaae7 100644
--- a/storage/sis-sql/src/main/java/org/apache/sis/storage/sql/SQLStore.java
+++ b/storage/sis-sql/src/main/java/org/apache/sis/storage/sql/SQLStore.java
@@ -17,6 +17,8 @@
package org.apache.sis.storage.sql;
import javax.sql.DataSource;
+import org.apache.sis.internal.sql.feature.Database;
+import org.apache.sis.internal.sql.feature.QueryFeatureSet;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.FeatureSet;
@@ -24,7 +26,8 @@ import org.apache.sis.storage.StorageConnector;
/**
- * A data store capable to read and create features from a database.
+ * A data store capable to read and create features from a spatial database.
+ * An example of spatial database is PostGIS.
*
* <div class="warning">This is an experimental class,
* not yet target for any Apache SIS release at this time.</div>
@@ -41,9 +44,14 @@ public abstract class SQLStore extends DataStore {
private final DataSource source;
/**
+ * The result of inspecting database schema for deriving {@link
org.opengis.feature.FeatureType}s.
+ * Created when first needed. May be discarded and recreated if the store
needs a refresh.
+ */
+ private Database model;
+
+ /**
* Creates a new instance for the given storage.
- * The {@code provider} argument is an optional information.
- * The {@code connector} argument is mandatory.
+ * The given {@code connector} shall contain a {@link DataSource}.
*
* @param provider the factory that created this {@code DataStore}
instance, or {@code null} if unspecified.
* @param connector information about the storage (JDBC data source,
<i>etc</i>).
@@ -69,5 +77,7 @@ public abstract class SQLStore extends DataStore {
* @param query the query to execute (can not be null).
* @return the features obtained by the given given query.
*/
- public abstract FeatureSet query(SQLQuery query);
+ public FeatureSet query(final SQLQuery query) {
+ return new QueryFeatureSet(this, model, query);
+ }
}