org.junit.jupiter
junit-jupiter-engine
diff --git a/zetasql-toolkit-core/src/main/antlr4/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeGrammar.g4 b/zetasql-toolkit-core/src/main/antlr4/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeGrammar.g4
index 918766a..333055d 100644
--- a/zetasql-toolkit-core/src/main/antlr4/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeGrammar.g4
+++ b/zetasql-toolkit-core/src/main/antlr4/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeGrammar.g4
@@ -34,24 +34,53 @@ BASIC_TYPE: STRING
| GEOGRAPHY
| JSON;
-STRING: 'STRING';
-BYTES: 'BYTES';
-INT32: 'INT32';
-INT64: 'INT64';
-UINT32: 'UINT32';
-UINT64: 'UINT64';
-FLOAT64: 'FLOAT64';
-DECIMAL: 'DECIMAL';
-NUMERIC: 'NUMERIC';
-BIGNUMERIC: 'BIGNUMERIC';
-INTERVAL: 'INTERVAL';
-BOOL: 'BOOL';
-TIMESTAMP: 'TIMESTAMP';
-DATE: 'DATE';
-TIME: 'TIME';
-DATETIME: 'DATETIME';
-GEOGRAPHY: 'GEOGRAPHY';
-JSON: 'JSON';
+STRING: S T R I N G;
+BYTES: B Y T E S;
+INT32: I N T THIRTYTWO;
+INT64: I N T SIXTYFOUR;
+UINT32: U I N T THIRTYTWO;
+UINT64: U I N T SIXTYFOUR;
+FLOAT64: F L O A T SIXTYFOUR;
+DECIMAL: D E C I M A L;
+NUMERIC: N U M E R I C;
+BIGNUMERIC: B I G N U M E R I C;
+INTERVAL: I N T E R V A L;
+BOOL: B O O L;
+TIMESTAMP: T I M E S T A M P;
+DATE: D A T E;
+TIME: T I M E;
+DATETIME: D A T E T I M E;
+GEOGRAPHY: G E O G R A P H Y;
+JSON: J S O N;
IDENTIFIER: [A-Za-z_][A-Za-z0-9_]*;
NUMBER: [1-9][0-9]*;
+
+fragment THIRTYTWO: '32';
+fragment SIXTYFOUR: '64';
+fragment A: [aA];
+fragment B: [bB];
+fragment C: [cC];
+fragment D: [dD];
+fragment E: [eE];
+fragment F: [fF];
+fragment G: [gG];
+fragment H: [hH];
+fragment I: [iI];
+fragment J: [jJ];
+fragment K: [kK];
+fragment L: [lL];
+fragment M: [mM];
+fragment N: [nN];
+fragment O: [oO];
+fragment P: [pP];
+fragment Q: [qQ];
+fragment R: [rR];
+fragment S: [sS];
+fragment T: [tT];
+fragment U: [uU];
+fragment V: [vV];
+fragment W: [wW];
+fragment X: [xX];
+fragment Y: [yY];
+fragment Z: [zZ];
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/SimpleCatalogUtil.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/SimpleCatalogUtil.java
new file mode 100644
index 0000000..15eefe1
--- /dev/null
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/SimpleCatalogUtil.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 Google LLC All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zetasql;
+
+/**
+ * Only public to make it possible to copy the SimpleCatalog
+ */
+public class SimpleCatalogUtil {
+ public static SimpleCatalog copyCatalog(SimpleCatalog sourceCatalog) {
+ // Simply serializes and deserializes the source catalog to create a copy.
+ // This is the most reliable way of creating a copy of a SimpleCatalog,
+ // as the SimpleCatalog's public interface does not expose enough of the internal
+ // structures to create an accurate copy.
+ FileDescriptorSetsBuilder fileDescriptorSetsBuilder = new FileDescriptorSetsBuilder();
+ SimpleCatalogProtos.SimpleCatalogProto serialized = sourceCatalog.serialize(fileDescriptorSetsBuilder);
+ return SimpleCatalog.deserialize(serialized, fileDescriptorSetsBuilder.getDescriptorPools());
+ }
+}
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/StatementRewriter.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/StatementRewriter.java
new file mode 100644
index 0000000..2d66780
--- /dev/null
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/StatementRewriter.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright 2023 Google LLC All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zetasql.toolkit;
+
+import com.google.zetasql.parser.ASTNode;
+import com.google.zetasql.parser.ASTNodes.ASTAlterAllRowAccessPoliciesStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterApproxViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterDatabaseStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterEntityStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterMaterializedViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterModelStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterPrivilegeRestrictionStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterRowAccessPolicyStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterSchemaStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterTableStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAlterViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTAuxLoadDataStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCallStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCloneDataSource;
+import com.google.zetasql.parser.ASTNodes.ASTCloneDataStatement;
+import com.google.zetasql.parser.ASTNodes.ASTConnectionClause;
+import com.google.zetasql.parser.ASTNodes.ASTCopyDataSource;
+import com.google.zetasql.parser.ASTNodes.ASTCreateApproxViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateConstantStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateDatabaseStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateEntityStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateExternalTableStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateIndexStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateMaterializedViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateModelStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreatePrivilegeRestrictionStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateProcedureStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateRowAccessPolicyStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateSchemaStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateSnapshotStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateSnapshotTableStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateTableStatement;
+import com.google.zetasql.parser.ASTNodes.ASTCreateViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDefineTableStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDescribeStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropAllRowAccessPoliciesStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropEntityStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropFunctionStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropMaterializedViewStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropPrivilegeRestrictionStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropRowAccessPolicyStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropSearchIndexStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropSnapshotTableStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropTableFunctionStatement;
+import com.google.zetasql.parser.ASTNodes.ASTDropVectorIndexStatement;
+import com.google.zetasql.parser.ASTNodes.ASTExportMetadataStatement;
+import com.google.zetasql.parser.ASTNodes.ASTExportModelStatement;
+import com.google.zetasql.parser.ASTNodes.ASTForeignKeyReference;
+import com.google.zetasql.parser.ASTNodes.ASTFunctionCall;
+import com.google.zetasql.parser.ASTNodes.ASTFunctionDeclaration;
+import com.google.zetasql.parser.ASTNodes.ASTGrantStatement;
+import com.google.zetasql.parser.ASTNodes.ASTIdentifier;
+import com.google.zetasql.parser.ASTNodes.ASTImportStatement;
+import com.google.zetasql.parser.ASTNodes.ASTMergeStatement;
+import com.google.zetasql.parser.ASTNodes.ASTModelClause;
+import com.google.zetasql.parser.ASTNodes.ASTModuleStatement;
+import com.google.zetasql.parser.ASTNodes.ASTPathExpression;
+import com.google.zetasql.parser.ASTNodes.ASTRenameStatement;
+import com.google.zetasql.parser.ASTNodes.ASTRenameToClause;
+import com.google.zetasql.parser.ASTNodes.ASTRevokeStatement;
+import com.google.zetasql.parser.ASTNodes.ASTSequenceArg;
+import com.google.zetasql.parser.ASTNodes.ASTShowStatement;
+import com.google.zetasql.parser.ASTNodes.ASTSpannerInterleaveClause;
+import com.google.zetasql.parser.ASTNodes.ASTStatement;
+import com.google.zetasql.parser.ASTNodes.ASTSystemVariableExpr;
+import com.google.zetasql.parser.ASTNodes.ASTTVF;
+import com.google.zetasql.parser.ASTNodes.ASTTableAndColumnInfo;
+import com.google.zetasql.parser.ASTNodes.ASTTableClause;
+import com.google.zetasql.parser.ASTNodes.ASTTablePathExpression;
+import com.google.zetasql.parser.ASTNodes.ASTTruncateStatement;
+import com.google.zetasql.parser.ASTNodes.ASTUndropStatement;
+import com.google.zetasql.parser.ParseTreeVisitor;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Implements query-level rewrites based on the parsed tree. It allows modifying the query text
+ * after parsing but before analyzing.
+ *
+ * These rewrites are done at the query level because the parsed tree is immutable and can't
+ * be modified itself.
+ */
+class StatementRewriter {
+
+ /**
+ * Rewrites the query text to ensure all resource name paths present in a parsed statement from
+ * said query are quoted entirely. For example, it rewrites "FROM project.dataset.table" to "FROM
+ * `project.dataset.table`".
+ *
+ *
To do so; it finds all {@link ASTPathExpression} nodes in the parse tree refer to a
+ * resource (i.e. tables, functions, etc.), builds their fully quoted representation and replaces
+ * their original text in the query with their quoted representation.
+ *
+ * @param query The original query text the statement was parsed from
+ * @param parsedStatement The parsed statement for which to rewrite name paths
+ * @return The rewritten version of the query
+ */
+ public static String quoteNamePaths(String query, ASTStatement parsedStatement) {
+ List pathExpressions =
+ getResourcePathExpressionFromParseTree(parsedStatement).stream()
+ .sorted(Comparator.comparing(expression -> expression.getParseLocationRange().start()))
+ .collect(Collectors.toList());
+
+ StringBuilder builder = new StringBuilder(query);
+
+ int rewritingOffset = 0;
+ for (ASTPathExpression pathExpression : pathExpressions) {
+ int startPosition = pathExpression.getParseLocationRange().start();
+ int endPosition = pathExpression.getParseLocationRange().end();
+
+ String originalNamePath = query.substring(startPosition, endPosition);
+ String quotedNamePath = buildQuotedNamePath(pathExpression);
+
+ int rewriteStartPosition = startPosition + rewritingOffset;
+ int rewriteEndPosition = endPosition + rewritingOffset;
+
+ builder.replace(rewriteStartPosition, rewriteEndPosition, quotedNamePath);
+
+ rewritingOffset += (quotedNamePath.length() - originalNamePath.length());
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns the fully quoted string representation of an {@link ASTPathExpression}.
+ *
+ * @param pathExpression The path expression for which to build the fully quoted
+ * representation
+ * @return The fully quoted representation of the path expression
+ */
+ private static String buildQuotedNamePath(ASTPathExpression pathExpression) {
+ String fullName = pathExpression.getNames()
+ .stream()
+ .map(ASTIdentifier::getIdString)
+ .collect(Collectors.joining("."));
+ return "`" + fullName + "`";
+ }
+
+ /**
+ * Extracts all {@link ASTPathExpression} nodes that refer to a resource
+ * (i.e. tables, functions, etc.) from a parse tree
+ *
+ * @param tree The parse tree
+ * @return The list of all {@link ASTPathExpression} in the tree that refer to a resource
+ */
+ private static List getResourcePathExpressionFromParseTree(ASTNode tree) {
+ ArrayList result = new ArrayList<>();
+
+ tree.accept(new ParseTreeVisitor() {
+
+ public void visit(ASTTablePathExpression node) {
+ result.add(node.getPathExpr());
+ }
+
+ public void visit(ASTFunctionCall node) {
+ result.add(node.getFunction());
+ super.visit(node);
+ }
+
+ public void visit(ASTSequenceArg node) {
+ result.add(node.getSequencePath());
+ }
+
+ public void visit(ASTDescribeStatement node) {
+ result.add(node.getName());
+ if (node.getOptionalFromName() != null) {
+ result.add(node.getOptionalFromName());
+ }
+ super.visit(node);
+ }
+
+ public void visit(ASTShowStatement node) {
+ result.add(node.getOptionalName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropEntityStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropFunctionStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropTableFunctionStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropAllRowAccessPoliciesStatement node) {
+ result.add(node.getTableName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropMaterializedViewStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropSnapshotTableStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropSearchIndexStatement node) {
+ result.add(node.getName());
+ result.add(node.getTableName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropVectorIndexStatement node) {
+ result.add(node.getName());
+ result.add(node.getTableName());
+ super.visit(node);
+ }
+
+ public void visit(ASTRenameStatement node) {
+ result.add(node.getOldName());
+ result.add(node.getNewName());
+ super.visit(node);
+ }
+
+ public void visit(ASTImportStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTModuleStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTSystemVariableExpr node) {
+ result.add(node.getPath());
+ }
+
+ public void visit(ASTFunctionDeclaration node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTTVF node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTTableClause node) {
+ result.add(node.getTablePath());
+ super.visit(node);
+ }
+
+ public void visit(ASTModelClause node) {
+ result.add(node.getModelPath());
+ }
+
+ public void visit(ASTConnectionClause node) {
+ result.add(node.getConnectionPath());
+ }
+
+ public void visit(ASTCloneDataSource node) {
+ result.add(node.getPathExpr());
+ super.visit(node);
+ }
+
+ public void visit(ASTCopyDataSource node) {
+ result.add(node.getPathExpr());
+ super.visit(node);
+ }
+
+ public void visit(ASTCloneDataStatement node) {
+ result.add(node.getTargetPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateConstantStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateDatabaseStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateProcedureStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateSchemaStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateModelStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateIndexStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTExportModelStatement node) {
+ result.add(node.getModelNamePath());
+ super.visit(node);
+ }
+
+ public void visit(ASTExportMetadataStatement node) {
+ result.add(node.getNamePath());
+ super.visit(node);
+ }
+
+ public void visit(ASTCallStatement node) {
+ result.add(node.getProcedureName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDefineTableStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateSnapshotStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateSnapshotTableStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTTableAndColumnInfo node) {
+ result.add(node.getTableName());
+ super.visit(node);
+ }
+
+ public void visit(ASTTruncateStatement node) {
+ result.add(node.getTargetPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTMergeStatement node) {
+ result.add(node.getTargetPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTGrantStatement node) {
+ result.add(node.getTargetPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTRevokeStatement node) {
+ result.add(node.getTargetPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTRenameToClause node) {
+ result.add(node.getNewName());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterAllRowAccessPoliciesStatement node) {
+ result.add(node.getTableNamePath());
+ super.visit(node);
+ }
+
+ public void visit(ASTForeignKeyReference node) {
+ result.add(node.getTableName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateEntityStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropPrivilegeRestrictionStatement node) {
+ result.add(node.getNamePath());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropRowAccessPolicyStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreatePrivilegeRestrictionStatement node) {
+ result.add(node.getNamePath());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateRowAccessPolicyStatement node) {
+ result.add(node.getName());
+ result.add(node.getTargetPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTDropStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateTableStatement node) {
+ result.add(node.getName());
+ if (node.getLikeTableName() != null) {
+ result.add(node.getLikeTableName());
+ }
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateExternalTableStatement node) {
+ result.add(node.getName());
+ if (node.getLikeTableName() != null) {
+ result.add(node.getLikeTableName());
+ }
+ super.visit(node);
+ }
+
+ public void visit(ASTAuxLoadDataStatement node) {
+ result.add(node.getName());
+ if (node.getLikeTableName() != null) {
+ result.add(node.getLikeTableName());
+ }
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateViewStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateApproxViewStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ public void visit(ASTCreateMaterializedViewStatement node) {
+ result.add(node.getName());
+ if (node.getReplicaSource() != null) {
+ result.add(node.getReplicaSource());
+ }
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterDatabaseStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterSchemaStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterTableStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterViewStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterMaterializedViewStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterApproxViewStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterModelStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterPrivilegeRestrictionStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterRowAccessPolicyStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTAlterEntityStatement node) {
+ result.add(node.getPath());
+ super.visit(node);
+ }
+
+ public void visit(ASTSpannerInterleaveClause node) {
+ result.add(node.getTableName());
+ super.visit(node);
+ }
+
+ public void visit(ASTUndropStatement node) {
+ result.add(node.getName());
+ super.visit(node);
+ }
+
+ });
+
+ return result;
+ }
+
+}
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/ZetaSQLToolkitAnalyzer.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/ZetaSQLToolkitAnalyzer.java
index 077a6f7..b6b95aa 100644
--- a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/ZetaSQLToolkitAnalyzer.java
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/ZetaSQLToolkitAnalyzer.java
@@ -182,7 +182,7 @@ public boolean hasNext() {
*/
@Override
public AnalyzedStatement next() {
- int startLocation = parseResumeLocation.getBytePosition();
+ int startPosition = parseResumeLocation.getBytePosition();
ASTStatement parsedStatement = parseNextStatement(parseResumeLocation);
@@ -206,9 +206,12 @@ public AnalyzedStatement next() {
return new AnalyzedStatement(parsedStatement, Optional.empty());
}
- parseResumeLocation.setBytePosition(startLocation);
+ String rewrittenQuery =
+ StatementRewriter.quoteNamePaths(query, parsedStatement);
+ ParseResumeLocation analysisParseResumeLocation = new ParseResumeLocation(rewrittenQuery);
+ analysisParseResumeLocation.setBytePosition(startPosition);
- ResolvedStatement resolvedStatement = analyzeNextStatement(parseResumeLocation);
+ ResolvedStatement resolvedStatement = analyzeNextStatement(analysisParseResumeLocation);
this.applyCatalogMutation(resolvedStatement);
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/CatalogOperations.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/CatalogOperations.java
index 3a60225..ba8afc3 100644
--- a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/CatalogOperations.java
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/CatalogOperations.java
@@ -23,6 +23,7 @@
import com.google.zetasql.TableValuedFunction.FixedOutputSchemaTVF;
import com.google.zetasql.resolvedast.ResolvedCreateStatementEnums.CreateMode;
import com.google.zetasql.toolkit.catalog.exceptions.CatalogResourceAlreadyExists;
+import com.google.zetasql.toolkit.catalog.exceptions.CatalogResourceDoesNotExist;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -38,13 +39,6 @@
*
*/
public class CatalogOperations {
- // TODO: Probably come up with an abstraction to reduce code repetition in this class.
- // This implementation has a lot of repeated code; namely in methods like
- // validate[Resource]DoesNotExist(), delete[Resource]FromCatalog() and
- // create[Resource]InCatalog().
- // Because of the slightly different ways the SimpleCatalog handles naming for different types of
- // resources,
- // avoiding that repetition is not very straightforward.
private CatalogOperations() {}
@@ -101,21 +95,11 @@ private static boolean functionExists(SimpleCatalog catalog, String fullName) {
.anyMatch(fullNameWithoutGroup::equalsIgnoreCase);
}
- /** Returns true if the Function exists in the SimpleCatalog */
- private static boolean functionExists(SimpleCatalog catalog, Function function) {
- return functionExists(catalog, function.getFullName(false));
- }
-
/** Returns true if the TVF named tvfName exists in the SimpleCatalog */
private static boolean tvfExists(SimpleCatalog catalog, String tvfName) {
return catalog.getTVFNameList().contains(tvfName.toLowerCase());
}
- /** Returns true if the TVF exists in the SimpleCatalog */
- private static boolean tvfExists(SimpleCatalog catalog, TableValuedFunction tvf) {
- return tvfExists(catalog, tvf.getName());
- }
-
/** Returns true if the named procedureName exists in the SimpleCatalog */
private static boolean procedureExists(SimpleCatalog catalog, String procedureName) {
return catalog.getProcedureList().stream()
@@ -123,11 +107,6 @@ private static boolean procedureExists(SimpleCatalog catalog, String procedureNa
.anyMatch(name -> name.equalsIgnoreCase(procedureName));
}
- /** Returns true if the Procedure exists in the SimpleCatalog */
- private static boolean procedureExists(SimpleCatalog catalog, Procedure procedure) {
- return procedureExists(catalog, procedure.getName());
- }
-
/**
* Gets the SimpleCatalog in which a resource should be created, based on the root catalog and the
* resource path.
@@ -154,336 +133,277 @@ private static SimpleCatalog getSubCatalogForResource(
}
/**
- * Checks a table does not exist at any of the provided paths.
+ * Generic function for creating a resource in a {@link SimpleCatalog}
*
- * @param rootCatalog The catalog to look for tables in
- * @param tablePaths The list of paths the table should not be in
- * @param fullTableName The full name of the table we're looking for, used for error reporting
- * @throws CatalogResourceAlreadyExists if a table exists at any of the provided paths
+ * @param nameInCatalog The name the resource will have in the catalog
+ * @param createMode The {@link CreateMode} to use
+ * @param resourceType The resource type name (e.g. "table", "function")
+ * @param alreadyExists Whether the resource already exists
+ * @param creator A {@link Runnable} that will create the resource in the catalog if run
+ * @param deleter A Runnable that will delete the resource from the catalog if run
*/
- private static void validateTableDoesNotExist(
- SimpleCatalog rootCatalog, List> tablePaths, String fullTableName) {
- for (List tablePath : tablePaths) {
- if (tableExists(rootCatalog, tablePath)) {
- String errorMessage =
- String.format(
- "Table %s already exists at path %s", fullTableName, tablePath.toString());
- throw new CatalogResourceAlreadyExists(fullTableName, errorMessage);
- }
+ private static void createResource(
+ String nameInCatalog, CreateMode createMode, String resourceType,
+ boolean alreadyExists, Runnable creator, Runnable deleter
+ ) {
+ if (createMode.equals(CreateMode.CREATE_IF_NOT_EXISTS) && alreadyExists) {
+ return;
}
+
+ if (createMode.equals(CreateMode.CREATE_OR_REPLACE) && alreadyExists) {
+ deleter.run();
+ }
+
+ if (createMode.equals(CreateMode.CREATE_DEFAULT) && alreadyExists) {
+ String errorMessage =
+ String.format(
+ "%s %s already exists in catalog", resourceType, nameInCatalog);
+ throw new CatalogResourceAlreadyExists(nameInCatalog, errorMessage);
+ }
+
+ creator.run();
}
/**
- * Deletes a table from the specified paths in a {@link SimpleCatalog}
+ * Deletes a table with the provided name from {@link SimpleCatalog}
*
- * @param rootCatalog The catalog from which to delete tables
- * @param tablePaths The paths for the table that should be deleted
+ * @param catalog The catalog from which to delete tables
+ * @param name The name for the table in the catalog
+ * @throws CatalogResourceDoesNotExist if the table does not exist in the catalog
*/
- public static void deleteTableFromCatalog(
- SimpleCatalog rootCatalog, List> tablePaths) {
- for (List tablePath : tablePaths) {
- String tableName = tablePath.get(tablePath.size() - 1);
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, tablePath);
-
- if (tableExists(catalog, tableName)) {
- catalog.removeSimpleTable(tableName);
- }
+ public static void deleteTableFromCatalog(SimpleCatalog catalog, String name) {
+ if (!tableExists(catalog, name)) {
+ String errorMessage = String.format("Tried to delete table which does not exist: %s", name);
+ throw new CatalogResourceDoesNotExist(name, errorMessage);
}
+
+ catalog.removeSimpleTable(name);
}
/**
- * Creates a table in a SimpleCatalog using the provided paths and complying with the provided
- * CreateMode.
+ * Creates a table in a {@link SimpleCatalog} using the provided paths and complying with
+ * the provided CreateMode.
*
- * @param rootCatalog The root SimpleCatalog in which to create the table.
- * @param tablePaths The table paths to create the table at. If multiple paths are provided,
- * multiple copies of the table will be registered in the catalog.
- * @param fullTableName The full name of the table to create.
- * @param columns The list of columns for the table
+ * @param catalog The catalog in which to create the table
+ * @param nameInCatalog The name under which the table will be registered in the catalog
+ * @param table The {@link SimpleTable} object representing the table
* @param createMode The CreateMode to use
* @throws CatalogResourceAlreadyExists if the table already exists at any of the provided paths
* and CreateMode != CREATE_OR_REPLACE.
*/
public static void createTableInCatalog(
- SimpleCatalog rootCatalog,
- List> tablePaths,
- String fullTableName,
- List columns,
+ SimpleCatalog catalog,
+ String nameInCatalog,
+ SimpleTable table,
CreateMode createMode) {
- if (createMode.equals(CreateMode.CREATE_OR_REPLACE)) {
- deleteTableFromCatalog(rootCatalog, tablePaths);
- }
-
- if (createMode.equals(CreateMode.CREATE_DEFAULT)) {
- validateTableDoesNotExist(rootCatalog, tablePaths, fullTableName);
- }
+ boolean alreadyExists = tableExists(catalog, nameInCatalog);
- SimpleTable table = new SimpleTable(fullTableName, columns);
- table.setFullName(fullTableName);
-
- for (List tablePath : tablePaths) {
- String tableName = tablePath.get(tablePath.size() - 1);
- SimpleCatalog catalogForCreation = getSubCatalogForResource(rootCatalog, tablePath);
-
- if (!tableExists(catalogForCreation, tableName)) {
- catalogForCreation.addSimpleTable(tableName, table);
- }
- }
+ createResource(
+ nameInCatalog,
+ createMode,
+ "Table",
+ alreadyExists,
+ /*creator=*/ () -> catalog.addSimpleTable(nameInCatalog, table),
+ /*deleter=*/ () -> deleteTableFromCatalog(catalog, nameInCatalog)
+ );
}
/**
- * Checks a function does not exist at any of the provided paths.
+ * Deletes a function with the provided name from the {@link SimpleCatalog}
*
- * @param rootCatalog The catalog to look for functions in
- * @param functionPaths The list of paths the function should not be in
- * @param functionFullName The full name of the function we're looking for, only used for error
- * reporting
- * @throws CatalogResourceAlreadyExists if a function exists at any of the provided paths
+ * @param catalog The catalog from which to delete the function
+ * @param fullName The full name of the function in the catalog
+ * @throws CatalogResourceDoesNotExist if the function does not exist in the catalog
*/
- private static void validateFunctionDoesNotExist(
- SimpleCatalog rootCatalog, List> functionPaths, String functionFullName) {
- for (List functionPath : functionPaths) {
- String functionNameInCatalog = functionPath.get(functionPath.size() - 1);
-
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, functionPath);
+ public static void deleteFunctionFromCatalog(SimpleCatalog catalog, String fullName) {
+ String fullNameWithoutGroup = removeGroupFromFunctionName(fullName);
- if (functionExists(catalog, functionNameInCatalog)) {
- throw new CatalogResourceAlreadyExists(functionFullName);
- }
- }
- }
+ Optional fullNameToDelete =
+ catalog.getFunctionNameList().stream()
+ .filter(
+ name ->
+ removeGroupFromFunctionName(name).equalsIgnoreCase(fullNameWithoutGroup))
+ .findFirst();
- /**
- * Deletes a function from the specified paths in a {@link SimpleCatalog}
- *
- * @param rootCatalog The catalog from which to delete functions
- * @param functionPaths The paths for the function that should be deleted
- */
- public static void deleteFunctionFromCatalog(
- SimpleCatalog rootCatalog, List> functionPaths) {
- for (List functionPath : functionPaths) {
- String functionNameInCatalog = functionPath.get(functionPath.size() - 1);
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, functionPath);
-
- if (functionExists(catalog, functionNameInCatalog)) {
- Optional fullNameToDelete =
- catalog.getFunctionNameList().stream()
- .filter(
- fullName ->
- removeGroupFromFunctionName(fullName)
- .equalsIgnoreCase(functionNameInCatalog))
- .findFirst();
- fullNameToDelete.ifPresent(catalog::removeFunction);
- }
+ if (fullNameToDelete.isPresent()) {
+ catalog.removeFunction(fullNameToDelete.get());
+ } else {
+ String errorMessage = String.format(
+ "Tried to delete function which does not exist: %s", fullName);
+ throw new CatalogResourceDoesNotExist(fullName, errorMessage);
}
}
/**
- * Creates a function in a SimpleCatalog using the provided paths and complying with the provided
- * CreateMode.
+ * Creates a function in a {@link SimpleCatalog} using the provided paths and complying with the
+ * provided CreateMode.
*
- * @param rootCatalog The root SimpleCatalog in which to create the function.
- * @param functionPaths The function paths to create the function at. If multiple paths are
- * provided, multiple copies of the function will be registered in the catalog.
- * @param functionInfo The FunctionInfo object representing the function that should be created
+ * @param catalog The catalog in which to create the function
+ * @param nameInCatalog The name under which the function will be registered in the catalog
+ * @param functionInfo The {@link FunctionInfo} object representing the function that
+ * should be created
* @param createMode The CreateMode to use
* @throws CatalogResourceAlreadyExists if the function already exists at any of the provided
* paths and CreateMode != CREATE_OR_REPLACE.
*/
public static void createFunctionInCatalog(
- SimpleCatalog rootCatalog,
- List> functionPaths,
+ SimpleCatalog catalog,
+ String nameInCatalog,
FunctionInfo functionInfo,
CreateMode createMode) {
- if (createMode.equals(CreateMode.CREATE_OR_REPLACE)) {
- deleteFunctionFromCatalog(rootCatalog, functionPaths);
- }
-
- if (createMode.equals(CreateMode.CREATE_DEFAULT)) {
- validateFunctionDoesNotExist(
- rootCatalog, functionPaths, String.join(".", functionInfo.getNamePath()));
- }
-
- for (List functionPath : functionPaths) {
- String functionName = functionPath.get(functionPath.size() - 1);
- SimpleCatalog catalogForCreation = getSubCatalogForResource(rootCatalog, functionPath);
-
- Function finalFunction =
- new Function(
- ImmutableList.of(functionName),
- functionInfo.getGroup(),
- functionInfo.getMode(),
- functionInfo.getSignatures());
-
- if (!functionExists(catalogForCreation, finalFunction)) {
- catalogForCreation.addFunction(finalFunction);
- }
- }
+ boolean alreadyExists = functionExists(catalog, nameInCatalog);
+
+ Function function =
+ new Function(
+ ImmutableList.of(nameInCatalog),
+ functionInfo.getGroup(),
+ functionInfo.getMode(),
+ functionInfo.getSignatures());
+
+ createResource(
+ nameInCatalog,
+ createMode,
+ "Function",
+ alreadyExists,
+ /*creator=*/ () -> catalog.addFunction(function),
+ /*deleter=*/ () -> deleteFunctionFromCatalog(catalog, nameInCatalog)
+ );
}
/**
- * Checks a TVF does not exist at any of the provided paths.
+ * Deletes a TVF with the provided name from the {@link SimpleCatalog}
*
- * @param rootCatalog The catalog to look for functions in
- * @param functionPaths The list of paths the function should not be in
- * @param functionFullName The full name of the function we're looking for, only used for error
- * reporting
- * @throws CatalogResourceAlreadyExists if a function exists at any of the provided paths
+ * @param catalog The catalog from which to delete the function
+ * @param fullName The full name of the function in the catalog
+ * @throws CatalogResourceDoesNotExist if the function does not exist in the catalog
*/
- private static void validateTVFDoesNotExist(
- SimpleCatalog rootCatalog, List> functionPaths, String functionFullName) {
- for (List functionPath : functionPaths) {
- String functionName = functionPath.get(functionPath.size() - 1);
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, functionPath);
-
- if (tvfExists(catalog, functionName)) {
- throw new CatalogResourceAlreadyExists(functionFullName);
- }
+ public static void deleteTVFFromCatalog(SimpleCatalog catalog, String fullName) {
+ if (!tvfExists(catalog, fullName)) {
+ String errorMessage = String.format("Tried to delete TVF which does not exist: %s", fullName);
+ throw new CatalogResourceDoesNotExist(fullName, errorMessage);
}
- }
- /**
- * Deletes a TVF from the specified paths in a {@link SimpleCatalog}
- *
- * @param rootCatalog The catalog from which to delete TVFs
- * @param functionPaths The paths for the TVF that should be deleted
- */
- public static void deleteTVFFromCatalog(
- SimpleCatalog rootCatalog, List> functionPaths) {
- for (List functionPath : functionPaths) {
- String functionName = functionPath.get(functionPath.size() - 1);
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, functionPath);
-
- if (tvfExists(catalog, functionName)) {
- catalog.removeTableValuedFunction(functionName);
- }
- }
+ catalog.removeTableValuedFunction(fullName);
}
/**
- * Creates a TVF in a SimpleCatalog using the provided paths and complying with the provided
- * CreateMode.
+ * Creates a TVF in a {@link SimpleCatalog} using the provided name and complying with the
+ * provided CreateMode.
*
- * @param rootCatalog The root SimpleCatalog in which to create the function.
- * @param functionPaths The function paths to create the TVF at. If multiple paths are provided,
- * multiple copies of the function will be registered in the catalog.
- * @param tvfInfo The TVFInfo object representing the TVF that should be created
+ * @param catalog The catalog in which to create the TVF
+ * @param nameInCatalog The name under which the TVF will be registered in the catalog
+ * @param tvfInfo The {@link TVFInfo} object representing the TVF that should be created
* @param createMode The CreateMode to use
- * @throws CatalogResourceAlreadyExists if the function already exists at any of the provided
+ * @throws CatalogResourceAlreadyExists if the TVF already exists at any of the provided
* paths and CreateMode != CREATE_OR_REPLACE.
*/
public static void createTVFInCatalog(
- SimpleCatalog rootCatalog,
- List> functionPaths,
+ SimpleCatalog catalog,
+ String nameInCatalog,
TVFInfo tvfInfo,
CreateMode createMode) {
Preconditions.checkArgument(
- tvfInfo.getOutputSchema().isPresent(), "Cannot create a a TVF without an output schema");
-
- if (createMode.equals(CreateMode.CREATE_OR_REPLACE)) {
- deleteTVFFromCatalog(rootCatalog, functionPaths);
- }
+ tvfInfo.getOutputSchema().isPresent(),
+ "Cannot create a a TVF without an output schema");
+
+ boolean alreadyExists = tvfExists(catalog, nameInCatalog);
+
+ TableValuedFunction tvf =
+ new FixedOutputSchemaTVF(
+ ImmutableList.of(nameInCatalog),
+ tvfInfo.getSignature(),
+ tvfInfo.getOutputSchema().get());
+
+ createResource(
+ nameInCatalog,
+ createMode,
+ "TVF",
+ alreadyExists,
+ /*creator=*/() -> catalog.addTableValuedFunction(tvf),
+ /*deleter=*/() -> deleteTVFFromCatalog(catalog, nameInCatalog)
+ );
+ }
- if (createMode.equals(CreateMode.CREATE_DEFAULT)) {
- String tvfFullName = String.join(".", tvfInfo.getNamePath());
- validateTVFDoesNotExist(rootCatalog, functionPaths, tvfFullName);
+ private static void deleteProcedureFromCatalogImpl(SimpleCatalog catalog, String fullName) {
+ if (!procedureExists(catalog, fullName)) {
+ String errorMessage = String.format(
+ "Tried to delete procedure which does not exist: %s", fullName);
+ throw new CatalogResourceDoesNotExist(fullName, errorMessage);
}
- for (List functionPath : functionPaths) {
- String functionName = functionPath.get(functionPath.size() - 1);
- SimpleCatalog catalogForCreation = getSubCatalogForResource(rootCatalog, functionPath);
-
- TableValuedFunction tvf =
- new FixedOutputSchemaTVF(
- ImmutableList.of(functionName),
- tvfInfo.getSignature(),
- tvfInfo.getOutputSchema().get());
-
- if (!tvfExists(catalogForCreation, tvf)) {
- catalogForCreation.addTableValuedFunction(tvf);
- }
- }
+ catalog.removeProcedure(fullName);
}
/**
- * Checks a Procedure does not exist at any of the provided paths.
+ * Deletes a procedure with the provided name from the {@link SimpleCatalog}
*
- * @param rootCatalog The catalog to look for procedures in
- * @param procedurePaths The list of paths the procedure should not be in
- * @param procedureFullName The full name of the procedure we're looking for, only used for error
- * reporting
- * @throws CatalogResourceAlreadyExists if a procedure exists at any of the provided paths
- */
- private static void validateProcedureDoesNotExist(
- SimpleCatalog rootCatalog, List> procedurePaths, String procedureFullName) {
- for (List procedurePath : procedurePaths) {
- String procedureName = procedurePath.get(procedurePath.size() - 1);
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, procedurePath);
-
- if (procedureExists(catalog, procedureName)) {
- throw new CatalogResourceAlreadyExists(procedureFullName);
- }
- }
- }
-
- /**
- * Deletes a Procedure from the specified paths in a {@link SimpleCatalog}
+ * Qualified procedures need to be registered two times in the catalog for analysis to
+ * work as expected. This method takes care of deleting both copies of the procedure if necessary.
*
- * @param rootCatalog The catalog from which to delete TVFs
- * @param procedurePaths The paths for the Procedure that should be deleted
+ * @param catalog The catalog from which to delete the procedure
+ * @param fullName The full name of the procedure in the catalog
+ * @throws CatalogResourceDoesNotExist if the procedure does not exist in the catalog
*/
- public static void deleteProcedureFromCatalog(
- SimpleCatalog rootCatalog, List> procedurePaths) {
- for (List procedurePath : procedurePaths) {
- String procedureName = procedurePath.get(procedurePath.size() - 1);
- SimpleCatalog catalog = getSubCatalogForResource(rootCatalog, procedurePath);
-
- if (procedureExists(catalog, procedureName)) {
- catalog.removeProcedure(procedureName);
- }
+ public static void deleteProcedureFromCatalog(SimpleCatalog catalog, String fullName) {
+ deleteProcedureFromCatalogImpl(catalog, fullName);
+
+ if (fullName.contains(".")) {
+ List nameComponents = Arrays.asList(fullName.split("\\."));
+ String nestedName = nameComponents.get(nameComponents.size() - 1);
+ SimpleCatalog nestedCatalog = getSubCatalogForResource(catalog, nameComponents);
+ deleteProcedureFromCatalogImpl(nestedCatalog, nestedName);
}
}
/**
- * Creates a procedure in a SimpleCatalog using the provided paths and complying with the provided
- * CreateMode.
+ * Creates a procedure in a {@link SimpleCatalog} using the provided name and complying with
+ * the provided CreateMode.
*
- * @param rootCatalog The root SimpleCatalog in which to create the procedure.
- * @param procedurePaths The procedure paths to create the procedure at. If multiple paths are
- * provided, multiple copies of the procedure will be registered in the catalog.
+ * Qualified procedures will be registered two times in the catalog for analysis to work as
+ * expected. A procedure with name "project.dataset.table" will be registered at name paths:
+ * ["project.dataset.table"] and ["project", "dataset", "table"].
+ *
+ * @param catalog The SimpleCatalog in which to create the procedure
+ * @param nameInCatalog The name under which the procedure will be registered in the catalog
* @param procedureInfo The ProcedureInfo object representing the procedure that should be created
* @param createMode The CreateMode to use
* @throws CatalogResourceAlreadyExists if the procedure already exists at any of the provided
* paths and CreateMode != CREATE_OR_REPLACE.
*/
public static void createProcedureInCatalog(
- SimpleCatalog rootCatalog,
- List> procedurePaths,
+ SimpleCatalog catalog,
+ String nameInCatalog,
ProcedureInfo procedureInfo,
CreateMode createMode) {
- if (createMode.equals(CreateMode.CREATE_OR_REPLACE)) {
- deleteProcedureFromCatalog(rootCatalog, procedurePaths);
- }
-
- if (createMode.equals(CreateMode.CREATE_DEFAULT)) {
- String procedureFullName = String.join(".", procedureInfo.getNamePath());
- validateProcedureDoesNotExist(rootCatalog, procedurePaths, procedureFullName);
- }
-
- for (List procedurePath : procedurePaths) {
- String procedureName = procedurePath.get(procedurePath.size() - 1);
- SimpleCatalog catalogForCreation = getSubCatalogForResource(rootCatalog, procedurePath);
+ boolean alreadyExists = procedureExists(catalog, nameInCatalog);
+ Runnable creatorFunction = () -> {
Procedure procedure =
- new Procedure(ImmutableList.of(procedureName), procedureInfo.getSignature());
-
- if (!procedureExists(catalogForCreation, procedure)) {
- catalogForCreation.addProcedure(procedure);
+ new Procedure(ImmutableList.of(nameInCatalog), procedureInfo.getSignature());
+ catalog.addProcedure(procedure);
+
+ if (nameInCatalog.contains(".")) {
+ List nameComponents = Arrays.asList(nameInCatalog.split("\\."));
+ String nestedName = nameComponents.get(nameComponents.size() - 1);
+ SimpleCatalog nestedCatalog = getSubCatalogForResource(catalog, nameComponents);
+ Procedure nestedProcedure =
+ new Procedure(ImmutableList.of(nestedName), procedureInfo.getSignature());
+ nestedCatalog.addProcedure(nestedProcedure);
}
- }
+ };
+
+ createResource(
+ nameInCatalog,
+ createMode,
+ "Procedure",
+ alreadyExists,
+ /*creator=*/ creatorFunction,
+ /*deleter=*/ () -> deleteProcedureFromCatalog(catalog, nameInCatalog)
+ );
+
}
/**
@@ -493,11 +413,6 @@ public static void createProcedureInCatalog(
* @return The copy of the provided SimpleCatalog.
*/
public static SimpleCatalog copyCatalog(SimpleCatalog sourceCatalog) {
- // Simply serializes and deserializes the source catalog to create a copy.
- // This is the most reliable way of creating a copy of a SimpleCatalog,
- // as the SimpleCatalog's public interface does not expose enough of the internal
- // structures to create an accurate copy.
- SimpleCatalogProto serialized = sourceCatalog.serialize(new FileDescriptorSetsBuilder());
- return SimpleCatalog.deserialize(serialized, ImmutableList.of());
+ return SimpleCatalogUtil.copyCatalog(sourceCatalog);
}
}
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/basic/BasicCatalogWrapper.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/basic/BasicCatalogWrapper.java
index 4e5f660..f04ffe7 100644
--- a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/basic/BasicCatalogWrapper.java
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/basic/BasicCatalogWrapper.java
@@ -16,11 +16,12 @@
package com.google.zetasql.toolkit.catalog.basic;
-import com.google.common.collect.ImmutableList;
import com.google.zetasql.Constant;
+import com.google.zetasql.LanguageOptions;
import com.google.zetasql.SimpleCatalog;
import com.google.zetasql.SimpleTable;
import com.google.zetasql.ZetaSQLBuiltinFunctionOptions;
+import com.google.zetasql.ZetaSQLOptions.LanguageFeature;
import com.google.zetasql.resolvedast.ResolvedCreateStatementEnums.CreateMode;
import com.google.zetasql.resolvedast.ResolvedCreateStatementEnums.CreateScope;
import com.google.zetasql.toolkit.catalog.CatalogOperations;
@@ -30,10 +31,8 @@
import com.google.zetasql.toolkit.catalog.TVFInfo;
import com.google.zetasql.toolkit.catalog.exceptions.CatalogException;
import com.google.zetasql.toolkit.catalog.exceptions.CatalogResourceAlreadyExists;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
/**
* Basic implementation of CatalogWrapper which does not implement the semantics of any particular
@@ -43,9 +42,17 @@ public class BasicCatalogWrapper implements CatalogWrapper {
private final SimpleCatalog catalog;
+ private static final LanguageOptions languageOptionsForFunctionsAndTypes = new LanguageOptions();
+
+ static {
+ Arrays.stream(LanguageFeature.values())
+ .forEach(languageOptionsForFunctionsAndTypes::enableLanguageFeature);
+ }
+
public BasicCatalogWrapper() {
this.catalog = new SimpleCatalog("catalog");
- this.catalog.addZetaSQLFunctionsAndTypes(new ZetaSQLBuiltinFunctionOptions());
+ this.catalog.addZetaSQLFunctionsAndTypes(
+ new ZetaSQLBuiltinFunctionOptions(languageOptionsForFunctionsAndTypes));
}
public BasicCatalogWrapper(SimpleCatalog initialCatalog) {
@@ -59,24 +66,19 @@ public BasicCatalogWrapper(SimpleCatalog initialCatalog) {
*/
@Override
public void register(SimpleTable table, CreateMode createMode, CreateScope createScope) {
- CatalogOperations.createTableInCatalog(
- this.catalog,
- ImmutableList.of(ImmutableList.of(table.getFullName())),
- table.getFullName(),
- table.getColumnList(),
- createMode);
+ CatalogOperations.createTableInCatalog(this.catalog, table.getFullName(), table, createMode);
}
@Override
public void register(FunctionInfo function, CreateMode createMode, CreateScope createScope) {
CatalogOperations.createFunctionInCatalog(
- this.catalog, ImmutableList.of(function.getNamePath()), function, createMode);
+ this.catalog, function.getFullName(), function, createMode);
}
@Override
public void register(TVFInfo tvfInfo, CreateMode createMode, CreateScope createScope) {
CatalogOperations.createTVFInCatalog(
- this.catalog, ImmutableList.of(tvfInfo.getNamePath()), tvfInfo, createMode);
+ this.catalog, tvfInfo.getFullName(), tvfInfo, createMode);
}
/**
@@ -87,24 +89,8 @@ public void register(TVFInfo tvfInfo, CreateMode createMode, CreateScope createS
@Override
public void register(
ProcedureInfo procedureInfo, CreateMode createMode, CreateScope createScope) {
- if (procedureInfo.getNamePath().size() > 1) {
- throw new CatalogException("Procedure name paths should have a single item");
- }
-
- List namePath =
- procedureInfo.getNamePath().stream()
- .flatMap(pathElement -> Arrays.stream(pathElement.split("\\.")))
- .collect(Collectors.toList());
- String fullName = String.join(".", namePath);
-
- List> procedurePaths = new ArrayList<>();
- procedurePaths.add(namePath);
- if (namePath.size() > 1) {
- procedurePaths.add(ImmutableList.of(fullName));
- }
-
CatalogOperations.createProcedureInCatalog(
- this.catalog, procedurePaths, procedureInfo, createMode);
+ this.catalog, procedureInfo.getFullName(), procedureInfo, createMode);
}
/**
@@ -130,22 +116,22 @@ public void register(Constant constant) {
@Override
public void removeTable(String fullTableName) {
- CatalogOperations.deleteTableFromCatalog(this.catalog, ImmutableList.of(ImmutableList.of(fullTableName)));
+ CatalogOperations.deleteTableFromCatalog(this.catalog, fullTableName);
}
@Override
public void removeFunction(String function) {
- CatalogOperations.deleteFunctionFromCatalog(this.catalog, ImmutableList.of(ImmutableList.of(function)));
+ CatalogOperations.deleteFunctionFromCatalog(this.catalog, function);
}
@Override
public void removeTVF(String function) {
- CatalogOperations.deleteTVFFromCatalog(this.catalog, ImmutableList.of(ImmutableList.of(function)));
+ CatalogOperations.deleteTVFFromCatalog(this.catalog, function);
}
@Override
public void removeProcedure(String procedure) {
- CatalogOperations.deleteProcedureFromCatalog(this.catalog, ImmutableList.of(ImmutableList.of(procedure)));
+ CatalogOperations.deleteProcedureFromCatalog(this.catalog, procedure);
}
@Override
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/exceptions/CatalogResourceDoesNotExist.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/exceptions/CatalogResourceDoesNotExist.java
new file mode 100644
index 0000000..e9f84cf
--- /dev/null
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/exceptions/CatalogResourceDoesNotExist.java
@@ -0,0 +1,26 @@
+package com.google.zetasql.toolkit.catalog.exceptions;
+
+public class CatalogResourceDoesNotExist extends CatalogException {
+
+ private final String resourceName;
+
+ public CatalogResourceDoesNotExist(String resourceName) {
+ super("Catalog resource already exists: " + resourceName);
+ this.resourceName = resourceName;
+ }
+
+ public CatalogResourceDoesNotExist(String resourceName, String message) {
+ super(message);
+ this.resourceName = resourceName;
+ }
+
+ public CatalogResourceDoesNotExist(String resourceName, String message, Throwable cause) {
+ super(message, cause);
+ this.resourceName = resourceName;
+ }
+
+ public String getResourceName() {
+ return resourceName;
+ }
+
+}
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParser.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParser.java
index fa75492..32f408f 100644
--- a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParser.java
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParser.java
@@ -115,7 +115,7 @@ public Type getResult() {
@Override
public void exitBasicType(BasicTypeContext ctx) {
- String basicTypeName = ctx.BASIC_TYPE().getText();
+ String basicTypeName = ctx.BASIC_TYPE().getText().toUpperCase();
TypeKind kind = simpleTypeMapping.getOrDefault(basicTypeName, TypeKind.TYPE_UNKNOWN);
Type type = TypeFactory.createSimpleType(kind);
this.typeStack.push(type);
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ColumnLineageExtractor.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ColumnLineageExtractor.java
index 5e54a2d..4c3f4b3 100644
--- a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ColumnLineageExtractor.java
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ColumnLineageExtractor.java
@@ -21,6 +21,7 @@
import com.google.zetasql.Table;
import com.google.zetasql.Type;
import com.google.zetasql.resolvedast.ResolvedColumn;
+import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedQueryStmt;
import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedColumnRef;
import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedCreateTableAsSelectStmt;
import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedCreateViewBase;
@@ -49,6 +50,7 @@
* Implements extraction of column-level lineage from ZetaSQL {@link ResolvedStatement}s.
* Supported statements:
*
+ * - SELECT
*
- CREATE TABLE AS SELECT
*
- CREATE [MATERIALIZED] VIEW AS SELECT
*
- INSERT
@@ -122,7 +124,7 @@ private static Set extractColumnLevelLineageForOutputColumns(
* @param createTableAsSelectStmt The ResolvedCreateTableAsSelectStmt for which to extract lineage
* @return The set of resulting {@link ColumnLineage} objects
*/
- private static Set extractColumnLevelLineage(
+ public static Set extractColumnLevelLineage(
ResolvedCreateTableAsSelectStmt createTableAsSelectStmt) {
String fullTableName = String.join(".", createTableAsSelectStmt.getNamePath());
@@ -139,7 +141,7 @@ private static Set extractColumnLevelLineage(
* @param createViewBase The ResolvedCreateViewBase statement for which to extract lineage
* @return The set of resulting {@link ColumnLineage} objects
*/
- private static Set extractColumnLevelLineage(
+ public static Set extractColumnLevelLineage(
ResolvedCreateViewBase createViewBase) {
String fullViewName = String.join(".", createViewBase.getNamePath());
@@ -149,13 +151,26 @@ private static Set extractColumnLevelLineage(
fullViewName, outputColumns, createViewBase);
}
+ /**
+ * Extracts the column-level lineage entries for a {@link ResolvedQueryStmt} statement
+ *
+ * @param statement The ResolvedQueryStmt statement for which to extract lineage
+ * @param outputTable The name of the table the statement write to
+ * @return The set of resulting {@link ColumnLineage} objects
+ */
+ public static Set extractColumnLevelLineage(
+ ResolvedQueryStmt statement, String outputTable) {
+ List outputColumns = statement.getOutputColumnList();
+ return extractColumnLevelLineageForOutputColumns(outputTable, outputColumns, statement);
+ }
+
/**
* Extracts the column-level lineage entries for a {@link ResolvedInsertStmt}
*
* @param insertStmt The ResolvedInsertStmt for which to extract lineage
* @return The set of resulting {@link ColumnLineage} objects
*/
- private static Set extractColumnLevelLineage(ResolvedInsertStmt insertStmt) {
+ public static Set extractColumnLevelLineage(ResolvedInsertStmt insertStmt) {
if (Objects.isNull(insertStmt.getQuery())) {
// The statement is inserting rows manually using "INSERT INTO ... VALUES ..."
// Since it does not query any tables, it does not produce lineage
@@ -255,7 +270,7 @@ private static Optional extractColumnLevelLineageForUpdateItem(
* @param updateStmt The ResolvedUpdateStmt for which to extract lineage
* @return The set of resulting {@link ColumnLineage} objects
*/
- private static Set extractColumnLevelLineage(ResolvedUpdateStmt updateStmt) {
+ public static Set extractColumnLevelLineage(ResolvedUpdateStmt updateStmt) {
Table targetTable = updateStmt.getTableScan().getTable();
List updateItems = updateStmt.getUpdateItemList();
@@ -317,7 +332,7 @@ private static Set extractColumnLevelLineage(
* @param mergeStmt The ResolvedMergeStmt for which to extract lineage
* @return The set of resulting {@link ColumnLineage} objects
*/
- private static Set extractColumnLevelLineage(ResolvedMergeStmt mergeStmt) {
+ public static Set extractColumnLevelLineage(ResolvedMergeStmt mergeStmt) {
Table targetTable = mergeStmt.getTableScan().getTable();
return mergeStmt.getWhenClauseList()
@@ -327,34 +342,4 @@ private static Set extractColumnLevelLineage(ResolvedMergeStmt me
.collect(Collectors.toSet());
}
- /**
- * Extracts the column-level lineage entries for a {@link ResolvedStatement}.
- * Supported statements:
- *
- * - CREATE TABLE AS SELECT
- *
- CREATE [MATERIALIZED] VIEW AS SELECT
- *
- INSERT
- *
- UPDATE
- *
- MERGE
- *
- *
- * @param statement The ResolvedStatement for which to extract lineage
- * @return The set of resulting {@link ColumnLineage} objects. Empty for unsupported statements.
- */
- public static Set extractColumnLevelLineage(ResolvedStatement statement) {
- if (statement instanceof ResolvedCreateTableAsSelectStmt) {
- return extractColumnLevelLineage((ResolvedCreateTableAsSelectStmt) statement);
- } else if (statement instanceof ResolvedInsertStmt) {
- return extractColumnLevelLineage((ResolvedInsertStmt) statement);
- } else if (statement instanceof ResolvedUpdateStmt) {
- return extractColumnLevelLineage((ResolvedUpdateStmt) statement);
- } else if (statement instanceof ResolvedMergeStmt) {
- return extractColumnLevelLineage((ResolvedMergeStmt) statement);
- } else if (statement instanceof ResolvedCreateViewBase) {
- return extractColumnLevelLineage((ResolvedCreateViewBase) statement);
- }
-
- return ImmutableSet.of();
- }
-
}
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ParentColumnFinder.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ParentColumnFinder.java
index ee43e46..7410862 100644
--- a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ParentColumnFinder.java
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/lineage/ParentColumnFinder.java
@@ -74,7 +74,7 @@
* those scopes to correlate the ResolvedWithRefScan columns to their parents in the corresponding
* ResolvedWithEntry.
*/
-class ParentColumnFinder extends Visitor {
+public class ParentColumnFinder extends Visitor {
private final HashMap> columnsToParents = new HashMap<>();
private final Set terminalColumns = new HashSet<>();
diff --git a/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/patch/ZetaSQLPatcher.java b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/patch/ZetaSQLPatcher.java
new file mode 100644
index 0000000..2a0ce55
--- /dev/null
+++ b/zetasql-toolkit-core/src/main/java/com/google/zetasql/toolkit/tools/patch/ZetaSQLPatcher.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2023 Google LLC All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zetasql.toolkit.tools.patch;
+
+import com.google.protobuf.ExperimentalApi;
+import com.google.protobuf.Message;
+import com.google.zetasql.LocalService.AnalyzeRequest;
+import com.google.zetasql.LocalService.AnalyzeResponse;
+import com.google.zetasql.LocalService.BuildSqlRequest;
+import com.google.zetasql.LocalService.BuildSqlResponse;
+import com.google.zetasql.LocalService.ParseRequest;
+import com.google.zetasql.LocalService.ParseResponse;
+import com.google.zetasql.ZetaSqlLocalServiceGrpc;
+import com.google.zetasql.io.grpc.MethodDescriptor;
+import com.google.zetasql.io.grpc.MethodDescriptor.Marshaller;
+import com.google.zetasql.io.grpc.protobuf.ProtoUtils;
+import java.lang.reflect.Field;
+
+/**
+ * Implements some reflection-based patches to ZetaSQL. The only patch currently available is
+ * {@link #patchMaxProtobufNestingDepth(int)}.
+ *
+ * These reflection-based patches are brittle by design and should be avoided whenever possible.
+ */
+public class ZetaSQLPatcher {
+
+ /**
+ * Patches the maximum protobuf nesting depth allowed when accessing the ZetaSQL local service
+ * through GRPC. This patch should be applied when working with large SQL statements that
+ * hit GRPC's default nesting limit of 100.
+ *
+ *
This new max depth is only set for three key RPCs, which result in a lot of nesting when
+ * working with large SQL statements. These RPCs are Parse, Analyze and BuildSql.
+ *
+ *
This patch should be considered experimental; as it relies on
+ * {@link ProtoUtils#marshallerWithRecursionLimit(Message, int)} from grpc-java, which is
+ * experimental itself.
+ *
+ * @param maxDepth the maximum nesting depth to set for RPCs to the ZetaSQL local service.
+ * Should be greater than 100.
+ * @throws IllegalAccessException if any reflective access performed by this patch produces an
+ * illegal access.
+ */
+ @ExperimentalApi
+ public static void patchMaxProtobufNestingDepth(int maxDepth)
+ throws IllegalAccessException {
+ if (!(maxDepth > 100)) {
+ throw new IllegalArgumentException(
+ "Invalid max nesting depth for patching protobuf. Should be at least 100, but got: "
+ + maxDepth);
+ }
+
+ patchMaxNestingDepthForParse(maxDepth);
+ patchMaxNestingDepthForAnalyze(maxDepth);
+ patchMaxNestingDepthForBuildSql(maxDepth);
+ }
+
+ private static Field getLocalServiceField(String name) {
+ try {
+ return ZetaSqlLocalServiceGrpc.class.getDeclaredField(name);
+ } catch (NoSuchFieldException noSuchFieldException) {
+ throw new IllegalStateException(
+ "Tried to access not existent field in class ZetaSqlLocalServiceGrpc: " + name,
+ noSuchFieldException);
+ }
+ }
+
+ private static void patchMaxNestingDepthForAnalyze(int maxDepth)
+ throws IllegalAccessException {
+ Field getAnalyzeMethod = getLocalServiceField("getAnalyzeMethod");
+
+ Marshaller requestMarshaller = ProtoUtils.marshallerWithRecursionLimit(
+ AnalyzeRequest.getDefaultInstance(), maxDepth);
+ Marshaller responseMarshaller = ProtoUtils.marshallerWithRecursionLimit(
+ AnalyzeResponse.getDefaultInstance(), maxDepth);
+
+ MethodDescriptor newMethodDescriptor =
+ ZetaSqlLocalServiceGrpc.getAnalyzeMethod()
+ .toBuilder(requestMarshaller, responseMarshaller)
+ .build();
+
+ synchronized (ZetaSqlLocalServiceGrpc.class) {
+ getAnalyzeMethod.setAccessible(true);
+ getAnalyzeMethod.set(null, newMethodDescriptor);
+ }
+ }
+
+ private static void patchMaxNestingDepthForParse(int maxDepth)
+ throws IllegalAccessException {
+ Field getParseMethod = getLocalServiceField("getParseMethod");
+
+ Marshaller requestMarshaller = ProtoUtils.marshallerWithRecursionLimit(
+ ParseRequest.getDefaultInstance(), maxDepth);
+ Marshaller responseMarshaller = ProtoUtils.marshallerWithRecursionLimit(
+ ParseResponse.getDefaultInstance(), maxDepth);
+
+ MethodDescriptor newMethodDescriptor =
+ ZetaSqlLocalServiceGrpc.getParseMethod()
+ .toBuilder(requestMarshaller, responseMarshaller)
+ .build();
+
+ synchronized (ZetaSqlLocalServiceGrpc.class) {
+ getParseMethod.setAccessible(true);
+ getParseMethod.set(null, newMethodDescriptor);
+ }
+ }
+
+ private static void patchMaxNestingDepthForBuildSql(int maxDepth)
+ throws IllegalAccessException {
+ Field getBuildSqlMethod = getLocalServiceField("getBuildSqlMethod");
+
+ Marshaller requestMarshaller = ProtoUtils.marshallerWithRecursionLimit(
+ BuildSqlRequest.getDefaultInstance(), maxDepth);
+ Marshaller responseMarshaller = ProtoUtils.marshallerWithRecursionLimit(
+ BuildSqlResponse.getDefaultInstance(), maxDepth);
+
+ MethodDescriptor newMethodDescriptor =
+ ZetaSqlLocalServiceGrpc.getBuildSqlMethod()
+ .toBuilder(requestMarshaller, responseMarshaller)
+ .build();
+
+ synchronized (ZetaSqlLocalServiceGrpc.class) {
+ getBuildSqlMethod.setAccessible(true);
+ getBuildSqlMethod.set(null, newMethodDescriptor);
+ }
+ }
+
+}
diff --git a/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/CatalogOperationsTest.java b/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/CatalogOperationsTest.java
index ece9b01..d00ac40 100644
--- a/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/CatalogOperationsTest.java
+++ b/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/CatalogOperationsTest.java
@@ -41,47 +41,6 @@ private SimpleCatalog createSampleCatalog(String name) {
"sample", "column", TypeFactory.createSimpleType(TypeKind.TYPE_STRING))));
catalog.addSimpleTable(sampleTable);
- Function function =
- new Function(
- ImmutableList.of("function"),
- "UDF",
- ZetaSQLFunctions.FunctionEnums.Mode.SCALAR,
- ImmutableList.of(
- new FunctionSignature(
- new FunctionArgumentType(TypeFactory.createSimpleType(TypeKind.TYPE_STRING)),
- ImmutableList.of(),
- -1)));
- catalog.addFunction(function);
-
- TVFRelation tvfOutputSchema =
- TVFRelation.createColumnBased(
- ImmutableList.of(
- TVFRelation.Column.create(
- "output", TypeFactory.createSimpleType(TypeKind.TYPE_STRING))));
- TableValuedFunction tvf =
- new TableValuedFunction.FixedOutputSchemaTVF(
- ImmutableList.of("tvf"),
- new FunctionSignature(
- new FunctionArgumentType(
- ZetaSQLFunctions.SignatureArgumentKind.ARG_TYPE_RELATION,
- FunctionArgumentType.FunctionArgumentTypeOptions.builder()
- .setRelationInputSchema(tvfOutputSchema)
- .build(),
- 1),
- ImmutableList.of(),
- -1),
- tvfOutputSchema);
- catalog.addTableValuedFunction(tvf);
-
- Procedure procedure =
- new Procedure(
- ImmutableList.of("procedure"),
- new FunctionSignature(
- new FunctionArgumentType(ZetaSQLFunctions.SignatureArgumentKind.ARG_TYPE_VOID),
- ImmutableList.of(),
- -1));
- catalog.addProcedure(procedure);
-
return catalog;
}
@@ -112,38 +71,21 @@ void testCreateTableInCatalog() {
tableName, "column", TypeFactory.createSimpleType(TypeKind.TYPE_STRING))));
newTable.setFullName(fullTableName);
- List newTablePath1 = ImmutableList.of("newTable");
- List newTablePath2 = ImmutableList.of("qualified", "newTable");
- List> newTablePaths = ImmutableList.of(newTablePath1, newTablePath2);
-
CatalogOperations.createTableInCatalog(
- this.testCatalog,
- newTablePaths,
- fullTableName,
- newTable.getColumnList(),
- CreateMode.CREATE_DEFAULT);
+ this.testCatalog, newTable.getFullName(), newTable, CreateMode.CREATE_DEFAULT);
- assertAll(
- () -> assertTableExists(this.testCatalog, newTablePath1, "Expected created table to exist"),
- () ->
- assertTableExists(this.testCatalog, newTablePath2, "Expected created table to exist"));
+ assertTableExists(this.testCatalog, ImmutableList.of("qualified.newTable"), "Expected created table to exist");
}
@Test
void testDeleteTableFromCatalog() {
- List sampleTablePath = ImmutableList.of("sample");
- List nestedSampleTablePath = ImmutableList.of("nested", "sample");
- List> tablePathsToDelete = ImmutableList.of(sampleTablePath, nestedSampleTablePath);
- CatalogOperations.deleteTableFromCatalog(this.testCatalog, tablePathsToDelete);
+ CatalogOperations.deleteTableFromCatalog(this.testCatalog, "sample");
+
+ assertTableDoesNotExist(
+ this.testCatalog, ImmutableList.of("sample"),
+ "Expected table to have been deleted");
- assertAll(
- () ->
- assertTableDoesNotExist(
- this.testCatalog, sampleTablePath, "Expected table to have been deleted"),
- () ->
- assertTableDoesNotExist(
- this.testCatalog, nestedSampleTablePath, "Expected table to have been deleted"));
}
@Test
@@ -156,17 +98,11 @@ void testTableAlreadyExists() {
new SimpleColumn(
tableName, "column", TypeFactory.createSimpleType(TypeKind.TYPE_INT64))));
- List tablePath = ImmutableList.of("sample");
-
assertThrows(
CatalogResourceAlreadyExists.class,
() ->
CatalogOperations.createTableInCatalog(
- this.testCatalog,
- ImmutableList.of(tablePath),
- "sample",
- newTable.getColumnList(),
- CreateMode.CREATE_DEFAULT));
+ this.testCatalog, newTable.getFullName(), newTable, CreateMode.CREATE_DEFAULT));
}
@Test
@@ -179,17 +115,12 @@ void testReplaceTable() {
new SimpleColumn(
tableName, "column", TypeFactory.createSimpleType(TypeKind.TYPE_INT64))));
- List tablePath = ImmutableList.of("sample");
CatalogOperations.createTableInCatalog(
- this.testCatalog,
- ImmutableList.of(tablePath),
- "sample",
- newTable.getColumnList(),
- CreateMode.CREATE_OR_REPLACE);
+ this.testCatalog, newTable.getFullName(), newTable, CreateMode.CREATE_OR_REPLACE);
- Table foundTable =
- assertTableExists(this.testCatalog, tablePath, "Expected replaced table to exist");
+ Table foundTable = assertTableExists(
+ this.testCatalog, ImmutableList.of("sample"), "Expected replaced table to exist");
assertEquals(
foundTable.getColumn(0).getType(),
@@ -212,11 +143,7 @@ void testCreateTableIfNotExists_ExistingTable() throws NotFoundException {
Table originalTable = this.testCatalog.findTable(sampleTablePath);
CatalogOperations.createTableInCatalog(
- this.testCatalog,
- ImmutableList.of(sampleTablePath),
- "sample",
- newTable.getColumnList(),
- CreateMode.CREATE_IF_NOT_EXISTS);
+ this.testCatalog, newTable.getFullName(), newTable, CreateMode.CREATE_IF_NOT_EXISTS);
Table foundTable =
assertTableExists(
@@ -240,16 +167,13 @@ void testCreateTableIfNotExists_NewTable() {
new SimpleColumn(
tableName, "column", TypeFactory.createSimpleType(TypeKind.TYPE_INT64))));
- List newTablePath = ImmutableList.of("newTable");
-
CatalogOperations.createTableInCatalog(
- this.testCatalog,
- ImmutableList.of(newTablePath),
- "newTable",
- newTable.getColumnList(),
- CreateMode.CREATE_IF_NOT_EXISTS);
+ this.testCatalog, newTable.getFullName(), newTable, CreateMode.CREATE_IF_NOT_EXISTS);
- assertTableExists(this.testCatalog, newTablePath, "Expected table to have been created");
+ assertTableExists(
+ this.testCatalog,
+ ImmutableList.of("newTable"),
+ "Expected table to have been created");
}
private Function assertFunctionExists(SimpleCatalog catalog, String fullName, String message) {
@@ -268,7 +192,7 @@ private void assertFunctionDoesNotExist(SimpleCatalog catalog, String fullName,
void testCreateFunctionInCatalog() {
FunctionInfo newFunction =
FunctionInfo.newBuilder()
- .setNamePath(ImmutableList.of("newFunction"))
+ .setNamePath(ImmutableList.of("qualified.newFunction"))
.setGroup("UDF")
.setMode(ZetaSQLFunctions.FunctionEnums.Mode.SCALAR)
.setSignatures(
@@ -280,46 +204,39 @@ void testCreateFunctionInCatalog() {
-1)))
.build();
- List newFunctionPath1 = ImmutableList.of("newFunction");
- List newFunctionPath2 = ImmutableList.of("qualified", "newFunction");
- List> newFunctionPaths = ImmutableList.of(newFunctionPath1, newFunctionPath2);
-
CatalogOperations.createFunctionInCatalog(
- this.testCatalog, newFunctionPaths, newFunction, CreateMode.CREATE_DEFAULT);
-
- SimpleCatalog qualifiedNestedCatalog = this.testCatalog.getCatalog("qualified", null);
+ this.testCatalog, "qualified.newFunction", newFunction, CreateMode.CREATE_DEFAULT);
- assertNotNull(
- qualifiedNestedCatalog,
- "Expected the nested catalog to exist after creating a resource in it");
+ assertFunctionExists(
+ this.testCatalog, "UDF:qualified.newFunction", "Expected created function to exist");
- assertAll(
- () ->
- assertFunctionExists(
- this.testCatalog, "UDF:newFunction", "Expected created function to exist"),
- () ->
- assertFunctionExists(
- qualifiedNestedCatalog, "UDF:newFunction", "Expected created function to exist"));
}
@Test
void testDeleteFunctionFromCatalog() {
- List sampleFunctionPath = ImmutableList.of("function");
- List nestedSampleFunctionPath = ImmutableList.of("nested", "function");
+ FunctionInfo newFunction =
+ FunctionInfo.newBuilder()
+ .setNamePath(ImmutableList.of("qualified.newFunction"))
+ .setGroup("UDF")
+ .setMode(ZetaSQLFunctions.FunctionEnums.Mode.SCALAR)
+ .setSignatures(
+ ImmutableList.of(
+ new FunctionSignature(
+ new FunctionArgumentType(
+ TypeFactory.createSimpleType(TypeKind.TYPE_STRING)),
+ ImmutableList.of(),
+ -1)))
+ .build();
- List> functionPathsToDelete =
- ImmutableList.of(sampleFunctionPath, nestedSampleFunctionPath);
- CatalogOperations.deleteFunctionFromCatalog(this.testCatalog, functionPathsToDelete);
+ CatalogOperations.createFunctionInCatalog(
+ this.testCatalog, "qualified.newFunction", newFunction, CreateMode.CREATE_DEFAULT);
+ CatalogOperations.deleteFunctionFromCatalog(this.testCatalog, "qualified.newFunction");
+
+ assertFunctionDoesNotExist(
+ this.testCatalog,
+ "UDF:qualified.newFunction",
+ "Expected function to have been deleted");
- assertAll(
- () ->
- assertFunctionDoesNotExist(
- this.testCatalog.getCatalog("nested", null),
- "UDF:function",
- "Expected function to have been deleted"),
- () ->
- assertFunctionDoesNotExist(
- this.testCatalog, "UDF:function", "Expected function to have been deleted"));
}
private TableValuedFunction assertTVFExists(SimpleCatalog catalog, String name, String message) {
@@ -338,7 +255,7 @@ private void assertTVFDoesNotExist(SimpleCatalog catalog, String name, String me
void testCreateTVFInCatalog() {
TVFInfo newTVF =
TVFInfo.newBuilder()
- .setNamePath(ImmutableList.of("newTVF"))
+ .setNamePath(ImmutableList.of("qualified.newTVF"))
.setSignature(
new FunctionSignature(
new FunctionArgumentType(
@@ -350,44 +267,33 @@ void testCreateTVFInCatalog() {
TypeFactory.createSimpleType(TypeKind.TYPE_STRING)))
.build();
- List newFunctionPath1 = ImmutableList.of("newTVF");
- List newFunctionPath2 = ImmutableList.of("qualified", "newTVF");
- List> newFunctionPaths = ImmutableList.of(newFunctionPath1, newFunctionPath2);
-
CatalogOperations.createTVFInCatalog(
- this.testCatalog, newFunctionPaths, newTVF, CreateMode.CREATE_DEFAULT);
-
- SimpleCatalog qualifiedNestedCatalog = this.testCatalog.getCatalog("qualified", null);
+ this.testCatalog, "qualified.newTVF", newTVF, CreateMode.CREATE_DEFAULT);
- assertNotNull(
- qualifiedNestedCatalog,
- "Expected the nested catalog to exist after creating a resource in it");
-
- assertAll(
- () -> assertTVFExists(this.testCatalog, "newTVF", "Expected created function to exist"),
- () ->
- assertTVFExists(
- qualifiedNestedCatalog, "newTVF", "Expected created function to exist"));
+ assertTVFExists(testCatalog, "qualified.newTVF", "Expected created function to exist");
}
@Test
void testDeleteTVFFromCatalog() {
- List sampleFunctionPath = ImmutableList.of("tvf");
- List nestedSampleFunctionPath = ImmutableList.of("nested", "tvf");
+ TVFInfo tvf = TVFInfo.newBuilder()
+ .setNamePath(ImmutableList.of("qualified.newTVF"))
+ .setSignature(
+ new FunctionSignature(
+ new FunctionArgumentType(
+ ZetaSQLFunctions.SignatureArgumentKind.ARG_TYPE_RELATION),
+ ImmutableList.of(),
+ -1))
+ .setOutputSchema(
+ TVFRelation.createValueTableBased(
+ TypeFactory.createSimpleType(TypeKind.TYPE_STRING)))
+ .build();
- List> functionPathsToDelete =
- ImmutableList.of(sampleFunctionPath, nestedSampleFunctionPath);
- CatalogOperations.deleteTVFFromCatalog(this.testCatalog, functionPathsToDelete);
+ CatalogOperations.createTVFInCatalog(
+ this.testCatalog, "qualified.newTVF", tvf, CreateMode.CREATE_DEFAULT);
+ CatalogOperations.deleteTVFFromCatalog(this.testCatalog, "qualified.newTVF");
- assertAll(
- () ->
- assertTVFDoesNotExist(
- this.testCatalog.getCatalog("nested", null),
- "tvf",
- "Expected function to have been deleted"),
- () ->
- assertTVFDoesNotExist(
- this.testCatalog, "tvf", "Expected function to have been deleted"));
+ assertTVFDoesNotExist(
+ this.testCatalog, "qualified.newTVF", "Expected function to have been deleted");
}
private Procedure assertProcedureExists(
@@ -404,18 +310,17 @@ private void assertProcedureDoesNotExist(
void testCreateProcedureInCatalog() {
ProcedureInfo newProcedure =
new ProcedureInfo(
- ImmutableList.of("newProcedure"),
+ ImmutableList.of("qualified.newProcedure"),
new FunctionSignature(
new FunctionArgumentType(ZetaSQLFunctions.SignatureArgumentKind.ARG_TYPE_VOID),
ImmutableList.of(),
-1));
- List newProcedurePath1 = ImmutableList.of("newProcedure");
+ List newProcedurePath1 = ImmutableList.of("qualified.newProcedure");
List newProcedurePath2 = ImmutableList.of("qualified", "newProcedure");
- List> newProcedurePaths = ImmutableList.of(newProcedurePath1, newProcedurePath2);
CatalogOperations.createProcedureInCatalog(
- this.testCatalog, newProcedurePaths, newProcedure, CreateMode.CREATE_DEFAULT);
+ this.testCatalog, "qualified.newProcedure", newProcedure, CreateMode.CREATE_DEFAULT);
assertAll(
() ->
@@ -428,20 +333,30 @@ void testCreateProcedureInCatalog() {
@Test
void testDeleteProcedureFromCatalog() {
- List sampleProcedurePath = ImmutableList.of("procedure");
- List nestedSampleProcedurePath = ImmutableList.of("nested", "procedure");
+ ProcedureInfo newProcedure =
+ new ProcedureInfo(
+ ImmutableList.of("qualified.newProcedure"),
+ new FunctionSignature(
+ new FunctionArgumentType(ZetaSQLFunctions.SignatureArgumentKind.ARG_TYPE_VOID),
+ ImmutableList.of(),
+ -1));
+
+ CatalogOperations.createProcedureInCatalog(
+ this.testCatalog, "qualified.newProcedure", newProcedure, CreateMode.CREATE_DEFAULT);
+
+ List procedurePath1 = ImmutableList.of("newProcedure");
+ List procedurePath2 = ImmutableList.of("qualified", "newProcedure");
- List> pathsToDelete = ImmutableList.of(sampleProcedurePath, nestedSampleProcedurePath);
- CatalogOperations.deleteProcedureFromCatalog(this.testCatalog, pathsToDelete);
+ CatalogOperations.deleteProcedureFromCatalog(this.testCatalog, "qualified.newProcedure");
assertAll(
() ->
assertProcedureDoesNotExist(
- this.testCatalog, sampleProcedurePath, "Expected procedure to have been deleted"),
+ this.testCatalog, procedurePath1, "Expected procedure to have been deleted"),
() ->
assertProcedureDoesNotExist(
this.testCatalog,
- nestedSampleProcedurePath,
+ procedurePath2,
"Expected procedure to have been deleted"));
}
diff --git a/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParserTest.java b/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParserTest.java
index 88de699..577bcfb 100644
--- a/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParserTest.java
+++ b/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/catalog/typeparser/ZetaSQLTypeParserTest.java
@@ -36,6 +36,7 @@ void parseSimpleTypes() {
Map inputsToExpectedKinds = new HashMap<>();
inputsToExpectedKinds.put("STRING", TypeKind.TYPE_STRING);
inputsToExpectedKinds.put("INT64", TypeKind.TYPE_INT64);
+ inputsToExpectedKinds.put("DATE", TypeKind.TYPE_DATE);
inputsToExpectedKinds.put("NUMERIC", TypeKind.TYPE_NUMERIC);
inputsToExpectedKinds.put("INTERVAL", TypeKind.TYPE_INTERVAL);
inputsToExpectedKinds.put("JSON", TypeKind.TYPE_JSON);
@@ -46,8 +47,31 @@ void parseSimpleTypes() {
inputToExpectedKind ->
() ->
assertEquals(
+ TypeFactory.createSimpleType(inputToExpectedKind.getValue()),
ZetaSQLTypeParser.parse(inputToExpectedKind.getKey()),
+ "Failed to parse type: " + inputToExpectedKind.getKey()));
+
+ assertAll(assertions);
+ }
+
+ @Test
+ void typesAreCaseInsensitive() {
+ Map inputsToExpectedKinds = new HashMap<>();
+ inputsToExpectedKinds.put("string", TypeKind.TYPE_STRING);
+ inputsToExpectedKinds.put("inT64", TypeKind.TYPE_INT64);
+ inputsToExpectedKinds.put("date", TypeKind.TYPE_DATE);
+ inputsToExpectedKinds.put("NuMEric", TypeKind.TYPE_NUMERIC);
+ inputsToExpectedKinds.put("intErval", TypeKind.TYPE_INTERVAL);
+ inputsToExpectedKinds.put("JSOn", TypeKind.TYPE_JSON);
+
+ Stream assertions =
+ inputsToExpectedKinds.entrySet().stream()
+ .map(
+ inputToExpectedKind ->
+ () ->
+ assertEquals(
TypeFactory.createSimpleType(inputToExpectedKind.getValue()),
+ ZetaSQLTypeParser.parse(inputToExpectedKind.getKey()),
"Failed to parse type: " + inputToExpectedKind.getKey()));
assertAll(assertions);
@@ -58,13 +82,13 @@ void parseSimpleTypesWithParameters() {
assertAll(
() ->
assertEquals(
- ZetaSQLTypeParser.parse("STRING(MAX)"),
TypeFactory.createSimpleType(TypeKind.TYPE_STRING),
+ ZetaSQLTypeParser.parse("STRING(MAX)"),
"Failed to parse string type with parameter: STRING(10)"),
() ->
assertEquals(
- ZetaSQLTypeParser.parse("NUMERIC(10, 2)"),
TypeFactory.createSimpleType(TypeKind.TYPE_NUMERIC),
+ ZetaSQLTypeParser.parse("NUMERIC(10, 2)"),
"Failed to parse numeric type with parameters: NUMERIC(10, 2)"));
}
@@ -75,7 +99,7 @@ void parseArray() {
TypeFactory.createArrayType(TypeFactory.createSimpleType(TypeKind.TYPE_STRING));
assertEquals(
- ZetaSQLTypeParser.parse(typeStr), expectedType, "Failed to parse type ARRAY");
+ expectedType, ZetaSQLTypeParser.parse(typeStr), "Failed to parse type ARRAY");
}
@Test
@@ -88,8 +112,8 @@ void parseStruct() {
new StructField("f2", TypeFactory.createSimpleType(TypeKind.TYPE_INT64))));
assertEquals(
- ZetaSQLTypeParser.parse(typeStr),
expectedType,
+ ZetaSQLTypeParser.parse(typeStr),
"Failed to parse type STRUCT");
}
@@ -103,8 +127,8 @@ void parseStructWithParameterType() {
new StructField("f2", TypeFactory.createSimpleType(TypeKind.TYPE_NUMERIC))));
assertEquals(
- ZetaSQLTypeParser.parse(typeStr),
expectedType,
+ ZetaSQLTypeParser.parse(typeStr),
"Failed to parse struct type STRUCT");
}
@@ -119,8 +143,8 @@ void parseArrayOfStructs() {
Type expectedType = TypeFactory.createArrayType(structType);
assertEquals(
- ZetaSQLTypeParser.parse(typeStr),
expectedType,
+ ZetaSQLTypeParser.parse(typeStr),
"Failed to array of structs ARRAY>");
}
@@ -139,8 +163,8 @@ void parseStructWithMultipleNestingLevels() {
ImmutableList.of(new StructField("f1", TypeFactory.createArrayType(innerStructType))));
assertEquals(
- ZetaSQLTypeParser.parse(typeStr),
expectedType,
+ ZetaSQLTypeParser.parse(typeStr),
"Failed to struct with multiple nesting levels "
+ "STRUCT, f1_2 NUMERIC(10, 2)>>>");
}
diff --git a/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/tools/patch/ZetaSQLPatcherTest.java b/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/tools/patch/ZetaSQLPatcherTest.java
new file mode 100644
index 0000000..01fff8c
--- /dev/null
+++ b/zetasql-toolkit-core/src/test/java/com/google/zetasql/toolkit/tools/patch/ZetaSQLPatcherTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 Google LLC All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zetasql.toolkit.tools.patch;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.google.zetasql.AnalyzerOptions;
+import com.google.zetasql.Parser;
+import com.google.zetasql.toolkit.ZetaSQLToolkitAnalyzer;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class ZetaSQLPatcherTest {
+
+ private ZetaSQLToolkitAnalyzer analyzer;
+
+ @BeforeEach
+ void init() {
+ AnalyzerOptions analyzerOptions = new AnalyzerOptions();
+ analyzerOptions.getLanguageOptions().enableMaximumLanguageFeatures();
+ analyzerOptions.getLanguageOptions().setSupportsAllStatementKinds();
+
+ this.analyzer = new ZetaSQLToolkitAnalyzer(analyzerOptions);
+ }
+
+ public static String generateNestedSelectStatement(int times) {
+ if (times == 1) {
+ return "SELECT 1";
+ }
+
+ return String.format("SELECT 1 FROM (%s)", generateNestedSelectStatement(times - 1));
+ }
+ @Test
+ void testMaxNestingDepthPatch() {
+ // The query is a SELECT statement nested 100 times. Parsing or analyzing
+ // such a statement normally fails due to reaching the default max nesting
+ // depth in the ZetaSQL local service.
+ // After patching the max nesting depth, it should not fail.
+ String query = generateNestedSelectStatement(100);
+
+ try {
+ ZetaSQLPatcher.patchMaxProtobufNestingDepth(1000);
+ } catch (IllegalAccessException err) {
+ Assumptions.abort("Aborting test because the patch was not applied successfully due to "
+ + "disallowed reflective access.");
+ }
+
+ assertDoesNotThrow(() -> {
+ this.analyzer.analyzeStatements(query).next();
+ });
+ }
+
+}
diff --git a/zetasql-toolkit-examples/pom.xml b/zetasql-toolkit-examples/pom.xml
index 3cad956..0c9433c 100644
--- a/zetasql-toolkit-examples/pom.xml
+++ b/zetasql-toolkit-examples/pom.xml
@@ -22,12 +22,12 @@
com.google.zetasql.toolkit
zetasql-toolkit
- 0.4.1
+ 0.5.0
../pom.xml
zetasql-toolkit-examples
- 0.4.1
+ 0.5.0
${project.groupId}:${project.artifactId}
diff --git a/zetasql-toolkit-examples/src/main/java/com/google/zetasql/toolkit/examples/ExtractColumnLevelLineage.java b/zetasql-toolkit-examples/src/main/java/com/google/zetasql/toolkit/examples/ExtractColumnLevelLineage.java
index 5ac74c5..43355b7 100644
--- a/zetasql-toolkit-examples/src/main/java/com/google/zetasql/toolkit/examples/ExtractColumnLevelLineage.java
+++ b/zetasql-toolkit-examples/src/main/java/com/google/zetasql/toolkit/examples/ExtractColumnLevelLineage.java
@@ -18,7 +18,11 @@
import com.google.common.collect.ImmutableList;
import com.google.zetasql.AnalyzerOptions;
+import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedCreateTableAsSelectStmt;
+import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedInsertStmt;
+import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedMergeStmt;
import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedStatement;
+import com.google.zetasql.resolvedast.ResolvedNodes.ResolvedUpdateStmt;
import com.google.zetasql.toolkit.AnalyzedStatement;
import com.google.zetasql.toolkit.ZetaSQLToolkitAnalyzer;
import com.google.zetasql.toolkit.catalog.bigquery.BigQueryCatalog;
@@ -60,8 +64,11 @@ private static void lineageForCreateTableAsSelectStatement(
Iterator statementIterator = analyzer.analyzeStatements(query, catalog);
ResolvedStatement statement = statementIterator.next().getResolvedStatement().get();
+ ResolvedCreateTableAsSelectStmt createTableAsSelectStmt =
+ (ResolvedCreateTableAsSelectStmt) statement;
- Set lineageEntries = ColumnLineageExtractor.extractColumnLevelLineage(statement);
+ Set lineageEntries =
+ ColumnLineageExtractor.extractColumnLevelLineage(createTableAsSelectStmt);
System.out.println("Extracted column lineage from CREATE TABLE AS SELECT");
outputLineage(query, lineageEntries);
@@ -84,8 +91,10 @@ private static void lineageForInsertStatement(
Iterator statementIterator = analyzer.analyzeStatements(query, catalog);
ResolvedStatement statement = statementIterator.next().getResolvedStatement().get();
+ ResolvedInsertStmt insertStmt = (ResolvedInsertStmt) statement;
- Set lineageEntries = ColumnLineageExtractor.extractColumnLevelLineage(statement);
+ Set lineageEntries =
+ ColumnLineageExtractor.extractColumnLevelLineage(insertStmt);
System.out.println("Extracted column lineage from INSERT");
outputLineage(query, lineageEntries);
@@ -101,8 +110,10 @@ private static void lineageForUpdateStatement(
Iterator statementIterator = analyzer.analyzeStatements(query, catalog);
ResolvedStatement statement = statementIterator.next().getResolvedStatement().get();
+ ResolvedUpdateStmt updateStmt = (ResolvedUpdateStmt) statement;
- Set lineageEntries = ColumnLineageExtractor.extractColumnLevelLineage(statement);
+ Set lineageEntries =
+ ColumnLineageExtractor.extractColumnLevelLineage(updateStmt);
System.out.println("Extracted column lineage from UPDATE");
outputLineage(query, lineageEntries);
@@ -121,8 +132,9 @@ private static void lineageForMergeStatement(
Iterator statementIterator = analyzer.analyzeStatements(query, catalog);
ResolvedStatement statement = statementIterator.next().getResolvedStatement().get();
+ ResolvedMergeStmt mergeStmt = (ResolvedMergeStmt) statement;
- Set lineageEntries = ColumnLineageExtractor.extractColumnLevelLineage(statement);
+ Set lineageEntries = ColumnLineageExtractor.extractColumnLevelLineage(mergeStmt);
System.out.println("Extracted column lineage from MERGE");
outputLineage(query, lineageEntries);
diff --git a/zetasql-toolkit-spanner/pom.xml b/zetasql-toolkit-spanner/pom.xml
index 3238a71..40f73f6 100644
--- a/zetasql-toolkit-spanner/pom.xml
+++ b/zetasql-toolkit-spanner/pom.xml
@@ -6,12 +6,12 @@
com.google.zetasql.toolkit
zetasql-toolkit
- 0.4.1
+ 0.5.0
../pom.xml
zetasql-toolkit-spanner
- 0.4.1
+ 0.5.0
${project.groupId}:${project.artifactId}
diff --git a/zetasql-toolkit-spanner/src/main/java/com/google/zetasql/toolkit/catalog/spanner/SpannerCatalog.java b/zetasql-toolkit-spanner/src/main/java/com/google/zetasql/toolkit/catalog/spanner/SpannerCatalog.java
index 27b7d6b..27edc5d 100644
--- a/zetasql-toolkit-spanner/src/main/java/com/google/zetasql/toolkit/catalog/spanner/SpannerCatalog.java
+++ b/zetasql-toolkit-spanner/src/main/java/com/google/zetasql/toolkit/catalog/spanner/SpannerCatalog.java
@@ -107,6 +107,7 @@ private SpannerCatalog(
* @param projectId The Spanner project id
* @param instance The Spanner instance name
* @param database The Spanner database name
+ * @return the new SpannerCatalog instance
*/
public static SpannerCatalog usingSpannerClient(
String projectId, String instance, String database) {
@@ -123,6 +124,7 @@ public static SpannerCatalog usingSpannerClient(
* @param instance The Spanner instance name
* @param database The Spanner database name
* @param spannerClient The Spanner client to use
+ * @return the new SpannerCatalog instance
*/
public static SpannerCatalog usingSpannerClient(
String projectId, String instance, String database, Spanner spannerClient) {
@@ -136,6 +138,7 @@ public static SpannerCatalog usingSpannerClient(
* {@link CatalogResources} object.
*
* @param resources The {@link CatalogResources} object from which this catalog will get tables
+ * @return the new SpannerCatalog instance
*/
public static SpannerCatalog usingResources(CatalogResources resources) {
SpannerResourceProvider resourceProvider = new LocalSpannerResourceProvider(resources);
@@ -151,18 +154,13 @@ public static SpannerCatalog usingResources(CatalogResources resources) {
*/
@Override
public void register(SimpleTable table, CreateMode createMode, CreateScope createScope) {
- String tableName = table.getName();
+ String fullName = table.getFullName();
- if (tableName.contains(".")) {
- throw new InvalidSpannerTableName(tableName);
+ if (fullName.contains(".")) {
+ throw new InvalidSpannerTableName(fullName);
}
- CatalogOperations.createTableInCatalog(
- this.catalog,
- ImmutableList.of(ImmutableList.of(table.getName())),
- table.getName(),
- table.getColumnList(),
- createMode);
+ CatalogOperations.createTableInCatalog(this.catalog, table.getFullName(), table, createMode);
}
@Override
@@ -191,7 +189,7 @@ public void register(Constant constant) {
@Override
public void removeTable(String table) {
this.validateSpannerTableNames(ImmutableList.of(table));
- CatalogOperations.deleteTableFromCatalog(this.catalog, ImmutableList.of(ImmutableList.of(table)));
+ CatalogOperations.deleteTableFromCatalog(this.catalog, table);
}
@Override