{
ResultSet rs = null;
DatabaseMetaData dbmeta = null;
boolean bPortable = true;
int nTableCount = 0;
Table lastTable;
int nCurTable;
assert schema.getTableCount() == 0;
assert m_connection != null;
schema.setPortable(false);
try
{
Lookup tableMap = new HashTab();
dbmeta = m_connection.getMetaData();
// Read the tables
if (progress != null)
{
progress.progress("info.sql.schemaManager.readingTables", null, 0);
}
sCatalogName = toDatabaseCase(sCatalogName);
sSchemaPattern = toDatabaseCase(sSchemaPattern);
sTablePattern = toDatabaseCase(sTablePattern);
rs = dbmeta.getTables(sCatalogName, sSchemaPattern, sTablePattern, new String[]{"TABLE"});
if (progress != null)
{
progress.progress("info.sql.schemaManager.readingTables", null, 0.01);
}
while (rs.next())
{
String sReadCatalogName = rs.getString("TABLE_CAT");
String sSchemaName = toMetadataCase(rs.getString("TABLE_SCHEM"));
String sTableName = rs.getString("TABLE_NAME");
if (!isValidTableName(sTableName))
{
continue;
}
if (nameSet != null && !nameSet.contains(sTableName))
{
continue;
}
sTableName = toMetadataCase(sTableName);
Table table = new Table(schema);
table.setName(getFullTableName(sSchemaName, sTableName));
table.setDescription(rs.getString("REMARKS"));
table.setType(Table.EXTERNAL);
++nTableCount;
if (s_logger.isDebugEnabled())
{
s_logger.debug("Read table \"" + ((sReadCatalogName == null) ? "" : sReadCatalogName) +
"." + ((sSchemaName == null) ? "" : sSchemaName) + "." + sTableName +
"\" -> \"" + table.getName() + "\"");
}
try
{
schema.addTable(table);
tableMap.put(table, new String[]{sReadCatalogName, sSchemaName});
bPortable &= isPortable(table);
}
catch (MetadataException e)
{
s_logger.error("Cannot add table \"" + table.getName() + "\"", e);
}
}
rs.close();
rs = null;
if (nTableCount == 0)
{
nTableCount = 1;
}
// Read the columns
rs = dbmeta.getColumns(sCatalogName, sSchemaPattern, sTablePattern, "%");
lastTable = null;
nCurTable = 0;
Lookup2D caseInsensitiveSet = new HashTab2D(); // Object[Table][String]
while (rs.next())
{
Table table = schema.findTable(
getFullTableName(toMetadataCase(rs.getString("TABLE_SCHEM")),
toMetadataCase(rs.getString("TABLE_NAME"))));
if (table == null)
{
continue;
}
if (progress != null && table != lastTable)
{
lastTable = table;
caseInsensitiveSet.clear();
progress.progress("info.sql.schemaManager.readingColumns", new Object[]{table.getName()},
0.05 + 0.15 * (nCurTable++ / nTableCount));
}
String sColName = toMetadataCase(rs.getString("COLUMN_NAME"));
String sName = null;
if (sColName != null)
{
sName = getCaseSensitiveName(sColName);
if (isCaseInsensitive(sColName))
{
caseInsensitiveSet.put(table, sName, Boolean.TRUE);
}
}
if (!isValidColumnName(sColName))
{
continue;
}
Column column = new Column(sName, table);
column.setNullable(rs.getInt("NULLABLE") != DatabaseMetaData.columnNoNulls);
column.setDescription(rs.getString("REMARKS"));
String sTypeName = rs.getString("TYPE_NAME");
int nType = rs.getInt("DATA_TYPE");
int nPrecision = rs.getInt("COLUMN_SIZE");
int nScale = rs.getInt("DECIMAL_DIGITS");
byte nAllocation = Column.FIXED;
Primitive type = null;
switch (nType)
{
case Types.BIGINT:
type = Primitive.LONG;
nPrecision = 0;
nScale = 0;
break;
case Types.BINARY:
type = Primitive.BINARY;
nScale = 0;
break;
case Types.BIT:
case Types.BOOLEAN:
type = Primitive.BOOLEAN;
nPrecision = 0;
nScale = 0;
break;
case Types.BLOB:
case Types.LONGVARBINARY:
type = Primitive.BINARY;
if (nPrecision <= 0x4000)
{
nPrecision = Integer.MAX_VALUE;
}
nScale = 0;
nAllocation = (nType == Types.BLOB) ? Column.LOCATOR : Column.VARYING;
break;
case Types.CHAR:
sTypeName = sTypeName.toLowerCase(Locale.ENGLISH);
if (sTypeName.equals("uniqueidentifier"))
{
type = Primitive.BINARY;
nPrecision = 16;
nScale = 0;
}
else
{
type = Primitive.STRING;
nScale = 0;
}
break;
case Types.CLOB:
case Types.LONGVARCHAR:
type = Primitive.STRING;
if (nPrecision <= 0x4000)
{
nPrecision = Integer.MAX_VALUE;
}
nScale = 0;
nAllocation = (nType == Types.CLOB) ? Column.LOCATOR : Column.VARYING;
break;
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
type = Primitive.TIMESTAMP;
nPrecision = 0;
nScale = 0;
break;
case Types.DECIMAL:
case Types.NUMERIC:
type = Primitive.DECIMAL;
if (nScale == 0 && nPrecision <= 20)
{
if (nPrecision <= 10)
{
type = Primitive.INTEGER;
if (nPrecision <= 3)
{
nPrecision = 1;
}
else if (nPrecision <= 5)
{
nPrecision = 2;
}
else
{
nPrecision = 0;
}
}
else
{
type = Primitive.LONG;
nPrecision = 0;
}
}
break;
case Types.DOUBLE:
case Types.FLOAT:
type = Primitive.DOUBLE;
nPrecision = 0;
nScale = 0;
break;
case Types.INTEGER:
type = Primitive.INTEGER;
nPrecision = 0;
nScale = 0;
break;
case Types.SMALLINT:
type = Primitive.INTEGER;
nPrecision = 2;
nScale = 0;
break;
case Types.TINYINT:
type = Primitive.INTEGER;
nPrecision = 1;
nScale = 0;
break;
case Types.REAL:
type = Primitive.FLOAT;
nPrecision = 0;
nScale = 0;
break;
case Types.VARBINARY:
type = Primitive.BINARY;
nScale = 0;
nAllocation = Column.VARYING;
break;
case Types.VARCHAR:
type = Primitive.STRING;
nScale = 0;
nAllocation = Column.VARYING;
break;
default:
sTypeName = sTypeName.toLowerCase(Locale.ENGLISH);
if (sTypeName.equals("nchar"))
{
type = Primitive.STRING;
nPrecision >>= 1;
nScale = 0;
}
else if (sTypeName.equals("nvarchar2") || sTypeName.equals("nvarchar"))
{
type = Primitive.STRING;
nPrecision >>= 1;
nScale = 0;
nAllocation = Column.VARYING;
}
else if (sTypeName.equals("binary_double"))
{
type = Primitive.DOUBLE;
nPrecision = 0;
nScale = 0;
}
else if (sTypeName.equals("binary_float"))
{
type = Primitive.FLOAT;
nPrecision = 0;
nScale = 0;
}
else if (sTypeName.startsWith("timestamp"))
{
type = Primitive.TIMESTAMP;
nPrecision = 0;
nScale = 0;
}
else if (sTypeName.equals("nclob") || sTypeName.equals("clob"))
{
type = Primitive.STRING;
if (nPrecision <= 0x4000)
{
nPrecision = Integer.MAX_VALUE;
}
nScale = 0;
nAllocation = Column.LOCATOR;
}
else if (sTypeName.equals("blob"))
{
type = Primitive.BINARY;
if (nPrecision <= 0x4000)
{
nPrecision = Integer.MAX_VALUE;
}
nScale = 0;
nAllocation = Column.LOCATOR;
}
break;
}
if (nPrecision < 0)
{
nPrecision = 0;
}
if (s_logger.isDebugEnabled())
{
s_logger.debug("Read column \"" + table.getName() + "." + column.getName() + "\" " +
sTypeName + "(" + rs.getInt("COLUMN_SIZE") + "," + rs.getInt("DECIMAL_DIGITS") +
"), SQLType=" + nType + " -> " + ((type == null) ? "ignored: unsupported type" : type.getName() +
"(" + nPrecision + "," + nScale + "), allocation=" + nAllocation));
}
if (type != null)
{
column.setType(type);
column.setPrecision(nPrecision);
column.setScale(nScale);
column.setAllocation(nAllocation);
try
{
table.addColumn(column);
bPortable &= isPortable(column);
}
catch (MetadataException e)
{
s_logger.error("Cannot add column \"" + column.getName() + "\"", e);
}
}
}
rs.close();
rs = null;
// Set the case-sensitive columns
for (Iterator tableItr = tableMap.iterator(); tableItr.hasNext();)
{
Table table = (Table)tableItr.next();
for (int i = 0; i < table.getColumnCount(); ++i)
{
Column column = table.getColumn(i);
if (!caseInsensitiveSet.contains(table, column.getName()))
{
column.setCaseInsensitive(false);
}
}
}
// Read the indexes
nCurTable = 0;
for (Iterator itr = schema.getTableIterator(); itr.hasNext();)
{
Table table = (Table)itr.next();
String[] names = (String[])tableMap.get(table);
Index index = null;
boolean bIgnore = false;
if (progress != null)
{
progress.progress("info.sql.schemaManager.readingIndexes", new Object[]{table.getName()},
0.20 + 0.50 * (nCurTable++ / nTableCount));
}
rs = getIndexInfo(
names[0], toDatabaseCase(names[1]), toDatabaseCase(table.getTableName()));
while (rs.next())
{
String sIndexName = toMetadataCase(rs.getString("INDEX_NAME"));
if (sIndexName == null)
{
continue;
}
String sColumnName = rs.getString("COLUMN_NAME");
boolean bAscending = !"D".equals(rs.getString("ASC_OR_DESC"));
boolean bUnique = !rs.getBoolean("NON_UNIQUE");
int nType = rs.getInt("TYPE");
sIndexName = generateIndexName(table.getTableName(), sIndexName, null);
if (s_logger.isDebugEnabled())
{
s_logger.debug("Read index column \"" + sIndexName + "." +
sColumnName + "\", ascending=" + bAscending);
}
if (index != null && !index.getName().equals(sIndexName))
{
if (!bIgnore)
{
if (addIndex(table, index))
{
bPortable &= isPortable(index);
}
}
index = null;
bIgnore = false;
}
if (index == null)
{
index = new Index(sIndexName, (nType == DatabaseMetaData.tableIndexClustered)
? Index.CLUSTER : Index.BTREE, table);
index.setUnique(bUnique);
}
if (!isValidColumnName(sColumnName))
{
if (isCaseInsensitive(sColumnName))
{
sColumnName = getCaseSensitiveName(sColumnName);
}
else if (isFunctionalIndexSupported())
{
String sExpr = rs.getString("EXPR");
if (sExpr != null && sExpr.length() != 0)
{
String sName = getCaseSensitiveNameFromExpression(sExpr);
if (sName == null)
{
bIgnore = true;
}
else
{
sColumnName = sName;
}
}
}
else
{
bIgnore = true;
}
}
sColumnName = toMetadataCase(sColumnName);
if (!bIgnore)
{
try
{
index.addIndexColumn(new IndexColumn(table.getColumn(sColumnName), bAscending));
}
catch (MetadataException e)
{
s_logger.error("Cannot find column \"" + sColumnName +
"\", ignoring index \"" + sIndexName + "\"", e);
bIgnore = true;
}
}
}
if (index != null && !bIgnore)
{
if (addIndex(table, index))
{
bPortable &= isPortable(index);
}
}
rs.close();
rs = null;
// Read the primary key
rs = getPrimaryKeys(names[0], names[1], table.getTableName());
index = null;
bIgnore = false;
try
{
while (rs.next())
{
String sColumnName = toMetadataCase(rs.getString("COLUMN_NAME"));
if (index == null)
{
String sIndexName = rs.getString("PK_NAME");
if (sIndexName == null)
{
sIndexName = table.getName() + ".PK";
index = new Index(sIndexName, Index.BTREE, table);
}
else
{
sIndexName = generateIndexName(table.getTableName(), sIndexName, "PK");
index = table.findIndex(sIndexName);
if (index == null)
{
index = new Index(sIndexName, Index.BTREE, table);
}
else
{
table.setPrimaryKey(index);
bIgnore = true;
break;
}
}
}
if (s_logger.isDebugEnabled())
{
s_logger.debug("Read primary key column \"" + index.getName() + "." + sColumnName + "\"");
}
index.setUnique(true);
index.addIndexColumn(new IndexColumn(table.getColumn(sColumnName), true));
}
}
catch (MetadataException e)
{
s_logger.error("Cannot add primary key to table \"" + table.getName() + "\"", e);
bIgnore = true;
}
if (index != null)
{
if (!bIgnore)
{
if (addIndex(table, index))
{
table.setPrimaryKey(index);
bPortable &= isPortable(index);
}
}
}
else
{
for (int i = 0; i < table.getIndexCount(); ++i)
{
index = table.getIndex(i);
if (index.isUnique())
{
table.setPrimaryKey(index);
break;
}
}
}
if (s_logger.isDebugEnabled())
{
if (table.getPrimaryKey() != null)
{
s_logger.debug("The primary key of table \"" + table.getName() +
"\" is \"" + table.getPrimaryKey().getName() + "\"");
}
else
{
s_logger.debug("Table \"" + table.getName() + "\" has no primary key");
}
}
rs.close();
rs = null;
}
// Read the foreign keys
nCurTable = 0;
for (Iterator itr = schema.getTableIterator(); itr.hasNext();)
{
Table table = (Table)itr.next();
String[] names = (String[])tableMap.get(table);
Index index = null;
boolean bIgnore = false;
if (progress != null)
{
progress.progress("info.sql.schemaManager.readingForeignKeys", new Object[]{table.getName()},
0.70 + 0.30 * (nCurTable++ / nTableCount));
}
rs = dbmeta.getExportedKeys(names[0], names[1], table.getTableName());
while (rs.next())
{
String sColumnName = toMetadataCase(rs.getString("FKCOLUMN_NAME"));
String sSchemaName = rs.getString("FKTABLE_SCHEM");
String sTableName = rs.getString("FKTABLE_NAME");
String sIndexName = rs.getString("FK_NAME");
Table foreignTable = schema.findTable(getFullTableName(sSchemaName, sTableName));
if (foreignTable == null)
{
continue;
}
sIndexName = generateIndexName(foreignTable.getTableName(), sIndexName, "FK" + (foreignTable.getIndexCount() + 1));
if (index != null && !index.getName().equals(sIndexName))
{
if (!bIgnore)
{
if (addIndex(index.getTable(), index))
{
addRelatedKey(table, index);
bPortable &= isPortable(index);
}
}
index = null;
bIgnore = false;
}
if (index == null)
{
if (rs.getString("FK_NAME") == null)
{
index = new Index(sIndexName, Index.BTREE, foreignTable);
}
else
{
index = foreignTable.findIndex(sIndexName);
if (index == null)
{
index = new Index(sIndexName, Index.BTREE, foreignTable);
}