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

Fix/ctas oracle column definitions deep copy #241

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.alfasoftware.morf.sql;

import static org.alfasoftware.morf.sql.SqlUtils.tableRef;
import static org.alfasoftware.morf.util.DeepCopyTransformations.castFields;
import static org.alfasoftware.morf.util.DeepCopyTransformations.transformIterable;

import java.util.ArrayList;
Expand Down Expand Up @@ -183,6 +184,11 @@ public T fields(AliasedFieldBuilder... fields) {
return fields(Arrays.asList(fields));
}

public T withFields(Iterable<? extends AliasedFieldBuilder> fields) {
this.fields.clear();
Iterables.addAll(this.fields, Builder.Helper.buildAll(fields));
return castToChild(this);
}

/**
* Selects fields from a specific table:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import org.alfasoftware.morf.sql.element.AliasedField;
import org.alfasoftware.morf.sql.element.FieldReference;
import org.alfasoftware.morf.sql.element.NullFieldLiteral;

import java.util.List;

/**
* Static collection of DeepCopyTransformation utilities.
Expand Down Expand Up @@ -56,6 +61,26 @@ public T apply(T input) {
}


public static DeepCopyTransformation castFields(List<AliasedField> fieldsToCast, List<AliasedField> fieldsToInclude) {
return new DeepCopyTransformation() {
@SuppressWarnings("unchecked")
@Override
public <T> T deepCopy(DeepCopyableWithTransformation<T,? extends Builder<T>> element) {

if(element == null) {
return null;
}

if(element instanceof FieldReference || element instanceof NullFieldLiteral) {
AliasedField fieldToCast = fieldsToInclude.get(fieldsToCast.indexOf(element));
return (T) fieldsToInclude.get(fieldsToCast.indexOf(element));
}

return element.deepCopy(noTransformation()).build();
}
};
}

private static class NoTransformDeepCopyTransformer implements DeepCopyTransformation {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,17 @@ protected List<String> expectedAddTableFromStatements() {
"INSERT INTO TESTSCHEMA.SomeTable SELECT someField, otherField FROM TESTSCHEMA.OtherTable"
);
}
/**
* @see org.alfasoftware.morf.jdbc.AbstractSqlDialectTest#expectedAddTableFromStatementsNullValue()
*/
@Override
protected List<String> expectedAddTableFromStatementsNullValue() {
return ImmutableList.of(
"CREATE TABLE TESTSCHEMA.SomeTable (someField VARCHAR(3) NOT NULL, otherField DECIMAL(3,0) NOT NULL, nullField VARCHAR(3) NOT NULL, CONSTRAINT SomeTable_PK PRIMARY KEY (someField))",
"CREATE INDEX SomeTable_1 ON TESTSCHEMA.SomeTable (otherField)",
"INSERT INTO TESTSCHEMA.SomeTable SELECT someField, otherField, null FROM TESTSCHEMA.OtherTable"
);
}


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,18 @@ protected List<String> expectedAddTableFromStatements() {
);
}

/**
* @see org.alfasoftware.morf.jdbc.AbstractSqlDialectTest#expectedAddTableFromStatementsNullValue()
*/
@Override
protected List<String> expectedAddTableFromStatementsNullValue() {
return ImmutableList.of(
"CREATE TABLE `SomeTable` (`someField` VARCHAR(3) NOT NULL, `otherField` DECIMAL(3,0) NOT NULL, `nullField` VARCHAR(3) NOT NULL, CONSTRAINT `SomeTable_PK` PRIMARY KEY (`someField`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin",
"ALTER TABLE `SomeTable` ADD INDEX `SomeTable_1` (`otherField`)",
"INSERT INTO SomeTable SELECT someField, otherField, null FROM OtherTable"
);
}


