>From Peeyush Gupta <[email protected]>:

Peeyush Gupta has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19309 )


Change subject: wip: transform function
......................................................................

wip: transform function

Change-Id: I670c5f28a3dc52e78a978b357b4a8b3705267bc2
---
M 
asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
M 
asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
M 
asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
M 
asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/FunctionDecl.java
M 
asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataTransactionContext.java
M 
asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
M 
hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialOnceRuleController.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
M 
asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
M 
hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialFixpointRuleController.java
M asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
M asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
M 
asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
17 files changed, 136 insertions(+), 26 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/09/19309/1

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 978997c..1ffd227 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -488,6 +488,16 @@
         return isFileStore ? 
String.valueOf(ExternalWriterProvider.getSeparator(adapter)) : "";
     }

+    private LogicalVariable getUnnestVar(ILogicalOperator op) {
+        while (op.getOperatorTag() != LogicalOperatorTag.UNNEST && 
!op.getInputs().isEmpty()) {
+            op = op.getInputs().get(0).getValue();
+        }
+        if (op.getOperatorTag() == LogicalOperatorTag.UNNEST) {
+            return ((UnnestOperator) op).getVariable();
+        }
+        return null;
+    }
+
     public ILogicalPlan translate(Query expr, String outputDatasetName, 
ICompiledDmlStatement stmt,
             ILogicalOperator baseOp, IResultMetadata resultMetadata) throws 
