diff --git a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandler.java b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandler.java index 3203fe8d..bc51b47f 100644 --- a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandler.java +++ b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandler.java @@ -1,8 +1,14 @@ package de.opitzconsulting.orcas.diff; +import de.opitzconsulting.orcas.orig.diff.ColumnDiff; import de.opitzconsulting.orcas.sql.CallableStatementProvider; import de.opitzconsulting.origOrcasDsl.CharType; +import java.util.ArrayList; +import java.util.List; + +import static de.opitzconsulting.origOrcasDsl.OrigOrcasDslPackage.Literals.*; + public abstract class DatabaseHandler { public abstract void createOrcasUpdatesTable(String pOrcasUpdatesTableName, CallableStatementProvider pOrcasCallableStatementProvider); @@ -50,6 +56,50 @@ public final boolean isExpressionDifferent(String pExpression1, String pExpressi return isExpressionDifferentNotNull(pExpression1, pExpression2); } + public List isRecreateColumn(ColumnDiff pColumnDiff) { + List lReturn = new ArrayList<>(); + + if (pColumnDiff.data_typeNew != null && pColumnDiff.data_typeOld != null) { + if (!pColumnDiff.data_typeIsEqual) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__DATA_TYPE, pColumnDiff)); + } + + if (isLessTahnOrNull(pColumnDiff.precisionNew, pColumnDiff.precisionOld)) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__PRECISION, pColumnDiff)); + } + + if (isLessTahnOrNull(pColumnDiff.scaleNew, pColumnDiff.scaleOld)) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__SCALE, pColumnDiff)); + } + } + + if (!pColumnDiff.object_typeIsEqual) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__OBJECT_TYPE, pColumnDiff)); + } + + if (!pColumnDiff.unsignedIsEqual) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__UNSIGNED, pColumnDiff)); + } + + if (!pColumnDiff.virtualIsEqual) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__VIRTUAL, pColumnDiff)); + } + + return lReturn; + } + + private boolean isLessTahnOrNull(Integer pValue1, Integer pValue2) { + if (pValue1 == null && pValue2 == null) { + return false; + } + + if (pValue1 == null || pValue2 == null) { + return true; + } + + return pValue1 < pValue2; + } + protected boolean isExpressionDifferentNotNull(String pExpression1, String pExpression2) { return !pExpression1.equals(pExpression2); } diff --git a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandlerAzureSql.java b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandlerAzureSql.java index 8dd6e211..1fd27a45 100644 --- a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandlerAzureSql.java +++ b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DatabaseHandlerAzureSql.java @@ -1,5 +1,6 @@ package de.opitzconsulting.orcas.diff; +import de.opitzconsulting.orcas.orig.diff.ColumnDiff; import de.opitzconsulting.orcas.sql.CallableStatementProvider; import de.opitzconsulting.orcas.sql.WrapperExecutePreparedStatement; import de.opitzconsulting.origOrcasDsl.CharType; @@ -11,6 +12,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static de.opitzconsulting.origOrcasDsl.OrigOrcasDslPackage.Literals.COLUMN__DEFAULT_VALUE; + public class DatabaseHandlerAzureSql extends DatabaseHandler { @Override public void createOrcasUpdatesTable(String pOrcasUpdatesTableName, CallableStatementProvider pOrcasCallableStatementProvider) { @@ -197,6 +200,25 @@ public List splitByIfPossible(String pSplit) { } } + @Override + public boolean isCanDiffFunctionBasedIndexExpression() { + return false; + } + + + @Override + public List isRecreateColumn(ColumnDiff pColumnDiff) { + List lReturn = super.isRecreateColumn(pColumnDiff); + + if ("virtual".equals(pColumnDiff.virtualNew) && !pColumnDiff.default_valueIsEqual) { + if (isExpressionDifferent(pColumnDiff.default_valueNew, pColumnDiff.default_valueOld)) { + lReturn.add(new RecreateNeededBuilder.DifferenceImpl(COLUMN__DEFAULT_VALUE, pColumnDiff)); + } + } + + return lReturn; + } + private static class SubListToken extends Token { List tokens; boolean logicOr = false; diff --git a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DdlBuilderAzureSql.java b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DdlBuilderAzureSql.java index 6e240635..24cb4af2 100644 --- a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DdlBuilderAzureSql.java +++ b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/DdlBuilderAzureSql.java @@ -62,7 +62,12 @@ public void dropComment(StatementBuilder p, TableDiff pTableDiff, InlineCommentD public void recreateColumn(StatementBuilder pP, TableDiff pTableDiff, ColumnDiff pColumnDiff) { pP.failIfAdditionsOnly("can't recreate columns"); - pP.addStmt("alter table " + pTableDiff.nameNew + " alter column " + createColumnCreatePart(pColumnDiff, false)); + if ("virtual".equals(pColumnDiff.virtualNew) || "virtual".equals(pColumnDiff.virtualOld)) { + pP.addStmt("alter table " + pTableDiff.nameNew + " drop column " + pColumnDiff.nameOld); + pP.addStmt("alter table " + pTableDiff.nameNew + " add " + createColumnCreatePart(pColumnDiff, false)); + } else { + pP.addStmt("alter table " + pTableDiff.nameNew + " alter column " + createColumnCreatePart(pColumnDiff, false)); + } } @Override @@ -102,13 +107,19 @@ public void dropPrimaryKey(StatementBuilder p, TableDiff pTableDiff, PrimaryKeyD @Override protected String createColumnCreatePart(ColumnDiff pColumnDiff, boolean pWithoutNotNull) { - String lReturn = pColumnDiff.nameNew + " " + getColumnDatatype(pColumnDiff); + boolean isVirtual = "virtual".equals(pColumnDiff.virtualNew); + + String lReturn = pColumnDiff.nameNew + (isVirtual ? "" : (" " + getColumnDatatype(pColumnDiff))); if (pColumnDiff.default_valueNew != null) { - if (pColumnDiff.default_nameNew != null) { - lReturn = lReturn + " constraint " + pColumnDiff.default_nameNew; + if (isVirtual) { + lReturn = lReturn + " as (" + pColumnDiff.default_valueNew + ")"; + } else { + if (pColumnDiff.default_nameNew != null) { + lReturn = lReturn + " constraint " + pColumnDiff.default_nameNew; + } + lReturn = lReturn + " default " + pColumnDiff.default_valueNew; } - lReturn = lReturn + " default " + pColumnDiff.default_valueNew; } if (pColumnDiff.notnullNew) { diff --git a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/LoadIstAzureSql.java b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/LoadIstAzureSql.java index d6c2f78a..d19b58c1 100644 --- a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/LoadIstAzureSql.java +++ b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/LoadIstAzureSql.java @@ -262,6 +262,8 @@ private void loadTableColumnsIntoModel(final Model pModel) { " columns.precision as precision," + // " columns.scale as scale," + // " columns.is_nullable as is_nullable," + // + " columns.is_computed," + // + " (select definition from " + getDataDictionaryView("computed_columns") + " where computed_columns.object_id = columns.object_id and computed_columns.column_id = columns.column_id) as column_virtual_definition," + // " (select definition from " + getDataDictionaryView("default_constraints") + " where default_constraints.object_id = columns.default_object_id) as column_default," + // " (select default_constraints.name from " + getDataDictionaryView("default_constraints") + " where default_constraints.object_id = columns.default_object_id) as column_default_name" + // " from " + getDataDictionaryView("columns") + // @@ -294,6 +296,11 @@ protected void useResultSetRow(ResultSet pResultSet) throws SQLException { lColumn.setDefault_name(pResultSet.getString("column_default_name")); } + if (pResultSet.getBoolean("is_computed")) { + lColumn.setVirtual("virtual"); + lColumn.setDefault_value(pResultSet.getString("column_virtual_definition")); + } + lColumn.setNotnull(!pResultSet.getBoolean("is_nullable")); if (pResultSet.getString("data_type").startsWith("numeric") || pResultSet.getString("data_type").startsWith("decimal")) { diff --git a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/OrcasDiff.java b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/OrcasDiff.java index d930e991..bd8de776 100644 --- a/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/OrcasDiff.java +++ b/orcas_core/build_source/orcas_diff/src/main/java/de/opitzconsulting/orcas/diff/OrcasDiff.java @@ -97,57 +97,7 @@ private List getIndexRecreate( TableDiff pTableDiff, String pI private List isRecreateColumn( ColumnDiff pColumnDiff ) { - List lReturn = new ArrayList<>(); - - if( pColumnDiff.data_typeNew != null && pColumnDiff.data_typeOld != null ) - { - if( !pColumnDiff.data_typeIsEqual ) - { - lReturn.add(new DifferenceImpl(COLUMN__DATA_TYPE, pColumnDiff)); - } - - if( isLessTahnOrNull( pColumnDiff.precisionNew, pColumnDiff.precisionOld ) ) - { - lReturn.add(new DifferenceImpl(COLUMN__PRECISION, pColumnDiff)); - } - - if( isLessTahnOrNull( pColumnDiff.scaleNew, pColumnDiff.scaleOld ) ) - { - lReturn.add(new DifferenceImpl(COLUMN__SCALE, pColumnDiff)); - } - } - - if( !pColumnDiff.object_typeIsEqual ) - { - lReturn.add(new DifferenceImpl(COLUMN__OBJECT_TYPE, pColumnDiff)); - } - - if( !pColumnDiff.unsignedIsEqual ) - { - lReturn.add(new DifferenceImpl(COLUMN__UNSIGNED, pColumnDiff)); - } - - if( !pColumnDiff.virtualIsEqual ) - { - lReturn.add(new DifferenceImpl(COLUMN__VIRTUAL, pColumnDiff)); - } - - return lReturn; - } - - private boolean isLessTahnOrNull( Integer pValue1, Integer pValue2 ) - { - if( pValue1 == null && pValue2 == null ) - { - return false; - } - - if( pValue1 == null || pValue2 == null ) - { - return true; - } - - return pValue1 < pValue2; + return databaseHandler.isRecreateColumn(pColumnDiff); } private void loadNames( ModelDiff pModelDiff, boolean pIsNew ) @@ -270,10 +220,16 @@ private void updateIsRecreateNeeded( ModelDiff pModelDiff ) lRecreateColumnNames.put( lColumnDiff.nameOld, recreateNeededRegistry.getRecreateNeededReasons( lColumnDiff ) ); } else { - List - lChangeVirtualColumn = - RecreateNeededBuilder.getDifferentEAttributes(lColumnDiff, Stream.of(COLUMN__IDENTITY, COLUMN__DEFAULT_VALUE).collect( - Collectors.toList())); + List lChangeVirtualColumn = new ArrayList<>(); + + if (!lColumnDiff.isFieldEqual(COLUMN__IDENTITY)) { + lChangeVirtualColumn.add(new DifferenceImpl(COLUMN__IDENTITY, lColumnDiff)); + } + + if (databaseHandler.isExpressionDifferent(lColumnDiff.default_valueOld, lColumnDiff.default_valueNew)) { + lChangeVirtualColumn.add(new DifferenceImpl(COLUMN__DEFAULT_VALUE, lColumnDiff)); + } + if (lColumnDiff.isOld && (lColumnDiff.virtualOld != null || !lColumnDiff.virtualIsEqual) && !lChangeVirtualColumn.isEmpty()) { DiffActionReasonDifferent lDiffActionReasonDifferent = diff --git a/orcas_core/build_source/orcas_diff/src/test/java/de/opitzconsulting/orcas/diff/TestDatabaseHandlerAzureSql.java b/orcas_core/build_source/orcas_diff/src/test/java/de/opitzconsulting/orcas/diff/TestDatabaseHandlerAzureSql.java index 08404d5f..088cac56 100644 --- a/orcas_core/build_source/orcas_diff/src/test/java/de/opitzconsulting/orcas/diff/TestDatabaseHandlerAzureSql.java +++ b/orcas_core/build_source/orcas_diff/src/test/java/de/opitzconsulting/orcas/diff/TestDatabaseHandlerAzureSql.java @@ -58,6 +58,7 @@ public void testIsExpressionDifferentNotNullStatics_Complex() { , "(benu_extern_knz = 0 and benu_passwort is not null) or (benu_extern_knz = 1 and benu_passwort is null)"); assertEqual("([eisc_zusatzfunktion]='SFA' OR [eisc_zusatzfunktion]='TK' OR [eisc_zusatzfunktion] IS NULL)" , "eisc_zusatzfunktion in ('TK','SFA') or eisc_zusatzfunktion is null"); + assertEqual("(CONVERT([varchar](10),[C_COL1])+'y')", "CONVERT(VARCHAR(10),C_COL1)+'y'"); } private static void assertEqual(String pExpression1, String pExpression2) { diff --git a/orcas_integrationstest/tests/test_column_virtual_azuresql/erzeuge_ausgangszustand.sql b/orcas_integrationstest/tests/test_column_virtual_azuresql/erzeuge_ausgangszustand.sql new file mode 100644 index 00000000..d0ae5172 --- /dev/null +++ b/orcas_integrationstest/tests/test_column_virtual_azuresql/erzeuge_ausgangszustand.sql @@ -0,0 +1,29 @@ +create table tab_add_column +( + c_col1 numeric(10) +); + +create table tab_change_column +( + c_col1 numeric(10), + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'X') +); + +create table tab_change_make_not_virtual +( + c_col1 numeric(10), + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'X') +); + +create table tab_change_make_virtual +( + c_col1 numeric(10), + c_col2 varchar(41) +); + +create table tab_change_virtual_with_index +( + c_col1 numeric(10) not null, + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'X') +); +create index tab_change_virtual_with_index_ix on tab_change_virtual_with_index (c_col2); diff --git a/orcas_integrationstest/tests/test_column_virtual_azuresql/erzeuge_zielzustand.sql b/orcas_integrationstest/tests/test_column_virtual_azuresql/erzeuge_zielzustand.sql new file mode 100644 index 00000000..82c39b32 --- /dev/null +++ b/orcas_integrationstest/tests/test_column_virtual_azuresql/erzeuge_zielzustand.sql @@ -0,0 +1,37 @@ +create table tab_virtual_column +( + c_col1 numeric(10), + c_col2 numeric(10), + c_col3 as (CONVERT(VARCHAR(10),C_COL1)+' '+CONVERT(VARCHAR(10),C_COL2)) +); + +create table tab_add_column +( + c_col1 numeric(10), + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'X') +); + +create table tab_change_column +( + c_col1 numeric(10), + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'Y') +); + +create table tab_change_make_not_virtual +( + c_col1 numeric(10), + c_col2 varchar(41) +); + +create table tab_change_make_virtual +( + c_col1 numeric(10), + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'Y') +); + +create table tab_change_virtual_with_index +( + c_col1 numeric(10) not null, + c_col2 as (CONVERT(VARCHAR(10),C_COL1)+'y') +); +create index tab_change_virtual_with_index_ix on tab_change_virtual_with_index (c_col2); diff --git a/orcas_integrationstest/tests/test_column_virtual_azuresql/parameter.properties b/orcas_integrationstest/tests/test_column_virtual_azuresql/parameter.properties new file mode 100644 index 00000000..95851c2a --- /dev/null +++ b/orcas_integrationstest/tests/test_column_virtual_azuresql/parameter.properties @@ -0,0 +1,4 @@ +dropmode = true +test_extract = true +dialect = azuresql + diff --git a/orcas_integrationstest/tests/test_column_virtual_azuresql/tabellen/tabelle.sql b/orcas_integrationstest/tests/test_column_virtual_azuresql/tabellen/tabelle.sql new file mode 100644 index 00000000..bf271795 --- /dev/null +++ b/orcas_integrationstest/tests/test_column_virtual_azuresql/tabellen/tabelle.sql @@ -0,0 +1,37 @@ +create table tab_virtual_column +( + c_col1 number(10), + c_col2 number(10), + c_col3 varchar2(21) as ("CONVERT(VARCHAR(10),C_COL1)+' '+CONVERT(VARCHAR(10),C_COL2)") virtual +); + +create table tab_add_column +( + c_col1 number(10), + c_col2 varchar2(11) as ("CONVERT(VARCHAR(10),C_COL1)+'X'") virtual +); + +create table tab_change_column +( + c_col1 number(10), + c_col2 varchar2(11) as ("CONVERT(VARCHAR(10),C_COL1)+'Y'") virtual +); + +create table tab_change_make_not_virtual +( + c_col1 number(10), + c_col2 varchar2(41) +); + +create table tab_change_make_virtual +( + c_col1 number(10), + c_col2 varchar2(11) as ("CONVERT(VARCHAR(10),C_COL1)+'Y'") virtual +); + +create table tab_change_virtual_with_index +( + c_col1 number(10) not null, + c_col2 varchar2(11) as ("CONVERT(VARCHAR(10),C_COL1)+'y'") virtual, + index tab_change_virtual_with_index_ix (c_col2) +);