Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_schema_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_search_index_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_table_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_view_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTddl_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTforeign_key;
import com.google.cloud.solutions.spannerddl.parser.ASTrow_deletion_policy_clause;
Expand Down Expand Up @@ -64,6 +65,7 @@ public static DatabaseDefinition create(List<ASTddl_statement> statements) {
LinkedHashMap<String, ASTcreate_change_stream_statement> changeStreams = new LinkedHashMap<>();
LinkedHashMap<String, String> alterDatabaseOptions = new LinkedHashMap<>();
LinkedHashMap<String, ASTcreate_schema_statement> schemas = new LinkedHashMap<>();
LinkedHashMap<String, ASTcreate_view_statement> views = new LinkedHashMap<>();

for (ASTddl_statement ddlStatement : statements) {
final SimpleNode statement = (SimpleNode) ddlStatement.jjtGetChild(0);
Expand Down Expand Up @@ -139,6 +141,14 @@ public static DatabaseDefinition create(List<ASTddl_statement> statements) {
(ASTcreate_schema_statement)
((ASTcreate_or_replace_statement) statement).getSchemaObject());
break;
case DdlParserTreeConstants.JJTCREATE_VIEW_STATEMENT:
views.put(
((ASTcreate_view_statement)
((ASTcreate_or_replace_statement) statement).getSchemaObject())
.getName(),
(ASTcreate_view_statement)
((ASTcreate_or_replace_statement) statement).getSchemaObject());
break;
default:
throw new IllegalArgumentException(
"Unsupported statement: " + AstTreeUtils.tokensToString(ddlStatement));
Expand All @@ -157,7 +167,8 @@ public static DatabaseDefinition create(List<ASTddl_statement> statements) {
ImmutableMap.copyOf(ttls),
ImmutableMap.copyOf(changeStreams),
ImmutableMap.copyOf(alterDatabaseOptions),
ImmutableMap.copyOf(schemas));
ImmutableMap.copyOf(schemas),
ImmutableMap.copyOf(views));
}