AlgebricksException {
         MutableObject<ILogicalOperator> base = new MutableObject<>(new 
EmptyTupleSourceOperator());
@@ -500,8 +510,8 @@
         ILogicalOperator topOp = p.first;
         List<LogicalVariable> liveVars = new ArrayList<>();
         VariableUtilities.getLiveVariables(topOp, liveVars);
-        LogicalVariable unnestVar = liveVars.get(0);
-        LogicalVariable resVar = unnestVar;
+        LogicalVariable unnestVar = getUnnestVar(topOp);
+        LogicalVariable resVar = liveVars.get(0);

         if (outputDatasetName == null) {
             FileSplit outputFileSplit = metadataProvider.getOutputFile();
diff --git 
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
 
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index ed93838..49d8c18 100644
--- 
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ 
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -49,6 +49,8 @@
 import org.apache.asterix.active.EntityId;
 import org.apache.asterix.active.IActiveEntityEventsListener;
 import org.apache.asterix.active.NoRetryPolicyFactory;
+import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslator;
+import org.apache.asterix.algebra.base.ILangExpressionToPlanTranslatorFactory;
 import org.apache.asterix.algebra.extension.ExtensionStatement;
 import org.apache.asterix.api.common.APIFramework;
 import org.apache.asterix.api.http.server.AbstractQueryApiServlet;
@@ -242,6 +244,7 @@
 import org.apache.asterix.translator.ExecutionPlansHtmlPrintUtil;
 import org.apache.asterix.translator.IRequestParameters;
 import org.apache.asterix.translator.IStatementExecutor;
+import org.apache.asterix.translator.ResultMetadata;
 import org.apache.asterix.translator.SchedulableClientRequest;
 import org.apache.asterix.translator.SessionConfig;
 import org.apache.asterix.translator.SessionOutput;
@@ -258,6 +261,9 @@
 import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.core.algebra.base.Counter;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression.FunctionKind;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
@@ -3260,10 +3266,14 @@
                 function = new Function(functionSignature, paramNames, 
paramTypes, returnTypeSignature, null,
                         FunctionKind.SCALAR.toString(), library.getLanguage(), 
libraryDatabaseName,
                         libraryDataverseName, libraryName, externalIdentifier, 
cfs.getNullCall(),
-                        cfs.getDeterministic(), cfs.getResources(), 
dependencies, creator);
+                        cfs.getDeterministic(), cfs.getResources(), 
dependencies, creator, false);
             } else {
                 List<Pair<VarIdentifier, TypeExpression>> paramList = 
cfs.getParameters();
                 int paramCount = paramList.size();
+                if (cfs.isTransform() && paramCount != 1) {
+                    throw new 
CompilationException(ErrorCode.INVALID_TRANSFORM_FUNCTION, sourceLoc,
+                            "Transform function can only have one parameter");
+                }
                 List<VarIdentifier> paramVars = new ArrayList<>(paramCount);
                 List<String> paramNames = new ArrayList<>(paramCount);
                 for (Pair<VarIdentifier, TypeExpression> paramPair : 
paramList) {
@@ -3279,7 +3289,8 @@
                 // Check whether the function is usable:
                 // create a function declaration for this function,
                 // and a query body calls this function with each argument set 
to 'missing'
-                FunctionDecl fd = new FunctionDecl(functionSignature, 
paramVars, cfs.getFunctionBodyExpression(), true);
+                FunctionDecl fd = new FunctionDecl(functionSignature, 
paramVars, cfs.getFunctionBodyExpression(), true,
+                        cfs.isTransform());
                 fd.setSourceLocation(sourceLoc);

                 Query wrappedQuery = 
queryRewriter.createFunctionAccessorQuery(fd);
@@ -3289,17 +3300,44 @@
                 metadataProvider.setDefaultNamespace(ns);
                 LangRewritingContext langRewritingContext = 
createLangRewritingContext(metadataProvider, fdList, null,
                         null, warningCollector, wrappedQuery.getVarCounter());
-                apiFramework.reWriteQuery(langRewritingContext, wrappedQuery, 
sessionOutput, false, false,
-                        Collections.emptyList());
+                List<VarIdentifier> externalVars = new ArrayList<>();
+                Pair<IReturningStatement, Integer> rewrittenResult = 
apiFramework.reWriteQuery(langRewritingContext,
+                        wrappedQuery, sessionOutput, false, true, 
externalVars);

                 List<List<DependencyFullyQualifiedName>> dependencies =
                         FunctionUtil.getFunctionDependencies(metadataProvider, 
fd, queryRewriter);
+                if (cfs.isTransform()) {
+                    if (!dependencies.get(0).isEmpty()) {
+                        throw new 
CompilationException(ErrorCode.INVALID_TRANSFORM_FUNCTION, sourceLoc,
+                                "Function definition uses one or more 
datasets");
+                    }
+                    ILangExpressionToPlanTranslatorFactory translatorFactory =
+                            
compilationProvider.getExpressionToPlanTranslatorFactory();
+                    ILangExpressionToPlanTranslator t = translatorFactory
+                            
.createExpressionToPlanTranslator(metadataProvider, rewrittenResult.second, 
null);
+                    org.apache.asterix.translator.ResultMetadata 
resultMetadata =
+                            new 
org.apache.asterix.translator.ResultMetadata(sessionOutput.config().fmt());
+                    ILogicalPlan plan = t.translate((Query) 
rewrittenResult.first, null, null, resultMetadata);
+                    if (plan.getRoots().size() != 1) {
+                        throw new 
CompilationException(ErrorCode.INVALID_TRANSFORM_FUNCTION, sourceLoc,
+                                "Function has more than one root");
+                    }
+                    ILogicalOperator op = 
plan.getRoots().get(0).getValue().getInputs().get(0).getValue();
+                    if (op.getOperatorTag() == LogicalOperatorTag.AGGREGATE) {
+                        if 
(!OperatorPropertiesUtil.isCardinalityZeroOrOne(op.getInputs().get(0).getValue()))
 {
+                            throw new 
CompilationException(ErrorCode.INVALID_TRANSFORM_FUNCTION, sourceLoc,
+                                    "Function can return more than one row");
+                        }
+                    } else {
+                        throw new 
CompilationException(ErrorCode.INVALID_TRANSFORM_FUNCTION, sourceLoc,
+                                "Function does not contain a query");
+                    }
+                }
                 appCtx.getReceptionist().ensureAuthorized(requestParameters, 
metadataProvider);
-
                 newInlineTypes = Collections.emptyMap();
                 function = new Function(functionSignature, paramNames, null, 
null, cfs.getFunctionBody(),
                         FunctionKind.SCALAR.toString(), 
compilationProvider.getParserFactory().getLanguage(), null,
-                        null, null, null, null, null, null, dependencies, 
creator);
+                        null, null, null, null, null, null, dependencies, 
creator, cfs.isTransform());
             }

             if (existingFunction == null) {
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index 35e0699..1d43a6b 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -316,6 +316,7 @@
     COULD_NOT_CREATE_TOKENS(1211),
     NO_AWS_VALID_PARAMS_FOUND_FOR_CROSS_ACCOUNT_TRUST_AUTHENTICATION(1212),
     FAILED_EXTERNAL_CROSS_ACCOUNT_AUTHENTICATION(1213),
+    INVALID_TRANSFORM_FUNCTION(1214),

     // Feed errors
     DATAFLOW_ILLEGAL_STATE(3001),
diff --git 
a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties 
b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index d15a751..1a61541 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -318,6 +318,7 @@
 1211 = Could not create delegation tokens
 1212 = No credentials found for cross-account authentication. Expected 
instance profile or access key id & secret access key for assuming role
 1213 = Failed to perform cross-account authentication. Encountered error : 
'%1$s'
+1214 = Failed to create transform function. Encountered error: '%1$s'

 # Feed Errors
 3001 = Illegal state.
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
index e0623a1..74b7bbd 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
@@ -63,9 +63,11 @@

     private final boolean replaceIfExists;
     private final boolean ifNotExists;
+    private final boolean transform;

     public CreateFunctionStatement(FunctionSignature signature, 
List<Pair<VarIdentifier, TypeExpression>> paramList,
-            String functionBody, Expression functionBodyExpression, boolean 
replaceIfExists, boolean ifNotExists) {
+            String functionBody, Expression functionBodyExpression, boolean 
replaceIfExists, boolean ifNotExists,
+            boolean transform) {
         this.signature = signature;
         this.functionBody = functionBody;
         this.functionBodyExpression = functionBodyExpression;
@@ -77,6 +79,7 @@
         this.options = null;
         this.replaceIfExists = replaceIfExists;
         this.ifNotExists = ifNotExists;
+        this.transform = transform;
     }

     public CreateFunctionStatement(FunctionSignature signature, 
List<Pair<VarIdentifier, TypeExpression>> paramList,
@@ -93,6 +96,7 @@
         this.functionBodyExpression = null;
         this.replaceIfExists = replaceIfExists;
         this.ifNotExists = ifNotExists;
+        this.transform = false;
     }

     public boolean getReplaceIfExists() {
@@ -196,6 +200,10 @@
         return Category.DDL;
     }

+    public boolean isTransform() {
+        return transform;
+    }
+
     private IAdmNode getOption(String optionName) {
         return options != null ? options.get(optionName) : null;
     }
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/FunctionDecl.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/FunctionDecl.java
index 2ef11ad..1a924ee 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/FunctionDecl.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/FunctionDecl.java
@@ -34,13 +34,20 @@
     private Expression funcBody;
     private Expression funcBodyNormalized;
     private final boolean isStored;
+    private final boolean transform;

     public FunctionDecl(FunctionSignature signature, List<VarIdentifier> 
paramList, Expression funcBody,
-            boolean isStored) {
+            boolean isStored, boolean transform) {
         this.signature = signature;
         this.paramList = paramList;
         this.funcBody = funcBody;
         this.isStored = isStored;
+        this.transform = transform;
+    }
+
+    public FunctionDecl(FunctionSignature signature, List<VarIdentifier> 
paramList, Expression funcBody,
+            boolean isStored) {
+        this(signature, paramList, funcBody, isStored, false);
     }

     public FunctionSignature getSignature() {
@@ -72,6 +79,10 @@
         return isStored;
     }

+    public boolean isTransform() {
+        return transform;
+    }
+
     @Override
     public int hashCode() {
         return signature.hashCode();
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
index 06f22b7..4f09722 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
@@ -179,7 +179,8 @@
         }

         Pair<ILangExpression, VariableSubstitutionEnvironment> p1 = 
fd.getFuncBody().accept(this, env);
-        FunctionDecl newF = new FunctionDecl(fd.getSignature(), newList, 
(Expression) p1.first, fd.isStored());
+        FunctionDecl newF =
+                new FunctionDecl(fd.getSignature(), newList, (Expression) 
p1.first, fd.isStored(), fd.isTransform());
         newF.setSourceLocation(fd.getSourceLocation());
         return new Pair<>(newF, env);
     }
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
index 32549d9..40933f6 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
@@ -70,11 +70,11 @@
     @Override
     public void rewrite(LangRewritingContext context, IReturningStatement 
topStatement, boolean allowNonStoredUdfCalls,
             boolean inlineUdfsAndViews, Collection<VarIdentifier> 
externalVars) throws CompilationException {
-        if (inlineUdfsAndViews) {
-            // When rewriting function or view body we do not inline UDFs or 
views into it.
-            // The main query rewriter will inline everything later, when it 
processes the query
-            throw new CompilationException(ErrorCode.ILLEGAL_STATE, 
topStatement.getSourceLocation(), "");
-        }
+        //        if (inlineUdfsAndViews) {
+        //            // When rewriting function or view body we do not inline 
UDFs or views into it.
+        //            // The main query rewriter will inline everything later, 
when it processes the query
+        //            throw new CompilationException(ErrorCode.ILLEGAL_STATE, 
topStatement.getSourceLocation(), "");
+        //        }

         // Sets up parameters.
         setup(context, topStatement, externalVars, allowNonStoredUdfCalls, 
inlineUdfsAndViews);
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 15865a2..478e1f4 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
@@ -44,9 +44,8 @@
 import org.apache.asterix.lang.common.expression.AbstractCallExpression;
 import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.FieldAccessor;
-import org.apache.asterix.lang.common.expression.LiteralExpr;
+import org.apache.asterix.lang.common.expression.RecordConstructor;
 import org.apache.asterix.lang.common.expression.VariableExpr;
-import org.apache.asterix.lang.common.literal.MissingLiteral;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.DatasetDecl;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
@@ -633,7 +632,7 @@
         FunctionSignature functionSignature = functionDecl.getSignature();
         int arity = functionSignature.getArity();
         List<Expression> args = arity == FunctionIdentifier.VARARGS ? 
Collections.emptyList()
-                : Collections.nCopies(arity, new 
LiteralExpr(MissingLiteral.INSTANCE));
+                : Collections.nCopies(arity, new 
RecordConstructor(Collections.emptyList()));
         CallExpr fcall = new CallExpr(functionSignature, args);
         fcall.setSourceLocation(functionDecl.getSourceLocation());
         return ExpressionUtils.createWrappedQuery(fcall, 
functionDecl.getSourceLocation());
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
index 1d43d0b..9941dde 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
@@ -267,7 +267,7 @@
     @Override
     public FunctionDecl visit(FunctionDecl fd, Void arg) throws 
CompilationException {
         FunctionDecl copy = new FunctionDecl(fd.getSignature(), 
fd.getParamList(),
-                (Expression) fd.getFuncBody().accept(this, arg), 
fd.isStored());
+                (Expression) fd.getFuncBody().accept(this, arg), 
fd.isStored(), fd.isTransform());
         copy.setSourceLocation(fd.getSourceLocation());
         return copy;
     }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj 
b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 6b3aa54..151cd52 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -1863,13 +1863,18 @@
   CreateFunctionStatement stmt = null;
 }
 {
-  <FUNCTION> stmt = FunctionSpecification(startStmtToken, orReplace)
+  <TRANSFORM> <FUNCTION> stmt = FunctionSpecification(startStmtToken, 
orReplace, true)
+  {
+    return stmt;
+  }
+  |
+  <FUNCTION> stmt = FunctionSpecification(startStmtToken, orReplace, false)
   {
     return stmt;
   }
 }

-CreateFunctionStatement FunctionSpecification(Token startStmtToken, boolean 
orReplace) throws ParseException:
+CreateFunctionStatement FunctionSpecification(Token startStmtToken, boolean 
orReplace, boolean transform) throws ParseException:
 {
   FunctionSignature signature = null;
   FunctionName fctName = null;
@@ -1924,7 +1929,7 @@
         getCurrentScope().addFunctionDescriptor(signature, false);
         removeCurrentScope();
         ensureNoTypeDeclsInFunction(fctName.function, params, returnType, 
startStmtToken);
-        stmt = new CreateFunctionStatement(signature, params, functionBody, 
functionBodyExpr, orReplace, ifNotExists);
+        stmt = new CreateFunctionStatement(signature, params, functionBody, 
functionBodyExpr, orReplace, ifNotExists, transform);
       }
     )
   |
