HHH-14435 Improve table information extraction (especially for Oracle with enableSynonyms)
Previously Oracle with enableSynonyms ran into a timeout on CI because the JDBC driver issues a rather expensive query. The new implementation issues a dummy query and uses the result set metadata as suggested in various online articles about schema introspection
This commit is contained in:
parent
62d727d44e
commit
21c89240d0
|
@ -23,4 +23,20 @@ public class QualifiedTableName extends QualifiedNameImpl {
|
|||
public Identifier getTableName() {
|
||||
return getObjectName();
|
||||
}
|
||||
|
||||
public QualifiedTableName quote() {
|
||||
Identifier catalogName = getCatalogName();
|
||||
if ( catalogName != null ) {
|
||||
catalogName = new Identifier( catalogName.getText(), true );
|
||||
}
|
||||
Identifier schemaName = getSchemaName();
|
||||
if ( schemaName != null ) {
|
||||
schemaName = new Identifier( schemaName.getText(), true );
|
||||
}
|
||||
Identifier tableName = getTableName();
|
||||
if ( tableName != null ) {
|
||||
tableName = new Identifier( tableName.getText(), true );
|
||||
}
|
||||
return new QualifiedTableName( catalogName, schemaName, tableName );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ package org.hibernate.tool.schema.extract.internal;
|
|||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -540,62 +542,53 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information
|
|||
}
|
||||
|
||||
private void addColumns(TableInformation tableInformation) {
|
||||
final QualifiedTableName tableName = tableInformation.getName();
|
||||
final Identifier catalog = tableName.getCatalogName();
|
||||
final Identifier schema = tableName.getSchemaName();
|
||||
// We use this dummy query to retrieve the table information through the ResultSetMetaData
|
||||
// This is significantly better than to use the DatabaseMetaData especially on Oracle with synonyms enabled
|
||||
final String tableName = extractionContext.getJdbcEnvironment().getQualifiedObjectNameFormatter().format(
|
||||
// The name comes from the database, so the case is correct
|
||||
// But we quote here to avoid issues with reserved words
|
||||
tableInformation.getName().quote(),
|
||||
extractionContext.getJdbcEnvironment().getDialect()
|
||||
);
|
||||
final String query = "select * from " + tableName + " where 1=0";
|
||||
try (Statement statement = extractionContext.getJdbcConnection()
|
||||
.createStatement(); ResultSet resultSet = statement.executeQuery( query )) {
|
||||
final ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
final int columnCount = metaData.getColumnCount();
|
||||
|
||||
final String catalogFilter;
|
||||
final String schemaFilter;
|
||||
|
||||
if ( catalog == null ) {
|
||||
catalogFilter = "";
|
||||
}
|
||||
else {
|
||||
catalogFilter = catalog.getText();
|
||||
}
|
||||
|
||||
if ( schema == null ) {
|
||||
schemaFilter = "";
|
||||
}
|
||||
else {
|
||||
schemaFilter = schema.getText();
|
||||
}
|
||||
|
||||
try {
|
||||
ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getColumns(
|
||||
catalogFilter,
|
||||
schemaFilter,
|
||||
tableName.getTableName().getText(),
|
||||
"%"
|
||||
);
|
||||
|
||||
try {
|
||||
while ( resultSet.next() ) {
|
||||
final String columnName = resultSet.getString( "COLUMN_NAME" );
|
||||
final ColumnInformationImpl columnInformation = new ColumnInformationImpl(
|
||||
tableInformation,
|
||||
DatabaseIdentifier.toIdentifier( columnName ),
|
||||
resultSet.getInt( "DATA_TYPE" ),
|
||||
new StringTokenizer( resultSet.getString( "TYPE_NAME" ), "() " ).nextToken(),
|
||||
resultSet.getInt( "COLUMN_SIZE" ),
|
||||
resultSet.getInt( "DECIMAL_DIGITS" ),
|
||||
interpretTruthValue( resultSet.getString( "IS_NULLABLE" ) )
|
||||
);
|
||||
tableInformation.addColumn( columnInformation );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resultSet.close();
|
||||
for ( int i = 1; i <= columnCount; i++ ) {
|
||||
final String columnName = metaData.getColumnName( i );
|
||||
final ColumnInformationImpl columnInformation = new ColumnInformationImpl(
|
||||
tableInformation,
|
||||
DatabaseIdentifier.toIdentifier( columnName ),
|
||||
metaData.getColumnType( i ),
|
||||
new StringTokenizer( metaData.getColumnTypeName( i ), "() " ).nextToken(),
|
||||
metaData.getPrecision( i ),
|
||||
metaData.getScale( i ),
|
||||
interpretNullable( metaData.isNullable( i ) )
|
||||
);
|
||||
tableInformation.addColumn( columnInformation );
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convertSQLException(
|
||||
e,
|
||||
"Error accessing column metadata: " + tableName.toString()
|
||||
"Error accessing column metadata: " + tableInformation.getName().toString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private TruthValue interpretNullable(int nullable) {
|
||||
switch ( nullable ) {
|
||||
case ResultSetMetaData.columnNullable:
|
||||
return TruthValue.TRUE;
|
||||
case ResultSetMetaData.columnNoNulls:
|
||||
return TruthValue.FALSE;
|
||||
default:
|
||||
return TruthValue.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private TruthValue interpretTruthValue(String nullable) {
|
||||
if ( "yes".equalsIgnoreCase( nullable ) ) {
|
||||
return TruthValue.TRUE;
|
||||
|
|
Loading…
Reference in New Issue