/**
* We only support {@link SelectStatement#useImplicitJoinOrder()}, and only to a limited extent.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,19 @@ protected List<String> expectedAddTableFromStatements() {
);
}

/**
* @see org.alfasoftware.morf.jdbc.AbstractSqlDialectTest#expectedAddTableFromStatementsNullValue()
*/
@Override
protected List<String> expectedAddTableFromStatementsNullValue() {
return ImmutableList.of(
"CREATE TABLE SCM.SomeTable (someField VARCHAR(3) NOT NULL, otherField DECIMAL(3,0) NOT NULL, nullField VARCHAR(3) NOT NULL, PRIMARY KEY (someField))",
"DROP INDEX IF EXISTS SCM.SomeTable_1",
"CREATE INDEX SomeTable_1 ON SCM.SomeTable (otherField)",
"INSERT INTO SCM.SomeTable SELECT someField, otherField, null FROM SCM.OtherTable"
);
}


/**
* @see org.alfasoftware.morf.jdbc.AbstractSqlDialectTest#expectedHints1(int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@
import org.alfasoftware.morf.sql.element.ConcatenatedField;
import org.alfasoftware.morf.sql.element.FieldReference;
import org.alfasoftware.morf.sql.element.Function;
import org.alfasoftware.morf.sql.element.NullFieldLiteral;
import org.alfasoftware.morf.sql.element.SqlParameter;
import org.alfasoftware.morf.sql.element.TableReference;
import org.alfasoftware.morf.util.DeepCopyTransformations;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -96,6 +98,8 @@ class OracleDialect extends SqlDialect {
*/
public static final String NULLS_LAST = "NULLS LAST";

private static final String CANNOT_CONVERT_NULL_STATEMENT_TO_SQL = "Cannot convert a null statement to SQL";

