From ff818793c9585fdb3539dbfa534022dd49549ea0 Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Mon, 24 Jan 2022 12:16:41 -0600 Subject: [PATCH 1/3] Escape schema/tablenames in metadata.getTable() to handle names with _'s in them. --- .../snapshot/JdbcDatabaseSnapshot.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java b/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java index adfea1077fd..cb67dd591b3 100644 --- a/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java +++ b/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java @@ -1029,8 +1029,8 @@ public List fastFetchQuery() throws SQLException, DatabaseException { String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema); - return extract(databaseMetaData.getTables(catalog, schema, ((table == null) ? - SQL_FILTER_MATCH_ALL : table), new String[]{"TABLE"})); + return extract(databaseMetaData.getTables(catalog, escapeForLike(schema), ((table == null) ? + SQL_FILTER_MATCH_ALL : escapeForLike(table)), new String[]{"TABLE"})); } @Override @@ -1049,7 +1049,7 @@ public List bulkFetchQuery() throws SQLException, DatabaseException { String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema); - return extract(databaseMetaData.getTables(catalog, schema, SQL_FILTER_MATCH_ALL, new String[]{"TABLE"})); + return extract(databaseMetaData.getTables(catalog, escapeForLike(schema), SQL_FILTER_MATCH_ALL, new String[]{"TABLE"})); } private List queryMssql(CatalogAndSchema catalogAndSchema, String tableName) throws DatabaseException, SQLException { @@ -1133,8 +1133,8 @@ private List queryDb2Zos(CatalogAndSchema catalogAndSchema, String ta private List queryPostgres(CatalogAndSchema catalogAndSchema, String tableName) throws SQLException { String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema); - return extract(databaseMetaData.getTables(catalog, schema, ((tableName == null) ? - SQL_FILTER_MATCH_ALL : tableName), new String[]{"TABLE", "PARTITIONED TABLE"})); + return extract(databaseMetaData.getTables(catalog, escapeForLike(schema), ((tableName == null) ? + SQL_FILTER_MATCH_ALL : escapeForLike(tableName)), new String[]{"TABLE", "PARTITIONED TABLE"})); } }); @@ -1186,8 +1186,8 @@ public List fastFetchQuery() throws SQLException, DatabaseException { String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema); - return extract(databaseMetaData.getTables(catalog, schema, ((view == null) ? SQL_FILTER_MATCH_ALL - : view), new String[]{"VIEW"})); + return extract(databaseMetaData.getTables(catalog, escapeForLike(schema), ((view == null) ? SQL_FILTER_MATCH_ALL + : escapeForLike(view)), new String[]{"VIEW"})); } @Override @@ -1200,7 +1200,7 @@ public List bulkFetchQuery() throws SQLException, DatabaseException { String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema); - return extract(databaseMetaData.getTables(catalog, schema, SQL_FILTER_MATCH_ALL, new String[]{"VIEW"})); + return extract(databaseMetaData.getTables(catalog, escapeForLike(schema), SQL_FILTER_MATCH_ALL, new String[]{"VIEW"})); } @@ -1698,4 +1698,10 @@ private String getAllCatalogsStringScratchData() { return (String) JdbcDatabaseSnapshot.this.getScratchData(ALL_CATALOGS_STRING_SCRATCH_KEY); } + private String escapeForLike(String string) { + return string + .replace("%", "\\%") + .replace("_", "\\_"); + } + } From dc477266e3d92043624ba2d0e951d96016cb7201 Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Mon, 24 Jan 2022 23:55:15 -0600 Subject: [PATCH 2/3] Escape schema/tablenames in metadata.getTable() to handle names with _'s in them. --- .../src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java b/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java index cb67dd591b3..4ddbb06d9da 100644 --- a/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java +++ b/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java @@ -1699,6 +1699,9 @@ private String getAllCatalogsStringScratchData() { } private String escapeForLike(String string) { + if (string == null) { + return null; + } return string .replace("%", "\\%") .replace("_", "\\_"); From fd0816867283fa9520829ac8c5be5a98e79e1597 Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Thu, 10 Feb 2022 12:21:37 -0600 Subject: [PATCH 3/3] Added test for getTables and getViews with an underscore in the table name --- .../snapshot/JdbcDatabaseSnapshotTest.groovy | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 liquibase-integration-tests/src/test/groovy/liquibase/snapshot/JdbcDatabaseSnapshotTest.groovy diff --git a/liquibase-integration-tests/src/test/groovy/liquibase/snapshot/JdbcDatabaseSnapshotTest.groovy b/liquibase-integration-tests/src/test/groovy/liquibase/snapshot/JdbcDatabaseSnapshotTest.groovy new file mode 100644 index 00000000000..4499199a1bd --- /dev/null +++ b/liquibase-integration-tests/src/test/groovy/liquibase/snapshot/JdbcDatabaseSnapshotTest.groovy @@ -0,0 +1,49 @@ +package liquibase.snapshot + +import liquibase.Scope +import liquibase.database.DatabaseFactory +import liquibase.database.jvm.JdbcConnection +import liquibase.extension.testing.testsystem.DatabaseTestSystem +import liquibase.extension.testing.testsystem.TestSystemFactory +import liquibase.statement.SqlStatement +import liquibase.statement.core.RawSqlStatement +import liquibase.structure.core.Table +import liquibase.structure.core.View +import org.junit.Rule +import spock.lang.Shared +import spock.lang.Specification +import spock.lang.Unroll + +import java.sql.Connection + +class JdbcDatabaseSnapshotTest extends Specification { + + @Rule + public DatabaseTestSystem h2 = Scope.currentScope.getSingleton(TestSystemFactory).getTestSystem("h2") + + @Unroll + def "getTables and getViews works with underscores in schema names"() { + when: + def connection = h2.getConnection() + def db = DatabaseFactory.instance.findCorrectDatabaseImplementation(new JdbcConnection(connection)) + db.execute([ + new RawSqlStatement("create schema if not exists \"TEST_SCHEMA\""), + new RawSqlStatement("create schema if not exists \"TEST-SCHEMA\""), + new RawSqlStatement("create table if not exists \"TEST-SCHEMA\".test_table (id int)"), + new RawSqlStatement("create view if not exists \"TEST-SCHEMA\".test_view as select * from \"TEST-SCHEMA\".test_table"), + ] as SqlStatement[], null) + + then: + SnapshotGeneratorFactory.instance.has(new Table(null, "TEST-SCHEMA", "TEST_TABLE"), db) + !SnapshotGeneratorFactory.instance.has(new Table(null, "TEST_SCHEMA", "TEST_TABLE"), db) + + SnapshotGeneratorFactory.instance.has(new View(null, "TEST-SCHEMA", "TEST_VIEW"), db) + !SnapshotGeneratorFactory.instance.has(new View(null, "TEST_SCHEMA", "TEST_VIEW"), db) + + cleanup: + db.execute([ + new RawSqlStatement("drop schema \"test_schema\" if exists"), + new RawSqlStatement("drop schema \"test-schema\" if exists"), + ] as SqlStatement[], null) + } +}