[NO-ISSUE][COMP] Copy hint when replicate OperatorExpr

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
The hints are not copied over when Copy or Clone OperatorExpr.

Change-Id: I5eef37e525b7d1bec842e3488d8b63f88ddc05ea
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2722
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/AbstractExpression.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/AbstractExpression.java
index 773268f..744d3cc 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/AbstractExpression.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/AbstractExpression.java
@@ -23,17 +23,34 @@
 
 import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
 
+/**
+ * All subclasses need to make sure the hints are copied over in the DeepCopyVisitor and
+ * CloneAndSubstituteVariablesVisitor
+ */
 public abstract class AbstractExpression extends AbstractLangExpression implements Expression {
 
     protected List<IExpressionAnnotation> hints;
 
     public void addHint(IExpressionAnnotation hint) {
+        if (hint == null) {
+            return;
+        }
         if (hints == null) {
             hints = new ArrayList<>();
         }
         hints.add(hint);
     }
 
+    public void addHints(List<IExpressionAnnotation> newHints) {
+        if (newHints == null) {
+            return;
+        }
+        if (hints == null) {
+            hints = new ArrayList<>();
+        }
+        hints.addAll(newHints);
+    }
+
     public boolean hasHints() {
         return hints != null;
     }
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 64023a8..e415a63 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
@@ -130,6 +130,7 @@
         Pair<ILangExpression, VariableSubstitutionEnvironment> p2 = qe.getSatisfiesExpr().accept(this, newSubs);
         QuantifiedExpression qe2 = new QuantifiedExpression(qe.getQuantifier(), newPairs, (Expression) p2.first);
         qe2.setSourceLocation(qe.getSourceLocation());
+        qe2.addHints(qe.getHints());
         return new Pair<>(qe2, newSubs);
     }
 
@@ -148,6 +149,7 @@
         List<Expression> exprList = VariableCloneAndSubstitutionUtil.visitAndCloneExprList(pf.getExprList(), env, this);
         CallExpr f = new CallExpr(pf.getFunctionSignature(), exprList);
         f.setSourceLocation(pf.getSourceLocation());
+        f.addHints(pf.getHints());
         return new Pair<>(f, env);
     }
 
@@ -183,6 +185,7 @@
         Pair<ILangExpression, VariableSubstitutionEnvironment> p3 = ifexpr.getElseExpr().accept(this, env);
         IfExpr i = new IfExpr((Expression) p1.first, (Expression) p2.first, (Expression) p3.first);
         i.setSourceLocation(ifexpr.getSourceLocation());
+        i.addHints(ifexpr.getHints());
         return new Pair<>(i, env);
     }
 
@@ -209,6 +212,7 @@
         List<Expression> exprs = VariableCloneAndSubstitutionUtil.visitAndCloneExprList(oldExprList, env, this);
         ListConstructor c = new ListConstructor(lc.getType(), exprs);
         c.setSourceLocation(lc.getSourceLocation());
+        c.addHints(lc.getHints());
         return new Pair<>(c, env);
     }
 
@@ -229,6 +233,7 @@
         }
         OperatorExpr oe = new OperatorExpr(exprs, op.getExprBroadcastIdx(), op.getOpList(), op.isCurrentop());
         oe.setSourceLocation(op.getSourceLocation());
+        oe.addHints(op.getHints());
         return new Pair<>(oe, env);
     }
 
@@ -268,6 +273,7 @@
         }
         RecordConstructor newRc = new RecordConstructor(newFbs);
         newRc.setSourceLocation(rc.getSourceLocation());
+        newRc.addHints(rc.getHints());
         return new Pair<>(newRc, env);
     }
 
@@ -277,6 +283,7 @@
         Pair<ILangExpression, VariableSubstitutionEnvironment> p1 = u.getExpr().accept(this, env);
         UnaryExpr newU = new UnaryExpr(u.getExprType(), (Expression) p1.first);
         newU.setSourceLocation(u.getSourceLocation());
+        newU.addHints(u.getHints());
         return new Pair<>(newU, env);
     }
 
@@ -292,6 +299,7 @@
         IndexAccessor i = new IndexAccessor((Expression) p1.first, indexExpr);
         i.setAny(ia.isAny());
         i.setSourceLocation(ia.getSourceLocation());
+        i.addHints(ia.getHints());
         return new Pair<>(i, env);
     }
 
@@ -301,6 +309,7 @@
         Pair<ILangExpression, VariableSubstitutionEnvironment> p = fa.getExpr().accept(this, env);
         FieldAccessor newF = new FieldAccessor((Expression) p.first, fa.getIdent());
         newF.setSourceLocation(fa.getSourceLocation());
+        newF.addHints(fa.getHints());
         return new Pair<>(newF, p.second);
     }
 
