>From Abhishek Jindal <[email protected]>:

Abhishek Jindal has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19366 )


Change subject: [WIP] [ASTERIXDB-3526] : SQL++ Update support #5.1
......................................................................

[WIP] [ASTERIXDB-3526] : SQL++ Update support #5.1

Ensure the records generated by our data-transform functions
are of transform type, so as to prevent altering user passed object
types

Change-Id: I46d22b1eddc10795e99fef4983de0d705bdcb950
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RemoveDuplicateFieldsRule.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/ConstantFoldingVisitor.java
M 
asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/RecordConstructor.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
M 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
M 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
M 
asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
8 files changed, 134 insertions(+), 35 deletions(-)



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

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RemoveDuplicateFieldsRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RemoveDuplicateFieldsRule.java
index e924a4c..03ded65 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RemoveDuplicateFieldsRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RemoveDuplicateFieldsRule.java
@@ -103,10 +103,15 @@
         boolean changed = false;
         if 
(function.getFunctionIdentifier().equals(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR)
                 || 
function.getFunctionIdentifier().equals(BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR))
 {
+            Mutable<ILogicalExpression> finalArgRef = null;
             if (function.getArguments().size() % 2 != 0) {
-                String functionName = 
function.getFunctionIdentifier().getName();
-                throw 
CompilationException.create(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, 
expr.getSourceLocation(),
-                        functionName);
+                finalArgRef = 
function.getArguments().get(function.getArguments().size() - 1);
+                if (finalArgRef.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                    String functionName = 
function.getFunctionIdentifier().getName();
+                    throw 
CompilationException.create(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS,
+                            expr.getSourceLocation(), functionName);
+                }
+                function.getArguments().remove(function.getArguments().size() 
- 1);
             }
             fieldNames.clear();
             Iterator<Mutable<ILogicalExpression>> iterator = 
function.getArguments().iterator();
@@ -127,6 +132,8 @@
                     iterator.next();
                 }
             }
