use of schemacrawler.schema.Column in project hale by halestudio.
the class JDBCSchemaReader method loadFromSource.
@Override
protected Schema loadFromSource(ProgressIndicator progress, IOReporter reporter) throws IOProviderConfigurationException, IOException {
DefaultSchema typeIndex = null;
progress.begin("Read database schema", ProgressIndicator.UNKNOWN);
Connection connection = null;
try {
// connect to the database
try {
connection = getConnection();
} catch (Exception e) {
reporter.error(new IOMessageImpl(e.getLocalizedMessage(), e));
reporter.setSuccess(false);
reporter.setSummary("Failed to connect to database.");
return null;
}
// connection has been created), report a warning message instead
try {
connection.setReadOnly(true);
} catch (SQLException e) {
// ignore
// reporter.warn(new IOMessageImpl(e.getLocalizedMessage(), e));
}
URI jdbcURI = getSource().getLocation();
final SchemaCrawlerOptions options = new SchemaCrawlerOptions();
SchemaInfoLevel level = new SchemaInfoLevel();
level.setTag("hale");
// these are enabled by default, we don't need them (yet)
level.setRetrieveSchemaCrawlerInfo(false);
level.setRetrieveJdbcDriverInfo(false);
level.setRetrieveDatabaseInfo(false);
// set what we need
level.setRetrieveTables(true);
level.setRetrieveColumnDataTypes(true);
level.setRetrieveUserDefinedColumnDataTypes(true);
// to get table columns
level.setRetrieveTableColumns(true);
// information, also
// includes primary key
// to get linking information
level.setRetrieveForeignKeys(true);
// level.setRetrieveIndices(true); // to get info about UNIQUE indices for validation
// XXX For some advanced info / DBMS specific info we'll need a
// properties file. See Config & InformationSchemaViews.
level.setTag("hale");
if (getParameter(SCHEMAS).as(String.class) != null) {
String schemas = getParameter(SCHEMAS).as(String.class).replace(',', '|');
options.setSchemaInclusionRule(new RegularExpressionInclusionRule(schemas));
}
if (SchemaSpaceID.SOURCE.equals(getSchemaSpace())) {
// show views and tables
final List<String> tableTypesWanted = Arrays.asList("TABLE", "VIEW", "MATERIALIZED VIEW");
// try to determine table types supported by the JDBC connection
final List<String> tableTypeSupported = new ArrayList<>();
try {
ResultSet rs = connection.getMetaData().getTableTypes();
while (rs.next()) {
String tableType = rs.getString(1);
tableTypeSupported.add(tableType);
}
} catch (Throwable t) {
// Ignore, try with wanted list
reporter.warn(new IOMessageImpl(MessageFormat.format("Could not determine supported table types for connection: {0}", t.getMessage()), t));
tableTypeSupported.addAll(tableTypesWanted);
}
options.setTableTypes(tableTypesWanted.stream().filter(tt -> tableTypeSupported.contains(tt)).collect(Collectors.toList()));
} else {
// only show tables
options.setTableTypes(Arrays.asList("TABLE"));
}
options.setSchemaInfoLevel(level);
// get advisor
// XXX should be created once, and used in other places if
// applicable
JDBCSchemaReaderAdvisor advisor = SchemaReaderAdvisorExtension.getInstance().getAdvisor(connection);
if (advisor != null) {
advisor.configureSchemaCrawler(options);
}
final Catalog database = SchemaCrawlerUtility.getCatalog(connection, options);
@SuppressWarnings("unused") String quotes = JDBCUtil.determineQuoteString(connection);
// FIXME not actually used here or in SQL schema reader
String overallNamespace = JDBCUtil.determineNamespace(jdbcURI, advisor);
// create the type index
typeIndex = new DefaultSchema(overallNamespace, jdbcURI);
for (final schemacrawler.schema.Schema schema : database.getSchemas()) {
// each schema represents a namespace
String namespace;
if (overallNamespace.isEmpty()) {
namespace = unquote(schema.getName());
} else {
namespace = overallNamespace;
if (schema.getName() != null) {
namespace += ":" + unquote(schema.getName());
}
}
for (final Table table : database.getTables(schema)) {
// each table is a type
// get the type definition
TypeDefinition type = getOrCreateTableType(schema, table, overallNamespace, namespace, typeIndex, connection, reporter, database);
// get ResultSetMetaData for extra info about columns (e. g.
// auto increment)
ResultsColumns additionalInfo = null;
Statement stmt = null;
try {
stmt = connection.createStatement();
// get if in table name, quotation required or not.
String fullTableName = getQuotedValue(table.getName());
if (schema.getName() != null) {
fullTableName = getQuotedValue(schema.getName()) + "." + fullTableName;
}
ResultSet rs = stmt.executeQuery("SELECT * FROM " + fullTableName + " WHERE 1 = 0");
additionalInfo = SchemaCrawlerUtility.getResultColumns(rs);
} catch (SQLException sqle) {
reporter.warn(new IOMessageImpl("Couldn't retrieve additional column meta data.", sqle));
} finally {
if (stmt != null)
try {
stmt.close();
} catch (SQLException e) {
// ignore
}
}
// create property definitions for each column
for (final Column column : table.getColumns()) {
DefaultPropertyDefinition property = getOrCreateProperty(schema, type, column, overallNamespace, namespace, typeIndex, connection, reporter, database);
// XXX does not work for example for PostgreSQL
if (additionalInfo != null) {
// ResultColumns does not quote the column namen in
// contrast to every other place
ResultsColumn rc = additionalInfo.getColumn(unquote(column.getName()));
if (rc != null && rc.isAutoIncrement())
property.setConstraint(AutoIncrementFlag.get(true));
}
}
}
}
reporter.setSuccess(true);
} catch (SchemaCrawlerException e) {
throw new IOProviderConfigurationException("Failed to read database schema", e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// ignore
}
}
progress.end();
}
return typeIndex;
}
use of schemacrawler.schema.Column in project hale by halestudio.
the class JDBCSchemaReader method getOrCreateProperty.
/**
* Gets or creates a property definition for the given column. Its type
* definition is created, too, if necessary.
*
* @param schema the schema the table belongs to
* @param tableType the type definition of the parent table this column
* belongs too
* @param column the column to get or create a property definition for
* @param overallNamespace the database namespace
* @param namespace the schema namespace
* @param typeIndex the type index
* @param connection the database connection
* @param reporter the reporter
* @param catalog the catalog for access to other column types
* @return the property definition for the given column
*/
private DefaultPropertyDefinition getOrCreateProperty(schemacrawler.schema.Schema schema, TypeDefinition tableType, Column column, String overallNamespace, String namespace, DefaultSchema typeIndex, Connection connection, IOReporter reporter, Catalog catalog) {
QName name = new QName(unquote(column.getName()));
// check for existing property definition
ChildDefinition<?> existing = tableType.getChild(name);
if (existing != null) {
return (DefaultPropertyDefinition) existing;
}
// create new one
// determine the column type
TypeDefinition columnType = getOrCreateColumnType(column, overallNamespace, typeIndex, connection, tableType, reporter, catalog);
SQLArray arrayInfo = columnType.getConstraint(SQLArray.class);
// create the property
DefaultPropertyDefinition property = new DefaultPropertyDefinition(name, tableType, columnType);
// configure property
if (column.getRemarks() != null && !column.getRemarks().isEmpty()) {
property.setDescription(column.getRemarks());
}
property.setConstraint(NillableFlag.get(column.isNullable()));
// XXX Default value is read as string from the meta data.
// This is probably not really a problem, but should be noted!
// XXX In particular the default value can be a function call like for
// example GETDATE().
String defaultValue = column.getDefaultValue();
if (arrayInfo.isArray() && arrayInfo.getDimension() <= 1) {
// dimension is not known (0)
if (!arrayInfo.hasSize(0)) {
property.setConstraint(Cardinality.CC_ANY_NUMBER);
} else {
// XXX what is appropriate as minimum?
long min = 0;
long max = arrayInfo.getSize(0);
property.setConstraint(Cardinality.get(min, max));
}
} else if (defaultValue != null) {
property.setConstraint(new DefaultValue(defaultValue));
property.setConstraint(Cardinality.CC_OPTIONAL);
} else
property.setConstraint(Cardinality.CC_EXACTLY_ONCE);
// incremented or not
if (column.isAutoIncremented()) {
property.setConstraint(AutoGenerated.get(true));
} else {
property.setConstraint(AutoGenerated.get(false));
}
// since they can have multiple columns
if (column.isPartOfForeignKey()) {
Column referenced = column.getReferencedColumn();
// StackOverFlow exception.
if (!(referenced.getParent().equals(column.getParent()) && referenced.equals(column))) {
// Referenced table can be in different schema.
// creation of referenced column's table should not be with same
// Schema or Namespace. It should be with referenced table's
// Schema and namespace.
String referencedNameSpace = getReferencedTableNamespace(referenced.getParent(), overallNamespace);
property.setConstraint(new Reference(getOrCreateTableType(referenced.getParent().getSchema(), referenced.getParent(), overallNamespace, referencedNameSpace, typeIndex, connection, reporter, catalog)));
}
}
return property;
}
Aggregations