@@ -6062,6 +6067,7 @@
   | <WITH : "with">
   | <WRITE : "write">
   | <COPY : "copy">
+  | <TRANSFORM : "transform">
 }

 <DEFAULT,IN_DBL_BRACE>
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataTransactionContext.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataTransactionContext.java
index 70bf83a..8db32d6 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataTransactionContext.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataTransactionContext.java
@@ -203,7 +203,7 @@

     public void dropFunction(FunctionSignature signature) {
         Function function = new Function(signature, null, null, null, null, 
null, null, null, null, null, null, false,
-                false, null, null, null);
+                false, null, null, null, false);
         droppedCache.addFunctionIfNotExists(function);
         logAndApply(new MetadataLogicalOperation(function, false));
     }
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
index 338e00d..31a7f9b 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
@@ -53,6 +53,7 @@
     public static final String FIELD_NAME_DEFAULT = "Default";
     public static final String FIELD_NAME_DEFINITION = "Definition";
     public static final String FIELD_NAME_DEPENDENCIES = "Dependencies";
+    public static final String FIELD_NAME_IS_TRANSFORM = "IsTransform";
     public static final String FIELD_NAME_DERIVED = "Derived";
     public static final String FIELD_NAME_DESCRIPTION = "Description";
     public static final String FIELD_NAME_EXTERNAL_DETAILS = "ExternalDetails";
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
index 3c1515b..c19b542 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
@@ -51,12 +51,13 @@
     private final Map<String, String> resources;
     private final List<List<DependencyFullyQualifiedName>> dependencies;
     private final Creator creator;