+            if (finalArgRef != null)
+                function.getArguments().add(finalArgRef);
         }
         List<Mutable<ILogicalExpression>> arguments = function.getArguments();
         for (int i = 0, size = arguments.size(); i < size; i++) {
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
index 50da592..c3b390a 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
@@ -110,35 +110,47 @@
             boolean changed = false;
             if 
(expr.getFunctionIdentifier().equals(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR)) 
{
                 ARecordType reqType = (ARecordType) 
TypeCastUtils.getRequiredType(expr);
+                boolean isTransform = false;
                 if (reqType == null || !reqType.isOpen()) {
+                    Mutable<ILogicalExpression> finalArgRef = null;
                     int n = expr.getArguments().size();
-                    if (n % 2 > 0) {
-                        throw new 
CompilationException(ErrorCode.COMPILATION_ERROR, expr.getSourceLocation(),
-                                "Record constructor expected to have an even 
number of arguments: "
-                                        + 
LogRedactionUtil.userData(expr.toString()));
+                    if (expr.getArguments().size() % 2 != 0) {
+                        finalArgRef = 
expr.getArguments().get(expr.getArguments().size() - 1);
+                        if (finalArgRef.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                            throw new 
CompilationException(ErrorCode.COMPILATION_ERROR, expr.getSourceLocation(),
+                                    "Record constructor expected to have an 
even number of arguments: "
+                                            + 
LogRedactionUtil.userData(expr.toString()));
+                        }
+                        ConstantExpression cExpr = (ConstantExpression) 
finalArgRef.getValue();
+                        isTransform = cExpr.getValue().isTrue();
                     }
-                    for (int i = 0; i < n / 2; i++) {
-                        ILogicalExpression a0 = expr.getArguments().get(2 * 
i).getValue();
-                        if (a0.getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
-                            allClosed = false;
+                    /** Only attempt to convert this record into a closed form 
if this is
+                     * not a transform_object type */
+                    if (!isTransform) {
+                        for (int i = 0; i < n / 2; i++) {
+                            ILogicalExpression a0 = expr.getArguments().get(2 
* i).getValue();
+                            if (a0.getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                                allClosed = false;
+                            }
+                            Mutable<ILogicalExpression> aRef1 = 
expr.getArguments().get(2 * i + 1);
+                            ILogicalExpression a1 = aRef1.getValue();
+                            ClosedDataInfo cdi = a1.accept(this, arg);
+                            if (!cdi.dataIsClosed) {
+                                allClosed = false;
+                            }
+                            if (cdi.expressionChanged) {
+                                aRef1.setValue(cdi.expression);
+                                changed = true;
+                            }
                         }
-                        Mutable<ILogicalExpression> aRef1 = 
expr.getArguments().get(2 * i + 1);
-                        ILogicalExpression a1 = aRef1.getValue();
-                        ClosedDataInfo cdi = a1.accept(this, arg);
-                        if (!cdi.dataIsClosed) {
-                            allClosed = false;
-                        }
-                        if (cdi.expressionChanged) {
-                            aRef1.setValue(cdi.expression);
+                        if (allClosed) {
+                            expr.setFunctionInfo(
+                                    
FunctionUtil.getFunctionInfo(BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR));
+                            AlgebricksConfig.ALGEBRICKS_LOGGER.trace(() -> 
"Switching to CLOSED record constructor in "
+                                    + 
LogRedactionUtil.userData(expr.toString()) + ".\n");
                             changed = true;
                         }
                     }
-                    if (allClosed) {
-                        
expr.setFunctionInfo(FunctionUtil.getFunctionInfo(BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR));
-                        AlgebricksConfig.ALGEBRICKS_LOGGER.trace(() -> 
"Switching to CLOSED record constructor in "
-                                + LogRedactionUtil.userData(expr.toString()) + 
".\n");
-                        changed = true;
-                    }
                 }
             } else {
                 boolean rewrite = true;
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/ConstantFoldingVisitor.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/ConstantFoldingVisitor.java
index 0feb6c5..e72fc47 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/ConstantFoldingVisitor.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/ConstantFoldingVisitor.java
@@ -294,10 +294,15 @@
     }

     private boolean foldRecordArgs(AbstractFunctionCallExpression expr, Void 
arg) throws AlgebricksException {
+        Mutable<ILogicalExpression> finalArgRef = null;
         if (expr.getArguments().size() % 2 != 0) {
-            String functionName = expr.getFunctionIdentifier().getName();
-            throw 
CompilationException.create(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, 
expr.getSourceLocation(),
-                    functionName);
+            finalArgRef = expr.getArguments().get(expr.getArguments().size() - 
1);
+            if (finalArgRef.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                String functionName = expr.getFunctionIdentifier().getName();
+                throw 
CompilationException.create(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, 
expr.getSourceLocation(),
+                        functionName);
+            }
+            expr.getArguments().remove(expr.getArguments().size() - 1);
         }
         boolean changed = false;
         Iterator<Mutable<ILogicalExpression>> iterator = 
expr.getArguments().iterator();
@@ -331,6 +336,8 @@
                 fieldNameIdx += 2;
             }
         }
+        if (finalArgRef != null)
+            expr.getArguments().add(finalArgRef);
         return changed;
     }

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..b337d9d 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
@@ -1676,6 +1676,9 @@
             f.getArguments().add(new MutableObject<>(eo2.first));
             topOp = eo2.second;
         }
+        if (rc.isTransformRecord()) {
+            f.getArguments().add(new 
MutableObject<>(createConstantExpression(ABoolean.TRUE, 
rc.getSourceLocation())));
+        }
         a.getInputs().add(topOp);
         return new Pair<>(a, v1);
     }
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/RecordConstructor.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/RecordConstructor.java
index cce92e6..3fb4a63 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/RecordConstructor.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/RecordConstructor.java
@@ -27,16 +27,22 @@

 public class RecordConstructor extends AbstractExpression {
     private List<FieldBinding> fbList;
+    private boolean isTransformRecord;

     public RecordConstructor() {
         super();
     }

     public RecordConstructor(List<FieldBinding> fbList) {
-        super();
+        this();
         this.fbList = fbList;
     }

+    public RecordConstructor(List<FieldBinding> fbList, boolean 
isTransformRecord) {
+        this(fbList);
+        this.isTransformRecord = isTransformRecord;
+    }
+
     public List<FieldBinding> getFbList() {
         return fbList;
     }
@@ -45,6 +51,10 @@
         this.fbList = fbList;
     }

+    public boolean isTransformRecord() {
+        return isTransformRecord;
+    }
+
     @Override
     public Kind getKind() {
         return Kind.RECORD_CONSTRUCTOR_EXPRESSION;
@@ -71,4 +81,4 @@
         RecordConstructor target = (RecordConstructor) object;
         return Objects.equals(fbList, target.fbList);
     }
-}
+}
\ No newline at end of file
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java
index 9262a1e..b1ca0628 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/SetExpressionTree.java
@@ -142,9 +142,9 @@
         Expression deletionRecord = null;
         Expression setRecord = null;
         if (setRecordArgs.size() > 0)
-            setRecord = new RecordConstructor(setRecordArgs);
+            setRecord = new RecordConstructor(setRecordArgs, true);
         if (deletionRecordArgs.size() > 0)
-            deletionRecord = new RecordConstructor(deletionRecordArgs);
+            deletionRecord = new RecordConstructor(deletionRecordArgs, false);
         return new Pair<>(setRecord, deletionRecord);
     }

diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
index d3cb2d7..14a19dc 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
@@ -24,6 +24,7 @@
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.om.exceptions.InvalidExpressionException;
+import org.apache.asterix.om.exceptions.TypeMismatchException;
 import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
 import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
 import org.apache.asterix.om.types.ARecordType;
@@ -36,6 +37,7 @@
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
 import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
 import org.apache.hyracks.util.LogRedactionUtil;
@@ -57,6 +59,21 @@
             return type;
         }

+        Mutable<ILogicalExpression> finalArgRef = null;
+        boolean isTransform = false;
+        if (f.getArguments().size() % 2 != 0) {
+            finalArgRef = f.getArguments().get(f.getArguments().size() - 1);
+            if (finalArgRef.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                IAType finalArgType = (IAType) 
env.getType(finalArgRef.getValue());
+                throw new TypeMismatchException(f.getSourceLocation(), 
f.getFunctionIdentifier(),
+                        f.getArguments().size() - 1, 
finalArgType.getTypeTag(), ATypeTag.BOOLEAN);
+            }
+            ConstantExpression cExpr = (ConstantExpression) 
finalArgRef.getValue();
+            if (cExpr.getValue().isTrue())
+                isTransform = true;
+            f.getArguments().remove(f.getArguments().size() - 1);
+        }
+
         int n = f.getArguments().size() / 2;
         String[] fieldNames = new String[n];
         IAType[] fieldTypes = new IAType[n];
@@ -85,6 +102,11 @@
             fieldNames[i] = fieldName;
             i++;
         }
-        return new ARecordType(null, fieldNames, fieldTypes, false);
+
+        if (finalArgRef != null)
+            f.getArguments().add(finalArgRef);
+        ARecordType resultType = new ARecordType(null, fieldNames, fieldTypes, 
false);
+        resultType.setIsTransform(isTransform);
+        return resultType;
     }
-}
+}
\ No newline at end of file
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
index 8358627..02ac4b6 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
@@ -31,6 +31,7 @@
 import org.apache.asterix.common.config.CompilerProperties;
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.om.exceptions.TypeMismatchException;
 import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
 import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
 import org.apache.asterix.om.types.ARecordType;
@@ -42,7 +43,9 @@
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
 import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
 import org.apache.hyracks.algebricks.core.config.AlgebricksConfig;
@@ -72,6 +75,21 @@
                     
.getOrDefault(CompilerProperties.COMPILER_ORDERED_FIELDS_KEY, 
String.valueOf(orderFields)));
         }

+        Mutable<ILogicalExpression> finalArgRef = null;
+        boolean isTransform = false;
+        if (f.getArguments().size() % 2 != 0) {
+            finalArgRef = f.getArguments().get(f.getArguments().size() - 1);
+            if (finalArgRef.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                IAType finalArgType = (IAType) 
env.getType(finalArgRef.getValue());
+                throw new TypeMismatchException(f.getSourceLocation(), 
f.getFunctionIdentifier(),
+                        f.getArguments().size() - 1, 
finalArgType.getTypeTag(), ATypeTag.BOOLEAN);
+            }
+            ConstantExpression cExpr = (ConstantExpression) 
finalArgRef.getValue();
+            if (cExpr.getValue().isTrue())
+                isTransform = true;
+            f.getArguments().remove(f.getArguments().size() - 1);
+        }
+
         Iterator<Mutable<ILogicalExpression>> argIter = 
f.getArguments().iterator();
         List<String> namesList = new ArrayList<>();
         List<IAType> typesList = new ArrayList<>();
@@ -108,6 +126,12 @@
             }
             allPossibleFieldNamesOrdered.add(fieldName);
         }
+        if (finalArgRef != null)
+            f.getArguments().add(finalArgRef);
+        // We always want the transform record to be welcoming of other fields
+        // from the data transformation apart from itself. This is why such is 
record is always open.
+        if (isTransform)
+            isOpen = true;
         String[] fieldNames = namesList.toArray(new String[0]);
         IAType[] fieldTypes = typesList.toArray(new IAType[0]);
         ARecordType resultType;
@@ -122,6 +146,7 @@
         } else {
             resultType = new ARecordType(null, fieldNames, fieldTypes, isOpen);
         }
+        resultType.setIsTransform(isTransform);
         return resultType;
     }
-}
+}
\ No newline at end of file

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19366
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: I46d22b1eddc10795e99fef4983de0d705bdcb950
Gerrit-Change-Number: 19366
Gerrit-PatchSet: 1
Gerrit-Owner: Abhishek Jindal <[email protected]>
Gerrit-MessageType: newchange

Reply via email to