@@ -321,6 +330,7 @@
             if (var != null) {
                 VariableExpr newVarExpr = new VariableExpr(var);
                 newVarExpr.setSourceLocation(expr.getSourceLocation());
+                newVarExpr.addHints(expr.getHints());
                 return newVarExpr;
             }
         }
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 fbe9eb5..766540e 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
@@ -364,7 +364,11 @@
         if (selectExpression.hasLimit()) {
             limit = (LimitClause) selectExpression.getLimitClause().accept(this, arg);
         }
-        return new SelectExpression(lets, select, orderby, limit, selectExpression.isSubquery());
+
+        SelectExpression copy = new SelectExpression(lets, select, orderby, limit, selectExpression.isSubquery());
+        copy.addHints(selectExpression.getHints());
+
+        return copy;
     }
 
     @Override
@@ -376,6 +380,7 @@
     public ListConstructor visit(ListConstructor lc, Void arg) throws CompilationException {
         ListConstructor copy = new ListConstructor(lc.getType(), copyExprList(lc.getExprList(), arg));
         copy.setSourceLocation(lc.getSourceLocation());
+        copy.addHints(lc.getHints());
         return copy;
     }
 
@@ -389,6 +394,7 @@
         }
         RecordConstructor copy = new RecordConstructor(bindings);
         copy.setSourceLocation(rc.getSourceLocation());
+        copy.addHints(rc.getHints());
         return copy;
     }
 
@@ -397,6 +403,7 @@
         OperatorExpr copy = new OperatorExpr(copyExprList(operatorExpr.getExprList(), arg),
                 operatorExpr.getExprBroadcastIdx(), operatorExpr.getOpList(), operatorExpr.isCurrentop());
         copy.setSourceLocation(operatorExpr.getSourceLocation());
+        copy.addHints(operatorExpr.getHints());
         return copy;
     }
 
@@ -407,6 +414,7 @@
         Expression elseExpr = (Expression) ifExpr.getElseExpr().accept(this, arg);
         IfExpr copy = new IfExpr(conditionExpr, thenExpr, elseExpr);
         copy.setSourceLocation(ifExpr.getSourceLocation());
+        copy.addHints(ifExpr.getHints());
         return copy;
     }
 
@@ -421,6 +429,7 @@
         Expression condition = (Expression) qe.getSatisfiesExpr().accept(this, arg);
         QuantifiedExpression copy = new QuantifiedExpression(qe.getQuantifier(), quantifiedPairs, condition);
         copy.setSourceLocation(qe.getSourceLocation());
+        copy.addHints(qe.getHints());
         return copy;
     }
 
@@ -432,6 +441,7 @@
         }
         CallExpr copy = new CallExpr(callExpr.getFunctionSignature(), newExprList);
         copy.setSourceLocation(callExpr.getSourceLocation());
+        copy.addHints(callExpr.getHints());
         return copy;
     }
 
@@ -440,6 +450,7 @@
         VariableExpr clonedVar = new VariableExpr(new VarIdentifier(varExpr.getVar()));
         clonedVar.setSourceLocation(varExpr.getSourceLocation());
         clonedVar.setIsNewVar(varExpr.getIsNewVar());
+        clonedVar.addHints(varExpr.getHints());
         return clonedVar;
     }
 
@@ -447,6 +458,7 @@
     public UnaryExpr visit(UnaryExpr u, Void arg) throws CompilationException {
         UnaryExpr copy = new UnaryExpr(u.getExprType(), (Expression) u.getExpr().accept(this, arg));
         copy.setSourceLocation(u.getSourceLocation());
+        copy.addHints(u.getHints());
         return copy;
     }
 
@@ -454,6 +466,7 @@
     public FieldAccessor visit(FieldAccessor fa, Void arg) throws CompilationException {
         FieldAccessor copy = new FieldAccessor((Expression) fa.getExpr().accept(this, arg), fa.getIdent());
         copy.setSourceLocation(fa.getSourceLocation());
+        copy.addHints(fa.getHints());
         return copy;
     }
 
@@ -466,6 +479,7 @@
         }
         IndexAccessor copy = new IndexAccessor(expr, indexExpr);
         copy.setSourceLocation(ia.getSourceLocation());
+        copy.addHints(ia.getHints());
         return copy;
     }
 
@@ -477,6 +491,7 @@
         Expression elseExpr = (Expression) caseExpr.getElseExpr().accept(this, arg);
         CaseExpression copy = new CaseExpression(conditionExpr, whenExprList, thenExprList, elseExpr);
         copy.setSourceLocation(caseExpr.getSourceLocation());
+        copy.addHints(caseExpr.getHints());
         return copy;
     }