com.rgi.geopackage.schema.SchemaVerifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swagd Show documentation
Show all versions of swagd Show documentation
SWAGD: Software to Aggregate Geospatial Data
The newest version!
/* The MIT License (MIT)
*
* Copyright (c) 2015 Reinventing Geospatial, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.rgi.geopackage.schema;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.rgi.common.util.jdbc.ResultSetStream;
import com.rgi.geopackage.core.GeoPackageCore;
import com.rgi.geopackage.utility.DatabaseUtility;
import com.rgi.geopackage.verification.Assert;
import com.rgi.geopackage.verification.AssertionError;
import com.rgi.geopackage.verification.ColumnDefinition;
import com.rgi.geopackage.verification.ForeignKeyDefinition;
import com.rgi.geopackage.verification.Requirement;
import com.rgi.geopackage.verification.Severity;
import com.rgi.geopackage.verification.TableDefinition;
import com.rgi.geopackage.verification.UniqueDefinition;
import com.rgi.geopackage.verification.VerificationLevel;
import com.rgi.geopackage.verification.Verifier;
/**
*
* @author Jenifer Cochran
*
*/
public class SchemaVerifier extends Verifier
{
private class DataColumns
{
String tableName;
String columnName;
String constraintName;
}
private class DataColumnConstraints
{
String constraintName;
String constraintType;
String value;
Double min;
Boolean minIsInclusive;
Double max;
Boolean maxIsInclusive;
public String invalidMinMaxWithRangeType()
{
return String.format("constraint_name: %10s, constraint_type: %5s, invalid min: %.3f, invalid max: %.3f.",
this.constraintName,
this.constraintType,
this.min,
this.max);
}
}
private final boolean hasDataColumnsTable;
private final boolean hasDataColumnsConstraintsTable;
private final List dataColumnsValues;
private final List dataColumnConstraintsValues;
/**
* @param sqliteConnection
* A handle to the database connection
* @param verificationLevel
* Controls the level of verification testing performed
* @throws SQLException throws if the method {@link DatabaseUtility#tableOrViewExists(Connection, String)} throws
*/
public SchemaVerifier(final Connection sqliteConnection, final VerificationLevel verificationLevel) throws SQLException
{
super(sqliteConnection, verificationLevel);
this.hasDataColumnsTable = DatabaseUtility.tableOrViewExists(this.getSqliteConnection(), GeoPackageSchema.DataColumnsTableName);
this.hasDataColumnsConstraintsTable = DatabaseUtility.tableOrViewExists(this.getSqliteConnection(), GeoPackageSchema.DataColumnConstraintsTableName);
this.dataColumnsValues = this.getDataColumnValues();
this.dataColumnConstraintsValues = this.getDataColumnConstraintsValues();
}
/**
* Requirement 57
*
*
* A GeoPackage MAY contain a table or updateable view named
* gpkg_data_columns
. If present it SHALL be defined per
* clause 2.3.2.1.1 Table Definition, Data
* Columns Table or View Definition and gpkg_data_columns Table Definition SQL.
*
*
* @throws SQLException throws if the method verifyTable throws an SQLException
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 57",
text = "A GeoPackage MAY contain a table or updateable view named "
+ "gpkg_data_columns. If present it SHALL be defined per "
+ "clause 2.3.2.1.1 Table Definition, Data Columns Table or"
+ " View Definition and gpkg_data_columns Table Definition SQL. ")
public void Requirement57() throws AssertionError, SQLException
{
if(this.hasDataColumnsTable)
{
this.verifyTable(SchemaVerifier.DataColumnsTableDefinition);
}
}
/**
* Requirement 58
*
*
* Values of the gpkg_data_columns
table
* table_name
column value SHALL reference values in the
* gpkg_contents
table_name
column.
*
*
* @throws SQLException throws if various SQLExceptions occur
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 58",
text = "Values of the gpkg_data_columns table table_name column value "
+ "SHALL reference values in the gpkg_contents table_name column.")
public void Requirement58() throws SQLException, AssertionError
{
if(this.hasDataColumnsTable)
{
final String query = String.format("SELECT dc.table_name "
+ "FROM %s AS dc "
+ "WHERE dc.table_name NOT IN(SELECT gc.table_name "
+ "FROM %s AS gc);",
GeoPackageSchema.DataColumnsTableName,
GeoPackageCore.ContentsTableName);
try(Statement statement = this.getSqliteConnection().createStatement();
ResultSet invalidTableNamesRS = statement.executeQuery(query))
{
final List invalidTableNames = ResultSetStream.getStream(invalidTableNamesRS)
.map(resultSet -> { try
{
return resultSet.getString("table_name");
}
catch(final SQLException ex)
{
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
Assert.assertTrue(String.format("The following table_name(s) is(are) from %s and is(are) not referenced in the %s table_name: %s",
GeoPackageSchema.DataColumnsTableName,
GeoPackageCore.ContentsTableName,
invalidTableNames.stream()
.collect(Collectors.joining(", "))),
invalidTableNames.isEmpty(),
Severity.Error);
}
}
}
/**
* Requirement 59
*
*
* The column_name
column value in a gpkg_data_columns
*
table row SHALL contain the name of a column in the SQLite table
* or view identified by the table_name
column value.
*
*
* @throws SQLException throws if various SQLExceptions occur
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 59",
text = "The column_name column value in a gpkg_data_columns table row "
+ "SHALL contain the name of a column in the SQLite table or view "
+ "identified by the table_name column value. ")
public void Requirement59() throws SQLException, AssertionError
{
if(this.hasDataColumnsTable)
{
for(final DataColumns dataColumn : this.dataColumnsValues)
{
if(DatabaseUtility.tableOrViewExists(this.getSqliteConnection(), dataColumn.tableName))
{
final String query = String.format("PRAGMA table_info(%s);", dataColumn.tableName);
try(PreparedStatement statement = this.getSqliteConnection().prepareStatement(query);
ResultSet tableInfoRS = statement.executeQuery())
{
final boolean columnExists = ResultSetStream.getStream(tableInfoRS)
.anyMatch(resultSet -> { try
{
return resultSet.getString("name").equals(dataColumn.columnName);
}
catch(final SQLException ex)
{
return false;
}
});
Assert.assertTrue(String.format("The column %s does not exist in the table %s.",
dataColumn.columnName,
dataColumn.tableName),
columnExists,
Severity.Warning);
}
}
}
}
}
/**
* Requirement 60
*
*
* The constraint_name column value in a gpkg_data_columns table MAY be
* NULL. If it is not NULL, it SHALL contain a case sensitive
* constraint_name column value from the gpkg_data_column_constraints
* table.
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 60",
text = "The constraint_name column value in a gpkg_data_columns table MAY be NULL. "
+ "If it is not NULL, it SHALL contain a case sensitive constraint_name "
+ "column value from the gpkg_data_column_constraints table. ")
public void Requirement60() throws AssertionError
{
if(this.hasDataColumnsTable && this.hasDataColumnsConstraintsTable)
{
for(final DataColumnConstraints dataColumnConstraints : this.dataColumnConstraintsValues)
{
if(dataColumnConstraints.constraintName != null)
{
final boolean containsConstraint = this.dataColumnsValues.stream()
.filter(dataColumn -> dataColumn.constraintName != null)
.anyMatch(dataColumn -> dataColumn.constraintName.equals(dataColumnConstraints.constraintName));
Assert.assertTrue(String.format("The constraint_name %s in %s is not referenced in %s table in the column constraint_name.",
dataColumnConstraints.constraintName,
GeoPackageSchema.DataColumnsTableName,
GeoPackageSchema.DataColumnConstraintsTableName),
containsConstraint,
Severity.Warning);
}
}
}
}
/**
* Requirement 61
*
*
* A GeoPackage MAY contain a table or updateable view named
* gpkg_data_column_constraints. If present it SHALL be defined per clause
* 2.3.3.1.1 Table Definition, Data
* Column Constraints Table or View Definition and gpkg_data_columns Table Definition SQL.
*
*
* @throws SQLException throws if the method verifyTable throws
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 61",
text = "A GeoPackage MAY contain a table or updateable view named "
+ "gpkg_data_column_constraints. If present it SHALL be defined "
+ "per clause 2.3.3.1.1 Table Definition, Data Column Constraints "
+ "Table or View Definition and gpkg_data_columns Table Definition SQL. ")
public void Requirement61() throws AssertionError, SQLException
{
if(this.hasDataColumnsConstraintsTable)
{
this.verifyTable(SchemaVerifier.DataColumnConstraintsTableDefinition);
}
}
/**
* Requirement 62
*
*
* The gpkg_data_column_constraints
table MAY be empty. If it
* contains data, the lowercase constraint_type
column values
* SHALL be one of "range", "enum", or "glob".
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 62",
text = "The gpkg_data_column_constraints table MAY be empty. "
+ "If it contains data, the lowercase constraint_type "
+ "column values SHALL be one of \"range\", \"enum\", or "
+ "\"glob\". ")
public void Requirement62() throws AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final boolean validConstraintType = this.dataColumnConstraintsValues.stream()
.allMatch(dataColumnConstraintValue -> SchemaVerifier.validConstraintType(dataColumnConstraintValue.constraintType));
Assert.assertTrue(String.format("There is(are) value(s) in %s table constraint_type that does not match \"range\" or \"enum\" or \"glob\". The invalid value(s): %s.",
GeoPackageSchema.DataColumnConstraintsTableName,
this.dataColumnConstraintsValues.stream()
.filter(dataColumnConstraintValue -> !SchemaVerifier.validConstraintType(dataColumnConstraintValue.constraintType))
.map(value -> value.constraintType).collect(Collectors.joining(", "))),
validConstraintType,
Severity.Warning);
}
}
/**
* Requirement 63
*
*
* gpkg_data_column_constraint constraint_name values for rows with
* constraint_type values of range and glob SHALL be
* unique.
*
*
* @throws SQLException throws if various SQLExceptions occur
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 63",
text = "gpkg_data_column_constraint constraint_name values "
+ "for rows with constraint_type values of range and "
+ "glob SHALL be unique. ")
public void Requirement63() throws SQLException, AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final String query = String.format("SELECT DISTINCT constraint_name AS cs FROM %s WHERE constraint_type IN ('range', 'glob');",
GeoPackageSchema.DataColumnConstraintsTableName);
try(final Statement statement = this.getSqliteConnection().createStatement();
final ResultSet constraintNamesWithRangeOrGlobRS = statement.executeQuery(query))
{
final List constraintNamesWithRangeOrGlob = ResultSetStream.getStream(constraintNamesWithRangeOrGlobRS)
.map(resultSet -> { try
{
return resultSet.getString("constraint_name");
}
catch(final SQLException ex)
{
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
for(final String constraintName : constraintNamesWithRangeOrGlob)
{
final String query2 = String.format("SELECT count(*) FROM %s WHERE constraint_name = '?'",
GeoPackageSchema.DataColumnConstraintsTableName);
try(final PreparedStatement statement2 = this.getSqliteConnection().prepareStatement(query2))
{
statement2.setString(1, constraintName);
try(final ResultSet countConstraintNameRS = statement2.executeQuery())
{
final int count = countConstraintNameRS.getInt("count(*)");
Assert.assertTrue(String.format("There are constraint_name values in %s with a constraint_type of 'glob' or 'range' are not unique. "
+ "Non-unique constraint_name: %s",
GeoPackageSchema.DataColumnConstraintsTableName,
constraintName),
count <= 1,
Severity.Warning);
}
}
}
}
}
}
/**
* Requirement 64
*
*
* The gpkg_data_column_constraints
table MAY be empty. If it
* contains rows with constraint_type column values of "range", the
* value
column values for those rows SHALL be NULL.
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 64",
text = "The gpkg_data_column_constraints table MAY be empty. "
+ "If it contains rows with constraint_type column "
+ "values of \"range\", the value column values for "
+ "those rows SHALL be NULL. ")
public void Requirement64() throws AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final List invalidColumnConstraints = this.dataColumnConstraintsValues.stream()
.filter(dataColumnConstraint -> Type.Range.equals(dataColumnConstraint.constraintType))
.filter(dataColumnConstraint -> dataColumnConstraint.value != null)
.collect(Collectors.toList());
Assert.assertTrue(String.format("There are records in %s that have a constraint_type of \"range\" but does not have a corresponding null value for the column value. \nInvalid value(s): %s",
GeoPackageSchema.DataColumnConstraintsTableName,
invalidColumnConstraints.stream().map(columnValue -> columnValue.value).collect(Collectors.joining(", "))),
invalidColumnConstraints.isEmpty(),
Severity.Warning);
}
}
/**
* Requirement 65
*
*
* The gpkg_data_column_constraints
table MAY be empty. If it
* contains rows with constraint_type
column values of
* "range", the min
column values for those rows SHALL be NOT
* NULL and less than the max
column value which shall be NOT
* NULL.
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*
*/
@Requirement(reference = "Requirement 65",
text = "The gpkg_data_column_constraints table MAY be empty. If it contains rows with "
+ "constraint_type column values of \"range\", the min column values for those "
+ "rows SHALL be NOT NULL and less than the max column value which shall be NOT NULL.")
public void Requirement65() throws AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final List invalidConstraintValuesWithRange = this.dataColumnConstraintsValues.stream()
.filter(constraintValue -> Type.Range.equals(constraintValue.constraintType))
.filter(constraintValue -> constraintValue.min == null ||
constraintValue.max == null ||
constraintValue.min >= constraintValue.max)
.collect(Collectors.toList());
Assert.assertTrue(String.format("The following records in %s have invalid values for min, or max or both:\n%s",
GeoPackageSchema.DataColumnConstraintsTableName,
invalidConstraintValuesWithRange.stream()
.map(constraintValue -> constraintValue.invalidMinMaxWithRangeType())
.collect(Collectors.joining("\n"))),
invalidConstraintValuesWithRange.isEmpty(),
Severity.Warning);
}
}
/**
* Requirement 66
*
*
* The gpkg_data_column_constraints
table MAY be empty. If it
* contains rows with constraint_type
column values of
* "range", the minIsInclusive
and maxIsInclusive
*
column values for those rows SHALL be 0 or 1.
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 66",
text = "The gpkg_data_column_constraints table MAY be empty. If it contains "
+ "rows with constraint_type column values of \"range\", the minIsInclusive "
+ "and maxIsInclusive column values for those rows SHALL be 0 or 1. ")
public void Requirement66() throws AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final List invalidMinIsInclusives = this.dataColumnConstraintsValues.stream()
.filter(columnValue -> Type.Range.equals(columnValue.constraintType))
.filter(columnValue -> !Boolean.TRUE.equals(columnValue.minIsInclusive) &&
!Boolean.FALSE.equals(columnValue.minIsInclusive))
.collect(Collectors.toList());
final List invalidMaxIsInclusives = this.dataColumnConstraintsValues.stream()
.filter(columnValue -> Type.Range.equals(columnValue.constraintType))
.filter(columnValue -> !Boolean.TRUE.equals(columnValue.maxIsInclusive) &&
!Boolean.FALSE.equals(columnValue.maxIsInclusive))
.collect(Collectors.toList());
Assert.assertTrue(String.format("The following are violations on either the minIsInclusive or maxIsIclusive columns "
+ "in the %s table for which the values are not 0 or 1. %s. \n%s.",
GeoPackageSchema.DataColumnConstraintsTableName,
invalidMinIsInclusives.stream()
.map(record -> String.format("Invalid minIsInclusive for constraint_name: %10s.", record.constraintName))
.collect(Collectors.joining(", ")),
invalidMaxIsInclusives.stream()
.map(record -> String.format("Invalid maxIsInclusive for constraint_name: %10s.", record.constraintName))
.collect(Collectors.joining(", "))),
invalidMinIsInclusives.isEmpty() && invalidMaxIsInclusives.isEmpty(),
Severity.Warning);
}
}
/**
* Requirement 67
*
*
* The gpkg_data_column_constraints
table MAY be empty. If it
* contains rows with constraint_type
column values of "enum"
* or "glob", the min
, max
, minIsInclusive
*
and maxIsInclusive
column values for those rows
* SHALL be NULL.
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 67",
text = "The gpkg_data_column_constraints table MAY be empty. If it contains "
+ "rows with constraint_type column values of \"enum\" or \"glob\", the min,"
+ " max, minIsInclusive and maxIsInclusive column values for those rows SHALL be NULL.")
public void Requirement67() throws AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final List invalidConstraintRecords = this.getDataColumnConstraintsValues().stream()
.filter(columnValue -> Type.Enum.equals(columnValue.constraintType) ||
Type.Glob.equals(columnValue.constraintType))
.filter(columnValue -> !(columnValue.min == null &&
columnValue.max == null &&
columnValue.minIsInclusive == null &&
columnValue.maxIsInclusive == null))
.collect(Collectors.toList());
Assert.assertTrue(String.format("The following constraint_name(s) have a constraint_type of \"enum\" or \"glob\" "
+ "and do NOT have null values for min, max, minIsInclusive, and/or maxIsInclusive. "
+ "\nInvalid constraint_name(s): %s.",
invalidConstraintRecords.stream()
.map(columnValue -> columnValue.constraintName)
.collect(Collectors.joining(", "))),
invalidConstraintRecords.isEmpty(),
Severity.Warning);
}
}
/**
* Requirement 68
*
*
* The gpkg_data_column_constraints
table MAY be empty. If it
* contains rows with constraint_type
column values of "enum"
* or "glob", the value
column SHALL NOT be NULL.
*
*
* @throws AssertionError throws if the GeoPackage fails to meet this Requirement
*/
@Requirement(reference = "Requirement 68",
text = "The gpkg_data_column_constraints table MAY be empty. "
+ "If it contains rows with constraint_type column values "
+ "of \"enum\" or \"glob\", the value column SHALL NOT be NULL. ")
public void Requirement68() throws AssertionError
{
if(this.hasDataColumnsConstraintsTable)
{
final List invalidValues = this.getDataColumnConstraintsValues().stream()
.filter(columnValue -> Type.Enum.equals(columnValue.constraintType) ||
Type.Glob.equals(columnValue.constraintType))
.filter(columnValue -> columnValue.value == null)
.collect(Collectors.toList());
Assert.assertTrue(String.format("The following constraint_name(s) from the %s table have invalid values for the column value. \nInvalid value with constraint_name as: %s.",
GeoPackageSchema.DataColumnConstraintsTableName,
invalidValues.stream()
.map(columnValue -> columnValue.constraintName)
.collect(Collectors.joining(", "))),
invalidValues.isEmpty(),
Severity.Warning);
}
}
private static boolean validConstraintType(final String constraintType)
{
return Stream.of(Type.values()).anyMatch(scope -> scope.toString().equalsIgnoreCase(constraintType));
}
private List getDataColumnConstraintsValues()
{
final String query = String.format("SELECT constraint_name, constraint_type, value, min, minIsInclusive, max, maxIsInclusive FROM %s;", GeoPackageSchema.DataColumnConstraintsTableName);
try(Statement statement = this.getSqliteConnection().createStatement();
ResultSet tableNamesAndColumnsRS = statement.executeQuery(query))
{
return ResultSetStream.getStream(tableNamesAndColumnsRS)
.map(resultSet -> { try
{
final DataColumnConstraints dataColumnConstraints = new DataColumnConstraints();
dataColumnConstraints.constraintName = resultSet.getString("constraint_name");
dataColumnConstraints.constraintType = resultSet.getString("constraint_type");
dataColumnConstraints.value = resultSet.getString("value");
if(resultSet.wasNull())
{
dataColumnConstraints.value = null;
}
dataColumnConstraints.min = resultSet.getDouble("min");
if(resultSet.wasNull())
{
dataColumnConstraints.min = null;
}
dataColumnConstraints.minIsInclusive = resultSet.getBoolean("minIsInclusive");
if(resultSet.wasNull())
{
dataColumnConstraints.minIsInclusive = null;
}
dataColumnConstraints.max = resultSet.getDouble("max");
if(resultSet.wasNull())
{
dataColumnConstraints.max = null;
}
dataColumnConstraints.maxIsInclusive = resultSet.getBoolean("maxIsInclusive");
if(resultSet.wasNull())
{
dataColumnConstraints.maxIsInclusive = null;
}
return dataColumnConstraints;
}
catch(final SQLException ex)
{
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
catch(final SQLException ex)
{
return Collections.emptyList();
}
}
private List getDataColumnValues()
{
final String query = String.format("SELECT table_name, column_name, constraint_name FROM %s;", GeoPackageSchema.DataColumnsTableName);
try(Statement statement = this.getSqliteConnection().createStatement();
ResultSet tableNamesAndColumnsRS = statement.executeQuery(query))
{
return ResultSetStream.getStream(tableNamesAndColumnsRS)
.map(resultSet -> { try
{
final DataColumns dataColumn = new DataColumns();
dataColumn.tableName = resultSet.getString("table_name");
dataColumn.columnName = resultSet.getString("column_name");
dataColumn.constraintName = resultSet.getString("constraint_name");
return dataColumn;
}
catch(final SQLException ex)
{
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
catch(final SQLException ex)
{
return Collections.emptyList();
}
}
private static final TableDefinition DataColumnsTableDefinition;
private static final TableDefinition DataColumnConstraintsTableDefinition;
static
{
final Map dataColumnsTableColumns = new HashMap<>();
dataColumnsTableColumns.put("table_name", new ColumnDefinition("TEXT", true, true, true, null));
dataColumnsTableColumns.put("column_name", new ColumnDefinition("TEXT", true, true, true, null));
dataColumnsTableColumns.put("name", new ColumnDefinition("TEXT", false, false, false, null));
dataColumnsTableColumns.put("title", new ColumnDefinition("TEXT", false, false, false, null));
dataColumnsTableColumns.put("description", new ColumnDefinition("TEXT", false, false, false, null));
dataColumnsTableColumns.put("mime_type", new ColumnDefinition("TEXT", false, false, false, null));
dataColumnsTableColumns.put("constraint_name", new ColumnDefinition("TEXT", false, false, false, null));
DataColumnsTableDefinition = new TableDefinition(GeoPackageSchema.DataColumnsTableName,
dataColumnsTableColumns,
new HashSet<>(Arrays.asList(new ForeignKeyDefinition(GeoPackageCore.ContentsTableName, "table_name", "table_name"))));
final Map dataColumnConstraintsColumns = new HashMap<>();
dataColumnConstraintsColumns.put("constraint_name", new ColumnDefinition("TEXT", true, false, false, null));
dataColumnConstraintsColumns.put("constraint_type", new ColumnDefinition("TEXT", true, false, false, null));
dataColumnConstraintsColumns.put("value", new ColumnDefinition("TEXT", false, false, false, null));
dataColumnConstraintsColumns.put("min", new ColumnDefinition("NUMERIC", false, false, false, null));
dataColumnConstraintsColumns.put("minIsInclusive", new ColumnDefinition("BOOLEAN", false, false, false, null));
dataColumnConstraintsColumns.put("max", new ColumnDefinition("NUMERIC", false, false, false, null));
dataColumnConstraintsColumns.put("maxIsInclusive", new ColumnDefinition("BOOLEAN", false, false, false, null));
dataColumnConstraintsColumns.put("description", new ColumnDefinition("TEXT", false, false, false, null));
DataColumnConstraintsTableDefinition = new TableDefinition(GeoPackageSchema.DataColumnConstraintsTableName,
dataColumnConstraintsColumns,
Collections.emptySet(),
new HashSet<>(Arrays.asList(new UniqueDefinition("constraint_name", "constraint_type", "value"))));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy