Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read Snowflake views definitions with the Snowflake-specific query #3794

Merged
merged 11 commits into from
Apr 7, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,18 @@ protected DatabaseObject snapshotObject(DatabaseObject example, DatabaseSnapshot
database.setObjectQuotingStrategy(ObjectQuotingStrategy.QUOTE_ALL_OBJECTS);
String definition = database.getViewDefinition(schemaFromJdbcInfo, view.getName());

if (definition.startsWith("FULL_DEFINITION: ")) {
if (definition != null && definition.startsWith("FULL_DEFINITION: ")) {
definition = definition.replaceFirst("^FULL_DEFINITION: ", "");
view.setContainsFullDefinition(true);
}

// remove strange zero-termination seen on some Oracle view definitions
int length = definition.length();
int length = definition != null ? definition.length() : 0;
if (length > 0 && definition.charAt(length-1) == 0) {
definition = definition.substring(0, length-1);
}

if (database instanceof InformixDatabase) {
if (database instanceof InformixDatabase && definition != null) {
// Cleanup
definition = definition.trim();
definition = definition.replaceAll("\\s*,\\s*", ", ");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package liquibase.database.core;

import liquibase.CatalogAndSchema;
import liquibase.Scope;
import liquibase.database.AbstractJdbcDatabase;
import liquibase.database.DatabaseConnection;
Expand All @@ -15,10 +16,12 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

public class SnowflakeDatabase extends AbstractJdbcDatabase {

public static final String PRODUCT_NAME = "Snowflake";
private static final Pattern CREATE_VIEW_AS_PATTERN = Pattern.compile("^CREATE\\s+.*?VIEW\\s+.*?AS\\s+", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
private Set<String> systemTables = new HashSet<>();
private Set<String> systemViews = new HashSet<>();

Expand Down Expand Up @@ -288,4 +291,18 @@ private Set<String> getDefaultReservedWords() {

return reservedWords;
}

public String getViewDefinition(CatalogAndSchema schema, String viewName) throws DatabaseException {
String definition = super.getViewDefinition(schema, viewName);
if (definition == null || definition.isEmpty()) {
Scope.getCurrentScope()
.getLog(getClass())
.info("Error reading '" + (viewName != null && viewName.isEmpty() ? viewName : "") + "' view definition");
return null;
}
if (definition.endsWith(";")) {
definition = definition.substring(0, definition.length() - 1);
}
return CREATE_VIEW_AS_PATTERN.matcher(definition).replaceFirst("");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package liquibase.sqlgenerator.core;

import liquibase.CatalogAndSchema;
import liquibase.database.Database;
import liquibase.database.core.SnowflakeDatabase;
import liquibase.sql.Sql;
import liquibase.sql.UnparsedSql;
import liquibase.sqlgenerator.SqlGeneratorChain;
import liquibase.statement.core.GetViewDefinitionStatement;

filipelautert marked this conversation as resolved.
Show resolved Hide resolved
/**
* Snowflake-specific view definition generator.
* Uses Snowflake-specific query to read full view definition statement from a database.
*/
public class GetViewDefinitionGeneratorSnowflake extends GetViewDefinitionGenerator {

@Override
public int getPriority() {
return PRIORITY_DATABASE;
}

@Override
public boolean supports(GetViewDefinitionStatement statement, Database database) {
return database instanceof SnowflakeDatabase;
}

@Override
public Sql[] generateSql(GetViewDefinitionStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
CatalogAndSchema schema = new CatalogAndSchema(statement.getCatalogName(), statement.getSchemaName()).customize(database);
// We can use non quoted schema/catalog/view names here.
// SELECT GET_DDL('VIEW', 'TEST.BAD$SCHEMA_NAME.BAD$%^VIEW_NAME', TRUE) - works fine.
// "TRUE" means that the returned result will be in the full representation
return new Sql[] {
new UnparsedSql( "SELECT GET_DDL('VIEW', '"
+ schema.getCatalogName() + "." + schema.getSchemaName() + "." + statement.getViewName() + "', TRUE)"
)
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ liquibase.sqlgenerator.core.InsertOrUpdateGeneratorSnowflake
liquibase.sqlgenerator.core.RenameTableGeneratorSnowflake
liquibase.sqlgenerator.core.RenameViewGeneratorSnowflake
liquibase.sqlgenerator.core.SetColumnRemarksGeneratorSnowflake
liquibase.sqlgenerator.core.SetTableRemarksGeneratorSnowflake
liquibase.sqlgenerator.core.SetTableRemarksGeneratorSnowflake
liquibase.sqlgenerator.core.GetViewDefinitionGeneratorSnowflake