/**
* Database platforms may order nulls first or last. My SQL always orders nulls first, Oracle defaults to ordering nulls last.
* Fortunately on Oracle it is possible to specify that nulls should be ordered first.
Expand Down Expand Up @@ -1105,11 +1109,28 @@ public Collection<String> renameTableStatements(Table fromTable, Table toTable)
*/
@Override
public Collection<String> addTableFromStatements(Table table, SelectStatement selectStatement) {
List<AliasedField> fieldsToInclude = new ArrayList<>();

for(AliasedField field: selectStatement.getFields()) {
if (field instanceof NullFieldLiteral || field instanceof FieldReference) {
Column column = table.columns().get(selectStatement.getFields().indexOf(field));
fieldsToInclude.add(new Cast(
field,
column.getType(),
column.getWidth(),
column.getScale()).as(column.getName()));
} else {
fieldsToInclude.add(field);
}
}

// SelectStatement deepCopiedStatement = selectStatement.deepCopy(DeepCopyTransformations.castFields(selectStatement.getFields(), fieldsToInclude)).build();

Builder<String> result = ImmutableList.<String>builder();
result.add(new StringBuilder()
.append(createTableStatement(table, true))
.append(" AS ")
.append(convertStatementToSQL(selectStatement))
.append(convertStatementToSQL(selectStatement.deepCopy(DeepCopyTransformations.castFields(selectStatement.getFields(), fieldsToInclude)).build()))
.toString()
);
result.add("ALTER TABLE " + schemaNamePrefix() + table.getName() + " NOPARALLEL LOGGING");
Expand All @@ -1123,7 +1144,6 @@ public Collection<String> addTableFromStatements(Table table, SelectStatement se
return result.build();
}


/**
* Builds the remaining statements (triggers, sequences and comments).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
package org.alfasoftware.morf.jdbc.oracle;

import static org.alfasoftware.morf.jdbc.oracle.OracleDialect.NULLS_LAST;
import static org.alfasoftware.morf.sql.SqlUtils.parameter;
import static org.alfasoftware.morf.metadata.SchemaUtils.*;
import static org.alfasoftware.morf.sql.SqlUtils.*;
import static org.alfasoftware.morf.sql.element.Direction.ASCENDING;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertEquals;
Expand All @@ -43,10 +44,13 @@
import org.alfasoftware.morf.jdbc.SqlScriptExecutor;
import org.alfasoftware.morf.metadata.DataType;
import org.alfasoftware.morf.metadata.SchemaUtils;
import org.alfasoftware.morf.metadata.Table;
import org.alfasoftware.morf.sql.CustomHint;
import org.alfasoftware.morf.sql.OracleCustomHint;
import org.alfasoftware.morf.sql.SelectStatement;
import org.alfasoftware.morf.sql.element.Direction;
import org.alfasoftware.morf.sql.element.SqlParameter;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import com.google.common.base.Strings;
Expand Down Expand Up @@ -1452,7 +1456,7 @@ protected String expectedSelectLiteralWithWhereClauseString() {
@Override
public List<String> expectedAddTableFromStatements() {
return ImmutableList.of(
"CREATE TABLE TESTSCHEMA.SomeTable (someField NOT NULL, otherField NOT NULL, CONSTRAINT SomeTable_PK PRIMARY KEY (someField) USING INDEX (CREATE UNIQUE INDEX TESTSCHEMA.SomeTable_PK ON TESTSCHEMA.SomeTable (someField))) PARALLEL NOLOGGING AS SELECT someField, otherField FROM TESTSCHEMA.OtherTable",
"CREATE TABLE TESTSCHEMA.SomeTable (someField NOT NULL, otherField NOT NULL, CONSTRAINT SomeTable_PK PRIMARY KEY (someField) USING INDEX (CREATE UNIQUE INDEX TESTSCHEMA.SomeTable_PK ON TESTSCHEMA.SomeTable (someField))) PARALLEL NOLOGGING AS SELECT CAST(someField AS NVARCHAR2(3)) AS someField, CAST(otherField AS DECIMAL(3,0)) AS otherField FROM TESTSCHEMA.OtherTable",
"ALTER TABLE TESTSCHEMA.SomeTable NOPARALLEL LOGGING",
"ALTER INDEX TESTSCHEMA.SomeTable_PK NOPARALLEL LOGGING",
"COMMENT ON TABLE TESTSCHEMA.SomeTable IS '"+OracleDialect.REAL_NAME_COMMENT_LABEL+":[SomeTable]'",
Expand All @@ -1461,6 +1465,22 @@ public List<String> expectedAddTableFromStatements() {
);
}

/**
* @see org.alfasoftware.morf.jdbc.AbstractSqlDialectTest#expectedAddTableFromStatementsNullValue()
*/
@Override
public List<String> expectedAddTableFromStatementsNullValue() {
return ImmutableList.of(
"CREATE TABLE TESTSCHEMA.SomeTable (someField NOT NULL, otherField NOT NULL, nullField NOT NULL, CONSTRAINT SomeTable_PK PRIMARY KEY (someField) USING INDEX (CREATE UNIQUE INDEX TESTSCHEMA.SomeTable_PK ON TESTSCHEMA.SomeTable (someField))) PARALLEL NOLOGGING AS SELECT CAST(someField AS NVARCHAR2(3)) AS someField, CAST(otherField AS DECIMAL(3,0)) AS otherField, CAST(null AS NVARCHAR2(3)) AS nullField FROM TESTSCHEMA.OtherTable",
"ALTER TABLE TESTSCHEMA.SomeTable NOPARALLEL LOGGING",
"ALTER INDEX TESTSCHEMA.SomeTable_PK NOPARALLEL LOGGING",
"COMMENT ON TABLE TESTSCHEMA.SomeTable IS 'REALNAME:[SomeTable]'",
"COMMENT ON COLUMN TESTSCHEMA.SomeTable.someField IS 'REALNAME:[someField]/TYPE:[STRING]'",
"COMMENT ON COLUMN TESTSCHEMA.SomeTable.otherField IS 'REALNAME:[otherField]/TYPE:[DECIMAL]'",
"COMMENT ON COLUMN TESTSCHEMA.SomeTable.nullField IS 'REALNAME:[nullField]/TYPE:[STRING]'"
);
}

/**
* @see org.alfasoftware.morf.jdbc.AbstractSqlDialectTest#expectedHints1(int)
*/
Expand Down
Loading