Skip to content

Commit

Permalink
Read Snowflake views definitions with the Snowflake-specific query (#…
Browse files Browse the repository at this point in the history
…3794)

* Read Snowflake views definitions with the Snowflake-specific query

* Move view DDL reading to the GetViewDefinitionGeneratorSnowflake class; avoid NPE from a view definition in the ViewSnapshotGenerator

* Add logging for the case of empty view definition

* Add Javadoc to the GetViewDefinitionGeneratorSnowflake class

---------

Co-authored-by: filipe <flautert@liquibase.org>
  • Loading branch information
LonwoLonwo and filipelautert committed Apr 7, 2023
1 parent b5bad04 commit 11f4b66
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 4 deletions.
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;

/**
* 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

0 comments on commit 11f4b66

Please sign in to comment.