-
Notifications
You must be signed in to change notification settings - Fork 0
dbeaver/pro#8539 netezza sql generator #3
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
Merged
Merged
Changes from 7 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
97a9609
dbeaver/pro#8539 netezza sql generator
Destrolaric 96c5e5d
dbeaver/pro#859 liquibase generator
Destrolaric b1cd221
dbeaver/pro#8539 update generators
Destrolaric eeb61a6
dbeaver/pro#8539 netezza
Destrolaric c19cd7b
dbeaver/pro#8539 fix incorrect variable
Destrolaric 5664510
dbeaver/pro#8539 netezza changes
Destrolaric e32ce77
dbeaver/pro#8539 netezza changes
Destrolaric 7b0cb90
dbeaver/pro#8539 fix incorrect query
Destrolaric 6d0f7b8
dbeaver/pro#8539 increment version
Destrolaric 97e66c3
dbeaver/pro#8539 log error instead of exception
Destrolaric 06f8093
dbeaver/pro#8539 license
Destrolaric f255abc
dbeaver/pro#8539 fix dates
Destrolaric 428c464
dbeaver/pro#8539 fix config name
Destrolaric File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
src/main/java/liquibase/ext/netezza/change/ModifyDataTypeChangeDestructiveNetezza.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package liquibase.ext.netezza.change; | ||
|
|
||
| import liquibase.change.DatabaseChange; | ||
| import liquibase.change.core.ModifyDataTypeChange; | ||
| import liquibase.database.Database; | ||
| import liquibase.database.core.DB2Database; | ||
| import liquibase.ext.netezza.statement.ModifyColumnDataTypeStatementNetezza; | ||
| import liquibase.statement.SqlStatement; | ||
| import liquibase.statement.core.ModifyDataTypeStatement; | ||
| import liquibase.statement.core.ReorganizeTableStatement; | ||
|
|
||
| /** | ||
| * Netezza only allows changing length(by incrementing but not decrementing) and precision(by incrementing but not decrementing) of the data type. | ||
| * So we need to override the default implementation of ModifyDataTypeChange to generate the correct SQL | ||
| * for Netezza. If the change is not safe, we will throw an exception to prevent the change from being executed. | ||
| * This class is used to mark the change as destructive, to make it different from the default implementation of ModifyDataTypeChange which is not destructive. | ||
| */ | ||
| @DatabaseChange( | ||
| name = "modifyDataTypeDestructive", | ||
| description = "Modify the data type of a column, by recreating", | ||
| priority = 5, | ||
| appliesTo = {"column"} | ||
| ) | ||
| public class ModifyDataTypeChangeDestructiveNetezza extends ModifyDataTypeChange { | ||
|
|
||
| @Override | ||
| public SqlStatement[] generateStatements(Database database) { | ||
| ModifyColumnDataTypeStatementNetezza modifyDataTypeStatement = new ModifyColumnDataTypeStatementNetezza(this.getCatalogName(), this.getSchemaName(), this.getTableName(), this.getColumnName(), this.getNewDataType()); | ||
| return new SqlStatement[] {modifyDataTypeStatement}; | ||
| } | ||
|
|
||
| @Override | ||
| public String getCatalogName() { | ||
| return super.getCatalogName(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getSchemaName() { | ||
| return super.getSchemaName(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getTableName() { | ||
| return super.getTableName(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getColumnName() { | ||
| return super.getColumnName(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getNewDataType() { | ||
| return super.getNewDataType(); | ||
| } | ||
| } | ||
20 changes: 20 additions & 0 deletions
20
src/main/java/liquibase/ext/netezza/datatype/NetezzaNumberType.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package liquibase.ext.netezza.datatype; | ||
|
|
||
| import liquibase.database.Database; | ||
| import liquibase.datatype.DatabaseDataType; | ||
| import liquibase.datatype.core.NumberType; | ||
| import liquibase.ext.netezza.database.NetezzaDatabase; | ||
|
|
||
| public class NetezzaNumberType extends NumberType { | ||
| public int getPriority() { | ||
| return 5; | ||
| } | ||
|
|
||
| public boolean supports(Database database) { | ||
| return database instanceof NetezzaDatabase; | ||
| } | ||
|
|
||
| public DatabaseDataType toDatabaseDataType(Database database) { | ||
| return new DatabaseDataType("NUMERIC", this.getParameters()); | ||
| } | ||
| } |
155 changes: 155 additions & 0 deletions
155
...java/liquibase/ext/netezza/diff/output/changelog/ChangedColumnChangeGeneratorNetezza.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| package liquibase.ext.netezza.diff.output.changelog; | ||
|
|
||
| import liquibase.change.Change; | ||
| import liquibase.database.Database; | ||
| import liquibase.database.jvm.JdbcConnection; | ||
| import liquibase.diff.Difference; | ||
| import liquibase.diff.ObjectDifferences; | ||
| import liquibase.diff.output.DiffOutputControl; | ||
| import liquibase.diff.output.changelog.core.ChangedColumnChangeGenerator; | ||
| import liquibase.exception.UnexpectedLiquibaseException; | ||
| import liquibase.ext.netezza.change.ModifyDataTypeChangeDestructiveNetezza; | ||
| import liquibase.ext.netezza.database.NetezzaDatabase; | ||
| import liquibase.structure.DatabaseObject; | ||
| import liquibase.structure.core.Column; | ||
| import liquibase.structure.core.DataType; | ||
| import liquibase.structure.core.Schema; | ||
|
|
||
| import java.sql.PreparedStatement; | ||
| import java.sql.ResultSet; | ||
| import java.util.List; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public class ChangedColumnChangeGeneratorNetezza extends ChangedColumnChangeGenerator { | ||
|
|
||
| public static final Pattern LENGTH_PATTERN = Pattern.compile("VARCHAR\\((\\d+)\\s*(?:BYTE)?\\)"); | ||
|
|
||
|
|
||
| @Override | ||
| public int getPriority(Class<? extends DatabaseObject> objectType, Database database) { | ||
| if (database instanceof NetezzaDatabase) { | ||
| return Column.class.isAssignableFrom(objectType) ? 2 : -1; | ||
| } else { | ||
| return PRIORITY_NONE; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| protected void handleTypeDifferences( | ||
| Column column, | ||
| ObjectDifferences differences, | ||
| DiffOutputControl control, | ||
| List<Change> changes, | ||
| Database referenceDatabase, | ||
| Database comparisonDatabase | ||
| ) { | ||
| Difference typeDifference = differences.getDifference("type"); | ||
| if (typeDifference == null) { | ||
| return; | ||
| } | ||
| String table = column.getRelation().getName(); | ||
| String columnName = column.getName(); | ||
| Schema schema = column.getRelation().getSchema(); | ||
| boolean isSafe = isSafeExpansion( | ||
| typeDifference.getComparedValue().toString(), | ||
| typeDifference.getReferenceValue().toString() | ||
| ); | ||
| if (!isSafe && isDistributionKey(referenceDatabase, schema, table, columnName)) { | ||
| throw new UnexpectedLiquibaseException( | ||
| "Column '" + columnName + "' is a distribution key. " + | ||
| "Full table rebuild required." | ||
| ); | ||
| } | ||
|
|
||
| if (!isSafe && isIndexed(referenceDatabase, schema, table, columnName)) { | ||
| throw new UnexpectedLiquibaseException( | ||
| String.format( | ||
| "Column '%s.%s.%s' is indexed and cannot be safely modified in Netezza.", | ||
| schema, table, columnName | ||
| ) | ||
| ); | ||
| } | ||
| if (isSafe) { | ||
| super.handleTypeDifferences(column, differences, control, changes, referenceDatabase, comparisonDatabase); | ||
| } else { | ||
| ModifyDataTypeChangeDestructiveNetezza modifyDataTypeChangeDestructiveNetezza = new ModifyDataTypeChangeDestructiveNetezza(); | ||
| modifyDataTypeChangeDestructiveNetezza.setSchemaName(schema.getName()); | ||
| modifyDataTypeChangeDestructiveNetezza.setTableName(table); | ||
| modifyDataTypeChangeDestructiveNetezza.setColumnName(columnName); | ||
| DataType referenceType = (DataType)typeDifference.getReferenceValue(); | ||
| modifyDataTypeChangeDestructiveNetezza.setNewDataType(referenceType.toString()); | ||
| changes.add(modifyDataTypeChangeDestructiveNetezza); | ||
| } | ||
| } | ||
|
|
||
| private boolean isSafeExpansion(String oldType, String newType) { | ||
| if (oldType == null) return false; | ||
|
|
||
| oldType = oldType.toUpperCase(); | ||
| newType = newType.toUpperCase(); | ||
|
|
||
| // VARCHAR(n) -> VARCHAR(m) where m >= n | ||
| if (oldType.startsWith("VARCHAR") && newType.startsWith("VARCHAR")) { | ||
| int oldLen = extractSingleNumber(oldType); | ||
| int newLen = extractSingleNumber(newType); | ||
| return newLen >= oldLen; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| private int extractSingleNumber(String type) { | ||
| Matcher m = LENGTH_PATTERN.matcher(type); | ||
| return m.find() ? Integer.parseInt(m.group(1)) : 0; | ||
| } | ||
|
|
||
| private boolean isDistributionKey(Database referenceDatabase, Schema schema, String table, String columnName) { | ||
| String sql = | ||
| "SELECT 1\n" | ||
| + "FROM _v_table_dist_map dm\n" | ||
| + "WHERE dm.OWNER = ?\n" | ||
| + " AND dm.TABLENAME = ?\n" | ||
| + " AND dm.attname = ?"; | ||
| try (PreparedStatement ps = ((JdbcConnection) referenceDatabase.getConnection()).prepareStatement(sql)) { | ||
| ps.setString(1, schema.getName().toUpperCase()); | ||
| ps.setString(2, table.toUpperCase()); | ||
| ps.setString(3, columnName.toUpperCase()); | ||
|
|
||
| try (ResultSet rs = ps.executeQuery()) { | ||
| return rs.next(); | ||
| } | ||
|
|
||
| } catch (Exception e) { | ||
| throw new RuntimeException( | ||
| "Failed to check distribution key for " + table + "." + columnName, e | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| protected boolean isIndexed(Database database, Schema schema, String table, String column) { | ||
| String sql = | ||
| "SELECT 1\n" | ||
| + "FROM DEFINITION_SCHEMA._V_RELATION_KEYDATA\n" | ||
| + "WHERE \"SCHEMA\" = ?\n" | ||
| + " AND RELATION = ?\n" | ||
| + " AND ATTNAME = ?"; | ||
|
|
||
| try (PreparedStatement ps = | ||
| ((JdbcConnection) database.getConnection()).prepareStatement(sql)) { | ||
|
|
||
| ps.setString(1, table.toUpperCase()); | ||
| ps.setString(2, schema.getName().toUpperCase()); | ||
| ps.setString(3, column.toUpperCase()); | ||
|
|
||
| try (ResultSet rs = ps.executeQuery()) { | ||
| return rs.next(); | ||
| } | ||
|
|
||
| } catch (Exception e) { | ||
| throw new RuntimeException( | ||
| "Failed to check index usage for " + schema + "." + table + "." + column, e | ||
| ); | ||
| } | ||
| } | ||
| } |
34 changes: 34 additions & 0 deletions
34
src/main/java/liquibase/ext/netezza/sqlgenerator/DropColumnGeneratorNetezza.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package liquibase.ext.netezza.sqlgenerator; | ||
|
|
||
| import liquibase.database.Database; | ||
| import liquibase.ext.netezza.database.NetezzaDatabase; | ||
| import liquibase.sql.Sql; | ||
| import liquibase.sql.UnparsedSql; | ||
| import liquibase.sqlgenerator.SqlGeneratorChain; | ||
| import liquibase.sqlgenerator.core.DropColumnGenerator; | ||
| import liquibase.statement.core.DropColumnStatement; | ||
| import liquibase.structure.DatabaseObject; | ||
|
|
||
| public class DropColumnGeneratorNetezza extends DropColumnGenerator { | ||
| public int getPriority() { | ||
| return 5; | ||
| } | ||
|
|
||
| public boolean supports(DropColumnStatement statement, Database database) { | ||
| return database instanceof NetezzaDatabase; | ||
| } | ||
|
|
||
| public Sql[] generateSql(DropColumnStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { | ||
| Sql[] sqls = new Sql[1]; | ||
| String tableName = database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName()); | ||
| sqls[0] = new UnparsedSql( | ||
| "ALTER TABLE " + tableName + " DROP " + database.escapeColumnName( | ||
| statement.getCatalogName(), | ||
| statement.getSchemaName(), | ||
| statement.getTableName(), | ||
| statement.getColumnName() | ||
| ) + " RESTRICT", new DatabaseObject[0] | ||
| ); | ||
| return sqls; | ||
| } | ||
| } |
81 changes: 81 additions & 0 deletions
81
src/main/java/liquibase/ext/netezza/sqlgenerator/ModifyDataTypeGeneratorNetezza.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| package liquibase.ext.netezza.sqlgenerator; | ||
|
|
||
| import liquibase.database.Database; | ||
| import liquibase.datatype.DataTypeFactory; | ||
| import liquibase.datatype.DatabaseDataType; | ||
| import liquibase.exception.Warnings; | ||
| import liquibase.ext.netezza.database.NetezzaDatabase; | ||
| import liquibase.ext.netezza.statement.ModifyColumnDataTypeStatementNetezza; | ||
| import liquibase.sql.Sql; | ||
| import liquibase.sql.UnparsedSql; | ||
| import liquibase.sqlgenerator.SqlGeneratorChain; | ||
| import liquibase.sqlgenerator.core.ModifyDataTypeGenerator; | ||
| import liquibase.statement.core.ModifyDataTypeStatement; | ||
| import liquibase.structure.DatabaseObject; | ||
| import liquibase.structure.core.Relation; | ||
|
|
||
| /** | ||
| * Netezza only allows changing length(by incrementing but not decrementing) and precision(by incrementing but not decrementing) of the data type. | ||
| * So we need to override the default implementation of ModifyDataTypeGenerator to generate the correct SQL for Netezza. | ||
| */ | ||
| public class ModifyDataTypeGeneratorNetezza extends ModifyDataTypeGenerator { | ||
| public ModifyDataTypeGeneratorNetezza() { | ||
| super(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supports(ModifyDataTypeStatement statement, Database database) { | ||
| if (statement instanceof ModifyColumnDataTypeStatementNetezza) { | ||
| return database instanceof NetezzaDatabase; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public Sql[] generateSql(ModifyDataTypeStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { | ||
| String table = database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName());; | ||
| String column = database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), statement.getColumnName()); | ||
| DatabaseDataType newDataType = DataTypeFactory.getInstance().fromDescription(statement.getNewDataType(), database).toDatabaseDataType(database); | ||
| // fallback: recreate column | ||
| String tempColumn = statement.getColumnName() + "_TMP_" + System.currentTimeMillis(); | ||
| Relation affectedTable = this.getAffectedTable(statement); | ||
| return new Sql[] { | ||
| new UnparsedSql(String.format( | ||
| "ALTER TABLE %s ADD COLUMN %s %s", | ||
| table, tempColumn, newDataType | ||
| ), affectedTable | ||
| ), | ||
| new UnparsedSql(String.format( | ||
| "UPDATE %s SET %s = %s", | ||
| table, tempColumn, column | ||
| ), affectedTable | ||
| ), | ||
| new UnparsedSql(String.format( | ||
| "ALTER TABLE %s DROP COLUMN %s RESTRICT", | ||
| table, column | ||
| ), affectedTable | ||
| ), | ||
| new UnparsedSql(String.format( | ||
| "ALTER TABLE %s RENAME COLUMN %s TO %s", | ||
| table, tempColumn, column | ||
| ), affectedTable | ||
| ) | ||
| }; | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public Warnings warn(ModifyDataTypeStatement modifyDataTypeStatement, Database database, SqlGeneratorChain sqlGeneratorChain) { | ||
| return new Warnings().addWarning( | ||
| "Changing data type " + | ||
| " to " + modifyDataTypeStatement.getNewDataType() + " may cause data loss. Netezza does not support shrinking data types nor changing the type itself. Migration will attempt to recreate the column, but it may fail if there are constraints or indexes on the column." | ||
| ); | ||
| } | ||
|
|
||
|
|
||
| @Override | ||
| public int getPriority() { | ||
| return PRIORITY_DATABASE; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there be a copyright?