public abstract ImmutableMap<String, ASTcreate_table_statement> tablesInCreationOrder();
Expand All @@ -175,4 +186,6 @@ public static DatabaseDefinition create(List<ASTddl_statement> statements) {
abstract ImmutableMap<String, String> alterDatabaseOptions();

abstract ImmutableMap<String, ASTcreate_schema_statement> schemas();

abstract ImmutableMap<String, ASTcreate_view_statement> views();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_schema_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_search_index_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_table_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTcreate_view_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTddl_statement;
import com.google.cloud.solutions.spannerddl.parser.ASTforeign_key;
import com.google.cloud.solutions.spannerddl.parser.ASToptions_clause;
Expand Down Expand Up @@ -103,6 +104,7 @@ public class DdlDiff {
private final MapDifference<String, ASTcreate_search_index_statement> searchIndexDifferences;
private final String databaseName; // for alter Database
private final MapDifference<String, ASTcreate_schema_statement> schemaDifferences;
private final MapDifference<String, ASTcreate_view_statement> viewDifferences;

private DdlDiff(DatabaseDefinition originalDb, DatabaseDefinition newDb, String databaseName)
throws DdlDiffException {
Expand All @@ -122,6 +124,7 @@ private DdlDiff(DatabaseDefinition originalDb, DatabaseDefinition newDb, String
this.searchIndexDifferences =
Maps.difference(originalDb.searchIndexes(), newDb.searchIndexes());
this.schemaDifferences = Maps.difference(originalDb.schemas(), newDb.schemas());
this.viewDifferences = Maps.difference(originalDb.views(), newDb.views());

if (!alterDatabaseOptionsDifferences.areEqual() && Strings.isNullOrEmpty(databaseName)) {
// should never happen, but...
Expand Down Expand Up @@ -197,6 +200,17 @@ public List<String> generateDifferenceStatements(Map<String, Boolean> options)
}
}

// Drop views in original order
for (String viewName : originalDb.views().keySet().asList().reverse()) {
if (viewDifferences.entriesDiffering().containsKey(viewName)) {
LOG.info( "Dropping changed view for re-creation: {}", viewName);
output.add("DROP VIEW " + viewName);
} else if (options.get(ALLOW_DROP_STATEMENTS_OPT) && viewDifferences.entriesOnlyOnLeft().containsKey(viewName)){
LOG.info( "Dropping deleted view: {}", viewName);
output.add("DROP VIEW " + viewName);
}
}

// drop deleted search indexes.
if (options.get(ALLOW_DROP_STATEMENTS_OPT)) {
for (String searchIndexName : searchIndexDifferences.entriesOnlyOnLeft().keySet()) {
Expand Down Expand Up @@ -424,7 +438,16 @@ public List<String> generateDifferenceStatements(Map<String, Boolean> options)
// For each changed search index, apply the add column statements
output.addAll(searchIndexUpdateStatements.createStatements());

// Add all new search indexes
// Create or alter views in new order.
for (ASTcreate_view_statement view : newDb.views().values()) {
if (viewDifferences.entriesOnlyOnRight().containsKey(view.getName())) {
LOG.info("Creating new view: {}", view.getName());
output.add("CREATE OR REPLACE " + view.toStringBase());
} else if (viewDifferences.entriesDiffering().containsKey(view.getName())) {
LOG.info("Re-creating new view: {}", view.getName());
output.add("CREATE OR REPLACE " + view.toStringBase());
}
}

return output.build();
}
Expand Down Expand Up @@ -813,6 +836,7 @@ public static List<ASTddl_statement> parseDdl(String original, boolean parseAnno
break;
case DdlParserTreeConstants.JJTCREATE_INDEX_STATEMENT:
case DdlParserTreeConstants.JJTALTER_DATABASE_STATEMENT:
case DdlParserTreeConstants.JJTCREATE_VIEW_STATEMENT:
case DdlParserTreeConstants.JJTCREATE_CHANGE_STREAM_STATEMENT:
case DdlParserTreeConstants.JJTCREATE_SEARCH_INDEX_STATEMENT:
// no-op - allowed
Expand All @@ -823,6 +847,7 @@ public static List<ASTddl_statement> parseDdl(String original, boolean parseAnno
.getSchemaObject()
.getId()) {
case DdlParserTreeConstants.JJTCREATE_SCHEMA_STATEMENT:
case DdlParserTreeConstants.JJTCREATE_VIEW_STATEMENT:
// no-op - allowed
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,60 @@
*/
package com.google.cloud.solutions.spannerddl.parser;

// TODO
import com.google.cloud.solutions.spannerddl.diff.AstTreeUtils;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;

public class ASTcreate_view_statement extends SimpleNode {
public ASTcreate_view_statement(int id) {
super(id);
throw new UnsupportedOperationException("Not Implemented");
}

public ASTcreate_view_statement(DdlParser p, int id) {
super(p, id);
throw new UnsupportedOperationException("Not Implemented");
}

public String toStringBase() {
validateChildren();
return Joiner.on(" ")
.skipNulls()
.join(
"VIEW",
getName(),
"SQL SECURITY",
AstTreeUtils.tokensToString(AstTreeUtils.getOptionalChildByType(children, ASTsql_security.class)),
"AS",
AstTreeUtils.tokensToString(AstTreeUtils.getOptionalChildByType(children, ASTview_definition.class))
);
}

private void validateChildren() {
AstTreeUtils.validateChildrenClasses(
children, ImmutableSet.of(ASTname.class, ASTsql_security.class, ASTview_definition.class));
}

public String getName() {
return AstTreeUtils.tokensToString(AstTreeUtils.getChildByType(children, ASTname.class), false);
}

@Override
public String toString() {
return Joiner.on(" ")
.skipNulls()
.join(
"CREATE",
toStringBase()
);
}


@Override
public boolean equals(Object obj) {
return (obj instanceof ASTcreate_view_statement) && toString().equals(obj.toString());
}

@Override
public int hashCode() {
return toString().hashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ public void compareDddTextFiles() throws IOException {
".*DROP (SCHEMA|TABLE|COLUMN|CHANGE STREAM|SEARCH INDEX).*"))
.collect(Collectors.toList());

// remove any drop views from the expectedResults if they do not have an equivalent
// CREATE statement. This is because we are allowing recreation of views, but not allowing
// dropping of removed views.
for (String statement : expectedDiff) {
if (statement.startsWith("DROP VIEW ")) {
String viewName = Iterables.get(Splitter.on(' ').split(statement), 2);
// see if there is a matching create statement
Pattern p = Pattern.compile("CREATE .*VIEW " + viewName + " ");
if (expectedDiffNoDrops.stream().noneMatch(s -> p.matcher(s).find())) {
expectedDiffNoDrops.remove(statement);
}
}
}

// remove any drop indexes from the expectedResults if they do not have an equivalent
// CREATE statement. This is because we are allowing recreation of indexes, but not allowing
// dropping of removed indexes.
Expand Down
22 changes: 1 addition & 21 deletions src/test/resources/ddlParserUnsupported.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ ALTER TABLE Albums DROP ROW DELETION POLICY
ALTER TABLE Albums
REPLACE ROW DELETION POLICY (OLDER_THAN(timestamp_column, INTERVAL 1 DAY))

== Test 3

CREATE OR REPLACE VIEW test1 SQL SECURITY INVOKER AS SELECT * from test2

== Test 4

CREATE VIEW test1 SQL SECURITY INVOKER AS SELECT * from test2

== Test 6

drop change stream test1
Expand Down Expand Up @@ -68,18 +60,6 @@ GRANT SELECT ON TABLE table_list TO ROLE role_list

REVOKE SELECT ON TABLE table_list TO ROLE role_list

== Test 12a // TODO views

CREATE VIEW view_name AS query

== Test 12b drop view not supported

DROP VIEW view_name

== Test 13 // TODO views

CREATE OR REPLACE VIEW view_name AS query

== Test 14a // TODO sequences

CREATE SEQUENCE IF NOT EXISTS sequence_name OPTIONS ( sequence_kind='bit_reversed_positive' )
Expand Down Expand Up @@ -163,4 +143,4 @@ ALTER SEARCH INDEX AlbumsIndex ADD STORED COLUMN test

ALTER SEARCH INDEX AlbumsIndex ADD COLUMN add_token_column

==
==
28 changes: 27 additions & 1 deletion src/test/resources/expectedDdlDiff.txt
Original file line number Diff line number Diff line change
Expand Up @@ -350,4 +350,30 @@ DROP SCHEMA schema2
CREATE SCHEMA schema3
CREATE TABLE schema3.table1 ( col1 INT64 ) PRIMARY KEY (col1 ASC)

==
== TEST 68 Create view with/without named schama

CREATE SCHEMA schema1
CREATE TABLE input ( PK INT64 ) PRIMARY KEY (PK ASC)
CREATE TABLE schema1.input ( PK INT64 ) PRIMARY KEY (PK ASC)
CREATE OR REPLACE VIEW preprocess SQL SECURITY INVOKER AS SELECT t.PK, 1 AS n FROM INPUT AS t
CREATE OR REPLACE VIEW final SQL SECURITY INVOKER AS SELECT v.PK, v.n, "foo" AS s FROM preprocess AS v
CREATE OR REPLACE VIEW schema1.preprocess SQL SECURITY INVOKER AS SELECT t.PK, 1 AS n FROM schema1.INPUT AS t
CREATE OR REPLACE VIEW schema1.final SQL SECURITY INVOKER AS SELECT v.PK, v.n, "foo" AS s FROM schema1.preprocess AS v


== TEST 69 Replace view with dependencies

DROP VIEW final
DROP VIEW preprocess
DROP INDEX inputByCol
ALTER TABLE input DROP COLUMN col1
ALTER TABLE input ADD COLUMN col2 INT64
CREATE INDEX inputByCol ON INPUT ( col2 ASC )
CREATE OR REPLACE VIEW preprocess SQL SECURITY INVOKER AS SELECT t.pk, t.col2, 1 AS n FROM INPUT AS t
CREATE OR REPLACE VIEW final SQL SECURITY INVOKER AS SELECT v.PK, v.col2, v.n, "foo" AS s FROM preprocess AS v

== TEST 70 Dropping view

DROP VIEW view2

==
49 changes: 48 additions & 1 deletion src/test/resources/newDdl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -563,4 +563,51 @@ CREATE TABLE schema3.table1 (
col1 INT64,
)PRIMARY KEY (col1);

==
== TEST 68 Create view with/without named schama

CREATE TABLE input (
PK INT64
) PRIMARY KEY (PK);
CREATE OR REPLACE VIEW preprocess
SQL SECURITY INVOKER
AS SELECT t.PK, 1 AS n
FROM input AS t;
CREATE OR REPLACE VIEW final
SQL SECURITY INVOKER
AS SELECT v.PK, v.n, "foo" AS s
FROM preprocess AS v;
CREATE SCHEMA schema1;
CREATE TABLE schema1.input (PK INT64) PRIMARY KEY (PK);
CREATE OR REPLACE VIEW schema1.preprocess
SQL SECURITY INVOKER
AS SELECT t.PK, 1 AS n
FROM schema1.input AS t;
CREATE OR REPLACE VIEW schema1.final
SQL SECURITY INVOKER
AS SELECT v.PK, v.n, "foo" AS s
FROM schema1.preprocess AS v;

== TEST 69 Replace view with dependencies

CREATE TABLE input (
pk INT64,
col2 INT64
) PRIMARY KEY (pk);

CREATE INDEX inputByCol ON input (col2);

CREATE OR REPLACE VIEW preprocess
SQL SECURITY INVOKER
AS SELECT t.pk, t.col2, 1 AS n
FROM input AS t;

CREATE OR REPLACE VIEW final
SQL SECURITY INVOKER
AS SELECT v.PK, v.col2, v.n, "foo" AS s
FROM preprocess AS v;

== TEST 70 Dropping view

CREATE VIEW view1 SQL SECURITY INVOKER AS SELECT * from test1;

==
30 changes: 29 additions & 1 deletion src/test/resources/originalDdl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -561,4 +561,32 @@ CREATE TABLE schema2.table1 (
)PRIMARY KEY (col1);


==
== TEST 68 Create view with/without named schama

-- nothing

== TEST 69 Replace view with dependencies

CREATE TABLE input (
pk INT64,
col1 INT64
) PRIMARY KEY (pk);

CREATE INDEX inputByCol ON input (col1);

CREATE OR REPLACE VIEW preprocess
SQL SECURITY INVOKER
AS SELECT t.pk, t.col1, 1 AS n
FROM input AS t;

CREATE OR REPLACE VIEW final
SQL SECURITY INVOKER
AS SELECT v.PK, v.col1, v.n, "foo" AS s
FROM preprocess AS v;

== TEST 70 Dropping view

CREATE VIEW view1 SQL SECURITY INVOKER AS SELECT * FROM test1;
CREATE OR REPLACE VIEW view2 SQL SECURITY DEFINER AS SELECT * FROM test2;

==