changelogSchemaName/changelogCatalogName configuration options will not work on Oracle DB

Description

Unable to use changelogSchemaName/changelogCatalogName configuration parameters on Oracle DB.

Steps to reproduce:

Testplan 1.

  1. Configure Liquibase against Oracle DB instance, user A;

  2. Set changelogSchemaName to B;

  3. Launch update procedure;

  4. Note that DATABASECHAGELOG* tables are created in A schema.

Testplan 2.

  1. Configure Liquibase against Oracle DB instance, user A;

  2. Set changelogCatalogName to B;

  3. Launch update procedure;

  4. Note that DATABASECHAGELOG* tables are created in A schema.

Testplan 3.

  1. Perform steps outlined in Testplan 2.

  2. Launch Liquibase again with the same configuration.

  3. Notice an exception similar to this:

Code analysis showed that:

Oracle does not support schemas "in Liquibase's opinion".

I.e. liquibase.database.core.OracleDatabase.supportsSchemas() always return false, hence liquibase.database.AbstractJdbcDatabase.getDefaultSchemaName() always return default catalog (usually <jdbc_connection_username>).

Code, which creates DATABASECHANGELOG/DATABASECHANGELOGLOCK tables also affected.

liquibase.sqlgenerator.core.CreateDatabaseChangeLogLockTableGenerator.generateSql(CreateDatabaseChangeLogLockTableStatement, Database, SqlGeneratorChain) will create an SQL statement containing catalog only, whereas schema (set to <changelogSchemaName>) ignored by liquibase.database.AbstractJdbcDatabase.escapeObjectName(String, String, String, Class<? extends DatabaseObject>). The same issue with liquibase.sqlgenerator.core.CreateDatabaseChangeLogTableGenerator.generateSql(CreateDatabaseChangeLogTableStatement, Database, SqlGeneratorChain).

Note on DB metadata check when <changelogCatalogName> is set.

In liquibase.snapshot.SnapshotGeneratorFactory.hasDatabaseChangeLogLockTable(Database) DATABASECHANGELOGLOCK table object recieves catalog = <changelogCatalogName>, schemaName = <jdbc_connection_username> (see note about AbstractJdbcDatabase.getDefaultSchemaName() above) upon creation.
DB metadata loading code - liquibase.snapshot.JdbcDatabaseSnapshot.CachingDatabaseMetaData.getTables(String, String, String, String[]) - called prior to the existance check, recieves catalogName = null, schemaName = <changelogCatalogName>, but eventually calls CatalogAndSchema catalogAndSchema = new CatalogAndSchema(catalogName, schemaName).customize(database);(JdbcDatabaseSnapshot.java:356, fastFetchQuery() method). customize(Database) method, in turn, calls liquibase.CatalogAndSchema.standardize(Database), which nullifyes schema name:

CatalogAndSchema.java

This effectively eliminates configured <changelogCatalogName> value and resets it to default schema (usually <jdbc_connection_username>).
queryOracle(CatalogAndSchema, String) that called furhter creates a query of the form:

which will return information about tables from <jdbc_connection_username> schema only; table snapshot will retain this info and, hence, the DATABASECHANGELOGLOCK table object passed to liquibase.snapshot.SnapshotGeneratorFactory.has(DatabaseObject, Database) by liquibase.snapshot.SnapshotGeneratorFactory.hasDatabaseChangeLogLockTable(Database) will not be matched because schema names differ. Liquibase will decide that this table does not exist (even if it is not the case, and it existis within the default schema) and attempt to recreate a lock table.

Environment

Oracle Database 11.2.0.3.0, Maven 3.2.1, JDK 1.7.0_51.

Reporter

Alexander

Fix versions

Affects versions

Priority

Critical
Configure