+    private final boolean transform;

     public Function(FunctionSignature signature, List<String> paramNames, 
List<TypeSignature> paramTypes,
             TypeSignature returnType, String functionBody, String 
functionKind, String language,
             String libraryDatabaseName, DataverseName libraryDataverseName, 
String libraryName,
             List<String> externalIdentifier, Boolean nullCall, Boolean 
deterministic, Map<String, String> resources,
-            List<List<DependencyFullyQualifiedName>> dependencies, Creator 
creator) {
+            List<List<DependencyFullyQualifiedName>> dependencies, Creator 
creator, boolean transform) {
         this.signature = signature;
         this.paramNames = paramNames;
         this.paramTypes = paramTypes;
@@ -75,6 +76,7 @@
                 ? Arrays.asList(Collections.emptyList(), 
Collections.emptyList(), Collections.emptyList())
                 : dependencies;
         this.creator = creator;
+        this.transform = transform;
     }

     public FunctionSignature getSignature() {
@@ -168,6 +170,10 @@
         return creator;
     }

+    public boolean isTransform() {
+        return transform;
+    }
+
     @Override
     public Function addToCache(MetadataCache cache) {
         return cache.addFunctionIfNotExists(this);
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
index 2741d12..2319cb0 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
@@ -206,9 +206,14 @@
         FunctionSignature signature = new FunctionSignature(databaseName, 
dataverseName, functionName, arity);
         Creator creator = Creator.createOrDefault(functionRecord);

+        int isTransformIndex = 
functionRecord.getType().getFieldIndex(MetadataRecordTypes.FIELD_NAME_IS_TRANSFORM);
+        boolean transform = false;
+        if (isTransformIndex >= 0) {
+            transform = ((ABoolean) 
functionRecord.getValueByPos(isTransformIndex)).getBoolean();
+        }
         return new Function(signature, paramNames, paramTypes, returnType, 
definition, functionKind, language,
                 libraryDatabaseName, libraryDataverseName, libraryName, 
externalIdentifier, nullCall, deterministic,
-                resources, dependencies, creator);
+                resources, dependencies, creator, transform);
     }

     private List<TypeSignature> getParamTypes(ARecord functionRecord, String 
functionDatabaseName,
@@ -435,6 +440,7 @@
         writeNullCall(function);
         writeDeterministic(function);
         writeFunctionCreator(function);
+        writeIsTransform(function);
     }

     protected void writeResources(Function function) throws 
HyracksDataException {
@@ -722,4 +728,15 @@
             recordBuilder.addField(fieldName, fieldValue);
         }
     }
+
+    private void writeIsTransform(Function function) throws 
HyracksDataException {
+        if (function.isTransform()) {
+            fieldName.reset();
+            aString.setValue(MetadataRecordTypes.FIELD_NAME_IS_TRANSFORM);
+            stringSerde.serialize(aString, fieldName.getDataOutput());
+            fieldValue.reset();
+            booleanSerde.serialize(ABoolean.TRUE, fieldValue.getDataOutput());
+            recordBuilder.addField(fieldName, fieldValue);
+        }
+    }
 }
diff --git 
a/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialFixpointRuleController.java
 
b/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialFixpointRuleController.java
index bbe281d..d4aed42 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialFixpointRuleController.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialFixpointRuleController.java
@@ -53,6 +53,7 @@
                 if (ruleFired) {
                     anyChange = true;
                     anyRuleFired = true;
+                    writePlan(planFor(root), rule, "");
                 }
             }
         } while (anyChange);
diff --git 
a/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialOnceRuleController.java
 
b/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialOnceRuleController.java
index 1090fe1..e660407 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialOnceRuleController.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-compiler/src/main/java/org/apache/hyracks/algebricks/compiler/rewriter/rulecontrollers/SequentialOnceRuleController.java
@@ -42,6 +42,7 @@
         for (IAlgebraicRewriteRule rule : rules) {
             if (rewriteOperatorRef(root, rule, enterNestedPlans, true, false)) 
{
                 fired = true;
+                writePlan(planFor(root), rule, "");
             }
         }
         return fired;

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19309
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: I670c5f28a3dc52e78a978b357b4a8b3705267bc2
Gerrit-Change-Number: 19309
Gerrit-PatchSet: 1
Gerrit-Owner: Peeyush Gupta <[email protected]>
Gerrit-MessageType: newchange

Reply via email to