ASTERIXDB-1652: fix dataverse.function(...) to check the existence of the dataverse.
Change-Id: I7779db56f540fdd645bb85c769baeaa37f620a0d
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1192
Reviewed-by: Till Westmann <tillw@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/binary_null/binary_null.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/binary_null/binary_null.1.query.sqlpp
index 6b7441e..0377995 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/binary_null/binary_null.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/binary_null/binary_null.1.query.sqlpp
@@ -18,4 +18,4 @@
*/
-{'result1':(test.hex('AA') > null),'result2':(null >= test.hex('AA')),'result3':(test.hex('AA') < null),'result4':(null <= test.hex('AA')),'result5':(test.hex('AA') = null),'result6':(null != test.hex('AA'))};
+{'result1':(hex('AA') > null),'result2':(null >= hex('AA')),'result3':(hex('AA') < null),'result4':(null <= hex('AA')),'result5':(hex('AA') = null),'result6':(null != hex('AA'))};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_missing/int64_missing.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_missing/int64_missing.1.query.sqlpp
index 320ef99..74e25a7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_missing/int64_missing.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_missing/int64_missing.1.query.sqlpp
@@ -18,4 +18,4 @@
*/
-{'result1':(test.int64('3') > missing),'result2':(missing >= test.int64('3')),'result3':(test.int64('3') < missing),'result4':(missing <= test.int64('3')),'result5':(test.int64('3') = missing),'result6':(missing != test.int64('3'))};
+{'result1':(int64('3') > missing),'result2':(missing >= int64('3')),'result3':(int64('3') < missing),'result4':(missing <= int64('3')),'result5':(int64('3') = missing),'result6':(missing != int64('3'))};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_null/int64_null.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_null/int64_null.1.query.sqlpp
index 2af586e..a6a2163 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_null/int64_null.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/int64_null/int64_null.1.query.sqlpp
@@ -17,4 +17,4 @@
* under the License.
*/
-{'result1':(test.int64('3') > null),'result2':(null >= test.int64('3')),'result3':(test.int64('3') < null),'result4':(null <= test.int64('3')),'result5':(test.int64('3') = null),'result6':(null != test.int64('3'))};
+{'result1':(int64('3') > null),'result2':(null >= int64('3')),'result3':(int64('3') < null),'result4':(null <= int64('3')),'result5':(int64('3') = null),'result6':(null != int64('3'))};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.1.ddl.sqlpp
new file mode 100644
index 0000000..cc938ae
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.1.ddl.sqlpp
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+
+use test;
+
+create function length(foo){
+ 1
+}
+
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.2.query.sqlpp
new file mode 100644
index 0000000..ba90535
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.2.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+// Tests if a builtin function can be overridden.
+test.length("test");
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652/query-ASTERIXDB-1652.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652/query-ASTERIXDB-1652.1.query.sqlpp
new file mode 100644
index 0000000..650889c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/query-ASTERIXDB-1652/query-ASTERIXDB-1652.1.query.sqlpp
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+test.length("test");
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.1.adm
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/query-ASTERIXDB-1652-2/query-ASTERIXDB-1652-2.1.adm
@@ -0,0 +1 @@
+1
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/binary_null/binary_null.1.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/binary_null/binary_null.1.ast
index 3df4327..ee79f0c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/binary_null/binary_null.1.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/binary_null/binary_null.1.ast
@@ -4,7 +4,7 @@
LiteralExpr [STRING] [result1]
:
OperatorExpr [
- FunctionCall test.hex@1[
+ FunctionCall null.hex@1[
LiteralExpr [STRING] [AA]
]
>
@@ -17,7 +17,7 @@
OperatorExpr [
LiteralExpr [NULL]
>=
- FunctionCall test.hex@1[
+ FunctionCall null.hex@1[
LiteralExpr [STRING] [AA]
]
]
@@ -26,7 +26,7 @@
LiteralExpr [STRING] [result3]
:
OperatorExpr [
- FunctionCall test.hex@1[
+ FunctionCall null.hex@1[
LiteralExpr [STRING] [AA]
]
<
@@ -39,7 +39,7 @@
OperatorExpr [
LiteralExpr [NULL]
<=
- FunctionCall test.hex@1[
+ FunctionCall null.hex@1[
LiteralExpr [STRING] [AA]
]
]
@@ -48,7 +48,7 @@
LiteralExpr [STRING] [result5]
:
OperatorExpr [
- FunctionCall test.hex@1[
+ FunctionCall null.hex@1[
LiteralExpr [STRING] [AA]
]
=
@@ -61,7 +61,7 @@
OperatorExpr [
LiteralExpr [NULL]
!=
- FunctionCall test.hex@1[
+ FunctionCall null.hex@1[
LiteralExpr [STRING] [AA]
]
]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/int64_null/int64_null.1.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/int64_null/int64_null.1.ast
index d1a8791..0866ec0 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/int64_null/int64_null.1.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/comparison/int64_null/int64_null.1.ast
@@ -4,7 +4,7 @@
LiteralExpr [STRING] [result1]
:
OperatorExpr [
- FunctionCall test.int64@1[
+ FunctionCall null.int64@1[
LiteralExpr [STRING] [3]
]
>
@@ -17,7 +17,7 @@
OperatorExpr [
LiteralExpr [NULL]
>=
- FunctionCall test.int64@1[
+ FunctionCall null.int64@1[
LiteralExpr [STRING] [3]
]
]
@@ -26,7 +26,7 @@
LiteralExpr [STRING] [result3]
:
OperatorExpr [
- FunctionCall test.int64@1[
+ FunctionCall null.int64@1[
LiteralExpr [STRING] [3]
]
<
@@ -39,7 +39,7 @@
OperatorExpr [
LiteralExpr [NULL]
<=
- FunctionCall test.int64@1[
+ FunctionCall null.int64@1[
LiteralExpr [STRING] [3]
]
]
@@ -48,7 +48,7 @@
LiteralExpr [STRING] [result5]
:
OperatorExpr [
- FunctionCall test.int64@1[
+ FunctionCall null.int64@1[
LiteralExpr [STRING] [3]
]
=
@@ -61,7 +61,7 @@
OperatorExpr [
LiteralExpr [NULL]
!=
- FunctionCall test.int64@1[
+ FunctionCall null.int64@1[
LiteralExpr [STRING] [3]
]
]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index a2bc4ce..2a57ac2 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -7002,6 +7002,17 @@
</compilation-unit>
</test-case>
<test-case FilePath="user-defined-functions">
+ <compilation-unit name="query-ASTERIXDB-1652">
+ <expected-error>In function call "test.length(...)", the dataverse "test" cannot be found!</expected-error>
+ <output-dir compare="Text">query-ASTERIXDB-1652-2</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="user-defined-functions">
+ <compilation-unit name="query-ASTERIXDB-1652-2">
+ <output-dir compare="Text">query-ASTERIXDB-1652-2</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="user-defined-functions">
<compilation-unit name="query-issue218-2">
<output-dir compare="Text">query-issue218-2</output-dir>
</compilation-unit>
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
index 5edc521..4568309 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
@@ -34,8 +34,8 @@
import org.apache.asterix.lang.aql.visitor.base.IAQLVisitor;
import org.apache.asterix.lang.common.base.Clause;
import org.apache.asterix.lang.common.base.Expression;
-import org.apache.asterix.lang.common.base.Expression.Kind;
import org.apache.asterix.lang.common.base.IQueryRewriter;
+import org.apache.asterix.lang.common.base.Expression.Kind;
import org.apache.asterix.lang.common.clause.GroupbyClause;
import org.apache.asterix.lang.common.clause.LetClause;
import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
@@ -46,11 +46,7 @@
import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.util.FunctionUtil;
import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
-import org.apache.asterix.metadata.MetadataManager;
-import org.apache.asterix.metadata.MetadataTransactionContext;
import org.apache.asterix.metadata.declared.AqlMetadataProvider;
-import org.apache.asterix.metadata.entities.Function;
-import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
class AqlQueryRewriter implements IQueryRewriter {
@@ -58,7 +54,6 @@
private Query topExpr;
private List<FunctionDecl> declaredFunctions;
private LangRewritingContext context;
- private MetadataTransactionContext mdTxnCtx;
private AqlMetadataProvider metadataProvider;
private void setup(List<FunctionDecl> declaredFunctions, Query topExpr, AqlMetadataProvider metadataProvider,
@@ -66,7 +61,6 @@
this.topExpr = topExpr;
this.context = context;
this.declaredFunctions = declaredFunctions;
- this.mdTxnCtx = metadataProvider.getMetadataTxnContext();
this.metadataProvider = metadataProvider;
}
@@ -108,9 +102,10 @@
funIds.add(fdecl.getSignature());
}
- List<FunctionDecl> otherFDecls = new ArrayList<FunctionDecl>();
- buildOtherUdfs(topExpr.getBody(), otherFDecls, funIds);
- declaredFunctions.addAll(otherFDecls);
+ List<FunctionDecl> storedFunctionDecls = FunctionUtil.retrieveUsedStoredFunctions(metadataProvider,
+ topExpr.getBody(), funIds, null,
+ expr -> getFunctionCalls(expr), func -> functionParser.getFunctionDecl(func), null);
+ declaredFunctions.addAll(storedFunctionDecls);
if (!declaredFunctions.isEmpty()) {
AQLInlineUdfsVisitor visitor =
new AQLInlineUdfsVisitor(context, new AQLRewriterFactory(), declaredFunctions, metadataProvider);
@@ -118,59 +113,7 @@
// loop until no more changes
}
}
- declaredFunctions.removeAll(otherFDecls);
- }
-
- private void buildOtherUdfs(Expression expression, List<FunctionDecl> functionDecls,
- List<FunctionSignature> declaredFunctions) throws AsterixException {
- if (expression == null) {
- return;
- }
- String value = metadataProvider.getConfig().get(FunctionUtil.IMPORT_PRIVATE_FUNCTIONS);
- boolean includePrivateFunctions = (value != null) ? Boolean.valueOf(value.toLowerCase()) : false;
- Set<FunctionSignature> functionCalls = getFunctionCalls(expression);
- for (FunctionSignature signature : functionCalls) {
-
- if (declaredFunctions != null && declaredFunctions.contains(signature)) {
- continue;
- }
-
- Function function = lookupUserDefinedFunctionDecl(signature);
- if (function == null) {
- if (AsterixBuiltinFunctions.isBuiltinCompilerFunction(signature, includePrivateFunctions)) {
- continue;
- }
- StringBuilder messageBuilder = new StringBuilder();
- if (functionDecls.size() > 0) {
- messageBuilder.append("function " + functionDecls.get(functionDecls.size() - 1).getSignature()
- + " depends upon function " + signature + " which is undefined");
- } else {
- messageBuilder.append("function " + signature + " is undefined ");
- }
- throw new AsterixException(messageBuilder.toString());
- }
-
- if (function.getLanguage().equalsIgnoreCase(Function.LANGUAGE_AQL)) {
- FunctionDecl functionDecl = functionParser.getFunctionDecl(function);
- if (functionDecl != null) {
- if (functionDecls.contains(functionDecl)) {
- throw new AsterixException(
- "Recursive invocation " + functionDecls.get(functionDecls.size() - 1).getSignature()
- + " <==> " + functionDecl.getSignature());
- }
- functionDecls.add(functionDecl);
- buildOtherUdfs(functionDecl.getFuncBody(), functionDecls, declaredFunctions);
- }
- }
- }
-
- }
-
- private Function lookupUserDefinedFunctionDecl(FunctionSignature signature) throws AsterixException {
- if (signature.getNamespace() == null) {
- return null;
- }
- return MetadataManager.INSTANCE.getFunction(mdTxnCtx, signature);
+ declaredFunctions.removeAll(storedFunctionDecls);
}
private Set<FunctionSignature> getFunctionCalls(Expression expression) throws AsterixException {
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
index acd40d7..94866eb 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
@@ -19,7 +19,19 @@
package org.apache.asterix.lang.common.util;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.functions.FunctionConstants;
import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.metadata.MetadataManager;
+import org.apache.asterix.metadata.MetadataTransactionContext;
+import org.apache.asterix.metadata.declared.AqlMetadataProvider;
+import org.apache.asterix.metadata.entities.Function;
import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
@@ -36,4 +48,102 @@
return getFunctionInfo(new FunctionIdentifier(fs.getNamespace(), fs.getName(), fs.getArity()));
}
+ @FunctionalInterface
+ public interface IFunctionCollector {
+ Set<FunctionSignature> getFunctionCalls(Expression expression) throws AsterixException;
+ }
+
+ @FunctionalInterface
+ public interface IFunctionParser {
+ FunctionDecl getFunctionDecl(Function function) throws AsterixException;
+ }
+
+ @FunctionalInterface
+ public interface IFunctionNormalizer {
+ FunctionSignature normalizeBuiltinFunctionSignature(FunctionSignature fs) throws AsterixException;
+ }
+
+ /**
+ * Retrieve stored functions (from CREATE FUNCTION statements) that have been used in an expression.
+ *
+ * @param metadataProvider,
+ * the metadata provider
+ * @param expression,
+ * the expression for analysis
+ * @param declaredFunctions,
+ * a set of declared functions in the query, which can potentially override stored functions.
+ * @param functionCollector,
+ * for collecting function calls in the <code>expression</code>
+ * @param functionParser,
+ * for parsing stored functions in the string represetnation.
+ * @param functionNormalizer,
+ * for normalizing function names.
+ * @throws AsterixException
+ */
+ public static List<FunctionDecl> retrieveUsedStoredFunctions(AqlMetadataProvider metadataProvider,
+ Expression expression, List<FunctionSignature> declaredFunctions, List<FunctionDecl> inputFunctionDecls,
+ IFunctionCollector functionCollector, IFunctionParser functionParser,
+ IFunctionNormalizer functionNormalizer) throws AsterixException {
+ List<FunctionDecl> functionDecls = inputFunctionDecls == null ? new ArrayList<>()
+ : new ArrayList<>(inputFunctionDecls);
+ if (expression == null) {
+ return functionDecls;
+ }
+ String value = metadataProvider.getConfig().get(FunctionUtil.IMPORT_PRIVATE_FUNCTIONS);
+ boolean includePrivateFunctions = (value != null) ? Boolean.valueOf(value.toLowerCase()) : false;
+ Set<FunctionSignature> functionCalls = functionCollector.getFunctionCalls(expression);
+ for (FunctionSignature signature : functionCalls) {
+ if (declaredFunctions != null && declaredFunctions.contains(signature)) {
+ continue;
+ }
+ String dataverseName = signature.getNamespace() == null ? metadataProvider.getDefaultDataverseName()
+ : signature.getNamespace();
+ // Checks the existence of the referred dataverse.
+ if (metadataProvider.findDataverse(dataverseName) == null
+ && !dataverseName.equals(FunctionConstants.ASTERIX_NS)) {
+ throw new AsterixException("In function call \"" + dataverseName + "." + signature.getName()
+ + "(...)\", the dataverse \"" + dataverseName + "\" cannot be found!");
+ }
+ Function function = lookupUserDefinedFunctionDecl(metadataProvider.getMetadataTxnContext(), signature);
+ if (function == null) {
+ FunctionSignature normalizedSignature = functionNormalizer == null ? signature
+ : functionNormalizer.normalizeBuiltinFunctionSignature(signature);
+ if (AsterixBuiltinFunctions.isBuiltinCompilerFunction(normalizedSignature, includePrivateFunctions)) {
+ continue;
+ }
+ StringBuilder messageBuilder = new StringBuilder();
+ if (!functionDecls.isEmpty()) {
+ messageBuilder.append("function " + functionDecls.get(functionDecls.size() - 1).getSignature()
+ + " depends upon function " + signature + " which is undefined");
+ } else {
+ messageBuilder.append("function " + signature + " is undefined ");
+ }
+ throw new AsterixException(messageBuilder.toString());
+ }
+
+ if (function.getLanguage().equalsIgnoreCase(Function.LANGUAGE_AQL)) {
+ FunctionDecl functionDecl = functionParser.getFunctionDecl(function);
+ if (functionDecl != null) {
+ if (functionDecls.contains(functionDecl)) {
+ throw new AsterixException(
+ "Recursive invocation " + functionDecls.get(functionDecls.size() - 1).getSignature()
+ + " <==> " + functionDecl.getSignature());
+ }
+ functionDecls.add(functionDecl);
+ functionDecls = retrieveUsedStoredFunctions(metadataProvider, functionDecl.getFuncBody(),
+ declaredFunctions, functionDecls, functionCollector, functionParser, functionNormalizer);
+ }
+ }
+ }
+ return functionDecls;
+ }
+
+ private static Function lookupUserDefinedFunctionDecl(MetadataTransactionContext mdTxnCtx,
+ FunctionSignature signature) throws AsterixException {
+ if (signature.getNamespace() == null) {
+ return null;
+ }
+ return MetadataManager.INSTANCE.getFunction(mdTxnCtx, signature);
+ }
+
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
index dd79969..329f04b 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
@@ -65,11 +65,7 @@
import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil;
import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
-import org.apache.asterix.metadata.MetadataManager;
-import org.apache.asterix.metadata.MetadataTransactionContext;
import org.apache.asterix.metadata.declared.AqlMetadataProvider;
-import org.apache.asterix.metadata.entities.Function;
-import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
class SqlppQueryRewriter implements IQueryRewriter {
private static final String INLINE_WITH = "inline_with";
@@ -78,7 +74,6 @@
private Query topExpr;
private List<FunctionDecl> declaredFunctions;
private LangRewritingContext context;
- private MetadataTransactionContext mdTxnCtx;
private AqlMetadataProvider metadataProvider;
protected void setup(List<FunctionDecl> declaredFunctions, Query topExpr, AqlMetadataProvider metadataProvider,
@@ -86,7 +81,6 @@
this.topExpr = topExpr;
this.context = context;
this.declaredFunctions = declaredFunctions;
- this.mdTxnCtx = metadataProvider.getMetadataTxnContext();
this.metadataProvider = metadataProvider;
}
@@ -259,9 +253,11 @@
funIds.add(fdecl.getSignature());
}
- List<FunctionDecl> otherFDecls = new ArrayList<FunctionDecl>();
- buildOtherUdfs(topExpr.getBody(), otherFDecls, funIds);
- declaredFunctions.addAll(otherFDecls);
+ List<FunctionDecl> usedStoredFunctionDecls = FunctionUtil.retrieveUsedStoredFunctions(metadataProvider,
+ topExpr.getBody(), funIds, null,
+ expr -> getFunctionCalls(expr), func -> functionRepository.getFunctionDecl(func),
+ signature -> FunctionMapUtil.normalizeBuiltinFunctionSignature(signature, false));
+ declaredFunctions.addAll(usedStoredFunctionDecls);
if (!declaredFunctions.isEmpty()) {
SqlppInlineUdfsVisitor visitor = new SqlppInlineUdfsVisitor(context,
new SqlppFunctionBodyRewriterFactory() /* the rewriter for function bodies expressions*/,
@@ -270,61 +266,7 @@
// loop until no more changes
}
}
- declaredFunctions.removeAll(otherFDecls);
- }
-
- protected void buildOtherUdfs(Expression expression, List<FunctionDecl> functionDecls,
- List<FunctionSignature> declaredFunctions) throws AsterixException {
- if (expression == null) {
- return;
- }
- String value = metadataProvider.getConfig().get(FunctionUtil.IMPORT_PRIVATE_FUNCTIONS);
- boolean includePrivateFunctions = (value != null) ? Boolean.valueOf(value.toLowerCase()) : false;
- Set<FunctionSignature> functionCalls = getFunctionCalls(expression);
- for (FunctionSignature signature : functionCalls) {
-
- if (declaredFunctions != null && declaredFunctions.contains(signature)) {
- continue;
- }
-
- Function function = lookupUserDefinedFunctionDecl(signature);
- if (function == null) {
- FunctionSignature normalizedSignature =
- FunctionMapUtil.normalizeBuiltinFunctionSignature(signature, false);
- if (AsterixBuiltinFunctions.isBuiltinCompilerFunction(normalizedSignature, includePrivateFunctions)) {
- continue;
- }
- StringBuilder messageBuilder = new StringBuilder();
- if (functionDecls.size() > 0) {
- messageBuilder.append("function " + functionDecls.get(functionDecls.size() - 1).getSignature()
- + " depends upon function " + signature + " which is undefined");
- } else {
- messageBuilder.append("function " + signature + " is undefined ");
- }
- throw new AsterixException(messageBuilder.toString());
- }
-
- if (function.getLanguage().equalsIgnoreCase(Function.LANGUAGE_AQL)) {
- FunctionDecl functionDecl = functionRepository.getFunctionDecl(function);
- if (functionDecl != null) {
- if (functionDecls.contains(functionDecl)) {
- throw new AsterixException(
- "Recursive invocation " + functionDecls.get(functionDecls.size() - 1).getSignature()
- + " <==> " + functionDecl.getSignature());
- }
- functionDecls.add(functionDecl);
- buildOtherUdfs(functionDecl.getFuncBody(), functionDecls, declaredFunctions);
- }
- }
- }
-
- }
-
- private Function lookupUserDefinedFunctionDecl(FunctionSignature signature) throws AsterixException {
- if (signature.getNamespace() == null) {
- return null;
- }
- return MetadataManager.INSTANCE.getFunction(mdTxnCtx, signature);
+ declaredFunctions.removeAll(usedStoredFunctionDecls);
}
private Set<FunctionSignature> getFunctionCalls(Expression expression) throws AsterixException {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/AqlMetadataProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/AqlMetadataProvider.java
index 41a843f..29087ba 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/AqlMetadataProvider.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/AqlMetadataProvider.java
@@ -26,10 +26,10 @@
import java.util.Map;
import org.apache.asterix.common.config.AsterixStorageProperties;
+import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.common.config.DatasetConfig.DatasetType;
import org.apache.asterix.common.config.DatasetConfig.ExternalFilePendingOp;
import org.apache.asterix.common.config.DatasetConfig.IndexType;
-import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.common.context.AsterixVirtualBufferCacheProvider;
import org.apache.asterix.common.context.ITransactionSubsystemProvider;
import org.apache.asterix.common.context.TransactionSubsystemProvider;
@@ -42,8 +42,8 @@
import org.apache.asterix.common.ioopcallbacks.LSMInvertedIndexIOOperationCallbackFactory;
import org.apache.asterix.common.ioopcallbacks.LSMRTreeIOOperationCallbackFactory;
import org.apache.asterix.common.library.ILibraryManager;
-import org.apache.asterix.common.transactions.IRecoveryManager.ResourceType;
import org.apache.asterix.common.transactions.JobId;
+import org.apache.asterix.common.transactions.IRecoveryManager.ResourceType;
import org.apache.asterix.common.utils.StoragePathUtil;
import org.apache.asterix.dataflow.data.nontagged.valueproviders.AqlPrimitiveValueProviderFactory;
import org.apache.asterix.external.adapter.factory.LookupAdapterFactory;
@@ -92,8 +92,8 @@
import org.apache.asterix.runtime.operators.AsterixLSMInvertedIndexUpsertOperatorDescriptor;
import org.apache.asterix.runtime.operators.AsterixLSMTreeUpsertOperatorDescriptor;
import org.apache.asterix.runtime.util.AsterixAppContextInfo;
-import org.apache.asterix.runtime.util.ClusterStateManager;
import org.apache.asterix.runtime.util.AsterixRuntimeComponentsProvider;
+import org.apache.asterix.runtime.util.ClusterStateManager;
import org.apache.asterix.transaction.management.opcallbacks.LockThenSearchOperationCallbackFactory;
import org.apache.asterix.transaction.management.opcallbacks.PrimaryIndexInstantSearchOperationCallbackFactory;
import org.apache.asterix.transaction.management.opcallbacks.PrimaryIndexModificationOperationCallbackFactory;
@@ -417,6 +417,10 @@
return format;
}
+ public Dataverse findDataverse(String dataverseName) throws AsterixException {
+ return MetadataManager.INSTANCE.getDataverse(mdTxnCtx, dataverseName);
+ }
+
public Triple<IOperatorDescriptor, AlgebricksPartitionConstraint, IAdapterFactory> buildFeedIntakeRuntime(
JobSpecification jobSpec, Feed primaryFeed, FeedPolicyAccessor policyAccessor) throws Exception {
Triple<IAdapterFactory, RecordDescriptor, IDataSourceAdapter.AdapterType> factoryOutput;