/** * Result {@code null} means that there is no variable. Result other than {@code null} means that there is a variable (that may possibly * be {@code null}). * * @param name the name of the variable. * @return a holder for a variable. */ protected Mutable<Object> doGetVariable(String name) { List<Object> variables = scripts.stream().filter(script -> script.getMetaClass().hasProperty(script.getMetaClass().getTheClass(), name) != null) .map(script -> script.getProperty(name)).collect(Collectors.toList()); if (variables.isEmpty()) { try { return new MutableObject<>(binding.getProperty(name)); } catch (MissingPropertyException e) { return null; // This means that no variable has been found! } } return new MutableObject<>(variables.get(0)); }
public void computeLocalProperties(ILogicalOperator op) { OrderOperator ord = (OrderOperator) op; List<OrderColumn> orderColumns = new ArrayList<OrderColumn>(); for (Pair<IOrder, Mutable<ILogicalExpression>> p : ord.getOrderExpressions()) { ILogicalExpression expr = p.second.getValue(); if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) { VariableReferenceExpression varRef = (VariableReferenceExpression) expr; LogicalVariable var = varRef.getVariableReference(); orderColumns.add(new OrderColumn(var, p.first.getKind())); } else { throw new IllegalStateException(); } } sortColumns = orderColumns.toArray(new OrderColumn[orderColumns.size()]); orderProp = new LocalOrderProperty(orderColumns); }
public static void printLogicalPlan(ILogicalPlan plan) throws AlgebricksException { int indent = 5; StringBuilder out = new StringBuilder(); int randomInt = 10000 + randomGenerator.nextInt(100); appendln(out, "digraph G {"); for (Mutable<ILogicalOperator> root : plan.getRoots()) { printVisualizationGraph((AbstractLogicalOperator) root.getValue(), indent, out, "", randomInt); } appendln(out, "\n}\n}"); try { File file = File.createTempFile("logicalPlan", ".txt"); FileUtils.writeStringToFile(file, out.toString()); file.deleteOnExit(); } catch (IOException e) { e.printStackTrace(); } }
@Override public boolean rewriteWithRuleCollection(Mutable<ILogicalOperator> root, Collection<IAlgebraicRewriteRule> rules) throws AlgebricksException { boolean anyRuleFired = false; boolean anyChange = false; do { anyChange = false; for (IAlgebraicRewriteRule r : rules) { while (true) { boolean ruleFired = rewriteOperatorRef(root, r); if (ruleFired) { anyChange = true; anyRuleFired = true; } else { break; // go to next rule } } } } while (anyChange); return anyRuleFired; }
@Override public ILogicalOperator visitTokenizeOperator(TokenizeOperator op, Void arg) throws AlgebricksException { List<Mutable<ILogicalExpression>> newPrimaryKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>(); deepCopyExpressionRefs(newPrimaryKeyExpressions, op.getPrimaryKeyExpressions()); List<Mutable<ILogicalExpression>> newSecondaryKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>(); deepCopyExpressionRefs(newSecondaryKeyExpressions, op.getSecondaryKeyExpressions()); List<LogicalVariable> newTokenizeVars = new ArrayList<LogicalVariable>(); deepCopyVars(newTokenizeVars, op.getTokenizeVars()); Mutable<ILogicalExpression> newFilterExpression = new MutableObject<ILogicalExpression>( ((AbstractLogicalExpression) op.getFilterExpression()).cloneExpression()); List<Object> newTokenizeVarTypes = new ArrayList<Object>(); deepCopyObjects(newTokenizeVarTypes, op.getTokenizeVarTypes()); TokenizeOperator tokenizeOp = new TokenizeOperator(op.getDataSourceIndex(), newPrimaryKeyExpressions, newSecondaryKeyExpressions, newTokenizeVars, newFilterExpression, op.getOperation(), op.isBulkload(), op.isPartitioned(), newTokenizeVarTypes); return tokenizeOp; }
public static void substituteVarRec(AbstractLogicalOperator op, LogicalVariable v1, LogicalVariable v2, boolean goThroughNts, ITypingContext ctx) throws AlgebricksException { VariableUtilities.substituteVariables(op, v1, v2, goThroughNts, ctx); for (Mutable<ILogicalOperator> opRef2 : op.getInputs()) { substituteVarRec((AbstractLogicalOperator) opRef2.getValue(), v1, v2, goThroughNts, ctx); } if (op.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE && goThroughNts) { NestedTupleSourceOperator nts = (NestedTupleSourceOperator) op; if (nts.getDataSourceReference() != null) { AbstractLogicalOperator op2 = (AbstractLogicalOperator) nts.getDataSourceReference().getValue() .getInputs().get(0).getValue(); substituteVarRec(op2, v1, v2, goThroughNts, ctx); } } if (op.hasNestedPlans()) { AbstractOperatorWithNestedPlans aonp = (AbstractOperatorWithNestedPlans) op; for (ILogicalPlan p : aonp.getNestedPlans()) { for (Mutable<ILogicalOperator> ref : p.getRoots()) { AbstractLogicalOperator aop = (AbstractLogicalOperator) ref.getValue(); substituteVarRec(aop, v1, v2, goThroughNts, ctx); } } } }
@Override public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); if (op.getOperatorTag() != LogicalOperatorTag.PROJECT) { return false; } ProjectOperator pi = (ProjectOperator) op; Mutable<ILogicalOperator> opRef2 = pi.getInputs().get(0); HashSet<LogicalVariable> toPush = new HashSet<LogicalVariable>(); toPush.addAll(pi.getVariables()); Pair<Boolean, Boolean> p = pushThroughOp(toPush, opRef2, op, context); boolean smthWasPushed = p.first; if (p.second) { // the original projection is redundant opRef.setValue(op.getInputs().get(0).getValue()); smthWasPushed = true; } return smthWasPushed; }
private static boolean pushNeededProjections(HashSet<LogicalVariable> toPush, Mutable<ILogicalOperator> opRef, IOptimizationContext context, ILogicalOperator initialOp) throws AlgebricksException { HashSet<LogicalVariable> allP = new HashSet<LogicalVariable>(); AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); VariableUtilities.getSubplanLocalLiveVariables(op, allP); HashSet<LogicalVariable> toProject = new HashSet<LogicalVariable>(); for (LogicalVariable v : toPush) { if (allP.contains(v)) { toProject.add(v); } } if (toProject.equals(allP)) { // projection would be redundant, since we would project everything // but we can try with the children boolean push = false; if (pushThroughOp(toProject, opRef, initialOp, context).first) { push = true; } return push; } else { return pushAllProjectionsOnTopOf(toProject, opRef, context, initialOp); } }
@Override public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); if (op.getInputs().size() <= 0) return false; AbstractLogicalOperator project = (AbstractLogicalOperator) op.getInputs().get(0).getValue(); if (project.getOperatorTag() != LogicalOperatorTag.PROJECT) return false; AbstractLogicalOperator exchange = (AbstractLogicalOperator) project.getInputs().get(0).getValue(); if (exchange.getOperatorTag() != LogicalOperatorTag.EXCHANGE) return false; AbstractLogicalOperator inputOp = (AbstractLogicalOperator) exchange.getInputs().get(0).getValue(); if (inputOp.getOperatorTag() != LogicalOperatorTag.DATASOURCESCAN) return false; DataSourceScanOperator scanOp = (DataSourceScanOperator) inputOp; ProjectOperator projectOp = (ProjectOperator) project; scanOp.addProjectVariables(projectOp.getVariables()); if (op.getOperatorTag() != LogicalOperatorTag.EXCHANGE) { op.getInputs().set(0, project.getInputs().get(0)); } else { op.getInputs().set(0, exchange.getInputs().get(0)); } return true; }
@Override public boolean rewriteWithRuleCollection(Mutable<ILogicalOperator> root, Collection<IAlgebraicRewriteRule> ruleCollection) throws AlgebricksException { boolean anyRuleFired = false; boolean anyChange = false; do { anyChange = false; for (IAlgebraicRewriteRule rule : ruleCollection) { boolean ruleFired = rewriteOperatorRef(root, rule, true, fullDfs); if (ruleFired) { anyChange = true; anyRuleFired = true; } } } while (anyChange); return anyRuleFired; }
@Override public ILogicalOperator visitIndexInsertDeleteUpsertOperator(IndexInsertDeleteUpsertOperator op, Void arg) throws AlgebricksException { List<Mutable<ILogicalExpression>> newPrimaryKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>(); deepCopyExpressionRefs(newPrimaryKeyExpressions, op.getPrimaryKeyExpressions()); List<Mutable<ILogicalExpression>> newSecondaryKeyExpressions = new ArrayList<Mutable<ILogicalExpression>>(); deepCopyExpressionRefs(newSecondaryKeyExpressions, op.getSecondaryKeyExpressions()); Mutable<ILogicalExpression> newFilterExpression = new MutableObject<ILogicalExpression>( ((AbstractLogicalExpression) op.getFilterExpression()).cloneExpression()); List<Mutable<ILogicalExpression>> newLSMComponentFilterExpressions = new ArrayList<Mutable<ILogicalExpression>>(); deepCopyExpressionRefs(newLSMComponentFilterExpressions, op.getAdditionalFilteringExpressions()); IndexInsertDeleteUpsertOperator indexInsertDeleteOp = new IndexInsertDeleteUpsertOperator( op.getDataSourceIndex(), newPrimaryKeyExpressions, newSecondaryKeyExpressions, newFilterExpression, op.getOperation(), op.isBulkload()); indexInsertDeleteOp.setAdditionalFilteringExpressions(newLSMComponentFilterExpressions); return indexInsertDeleteOp; }
private void mapVariablesInNestedPlans(ILogicalOperator opOrigin, ILogicalOperator arg) throws AlgebricksException { AbstractOperatorWithNestedPlans op = (AbstractOperatorWithNestedPlans) opOrigin; AbstractOperatorWithNestedPlans argOp = (AbstractOperatorWithNestedPlans) arg; List<ILogicalPlan> plans = op.getNestedPlans(); List<ILogicalPlan> plansArg = argOp.getNestedPlans(); if (plans.size() != plansArg.size()) return; for (int i = 0; i < plans.size(); i++) { List<Mutable<ILogicalOperator>> roots = plans.get(i).getRoots(); List<Mutable<ILogicalOperator>> rootsArg = plansArg.get(i).getRoots(); if (roots.size() != rootsArg.size()) return; for (int j = 0; j < roots.size(); j++) { ILogicalOperator topOp1 = roots.get(j).getValue(); ILogicalOperator topOp2 = rootsArg.get(j).getValue(); topOp1.accept(this, topOp2); } } }
@Override public Object getVariable(String name) { try { Mutable<Object> variable = doGetVariable(name); if (variable == null) { throw new SpongeException("Variable '" + name + "' not found in any of the scripts"); } return variable.getValue(); } catch (Throwable e) { throw SpongeUtils.wrapException("getVariable", e); } }
@Override protected boolean shouldAddToEventTreeForNMode(TreeNode<NodeValue> parentNode, Mutable<TreeNode<NodeValue>> newNodeHolder, Event event) { handleNoneEventHappenedButShouldNot(parentNode, newNodeHolder.getValue(), event); return false; }
@Override protected boolean shouldAddToEventTreeForNMode(TreeNode<NodeValue> parentNode, Mutable<TreeNode<NodeValue>> newNodeHolder, Event event) { boolean result = false; if (handleNoneEventHappenedButShouldNot(parentNode, newNodeHolder.getValue(), event)) { return false; } // We need only one node marking NONE event that has not happened, so others are removed. parentNode.getChildren().subList(1, parentNode.getChildren().size()).clear(); // Because an event hasn't happened, the value of the node will be set to null. TreeNode<NodeValue> emptyNode = parentNode.getChildren().get(0); if (emptyNode.getValue().getEvent() != null) { emptyNode.getValue().setEvent(null); } // Recursively build event tree because the event may match one of the following expected events for this rule. buildEventTree(emptyNode, event); // Add to event tree only when the event does match one of the following expected events. if (emptyNode.hasChildren()) { result = true; } // Change newNode in the holder for further processing. newNodeHolder.setValue(emptyNode); return result; }
@Override public boolean transform(Mutable<ILogicalExpression> exprRef) { ILogicalExpression e = exprRef.getValue(); switch (((AbstractLogicalExpression) e).getExpressionTag()) { case VARIABLE: { // Replace variable references with their equivalent representative in the equivalence class map. VariableReferenceExpression varRefExpr = (VariableReferenceExpression) e; LogicalVariable var = varRefExpr.getVariableReference(); List<LogicalVariable> equivalentVars = equivalentVarsMap.get(var); if (equivalentVars == null) { return false; } LogicalVariable representative = equivalentVars.get(0); if (representative != var) { varRefExpr.setVariable(representative); return true; } return false; } case FUNCTION_CALL: { AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) e; boolean modified = false; for (Mutable<ILogicalExpression> arg : funcExpr.getArguments()) { if (transform(arg)) { modified = true; } } return modified; } default: { return false; } } }
private static ILogicalExpression afce(Function fn, boolean isTwoStep, ILogicalExpression... argExprs) { List<Mutable<ILogicalExpression>> args = new ArrayList<Mutable<ILogicalExpression>>(); for (ILogicalExpression e : argExprs) { args.add(mutable(e)); } return new AggregateFunctionCallExpression(fn, isTwoStep, args); }
protected boolean worthMaterialization(Mutable<ILogicalOperator> candidate) { AbstractLogicalOperator aop = (AbstractLogicalOperator) candidate.getValue(); if (aop.getPhysicalOperator().expensiveThanMaterialization()) { return true; } List<Mutable<ILogicalOperator>> inputs = candidate.getValue().getInputs(); for (Mutable<ILogicalOperator> inputRef : inputs) { if (worthMaterialization(inputRef)) { return true; } } return false; }
@Override public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); if (op.getOperatorTag() != LogicalOperatorTag.ASSIGN) { return false; } AssignOperator assignOp = (AssignOperator) op; // Find a join operator below this assign. Mutable<ILogicalOperator> joinOpRef = findJoinOp(assignOp.getInputs().get(0)); if (joinOpRef == null) { return false; } AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) joinOpRef.getValue(); // Check if the assign uses a function that we wish to push below the join if possible. funcExprs.clear(); gatherFunctionCalls(assignOp, funcExprs); if (funcExprs.isEmpty()) { return false; } // Try to push the functions down the input branches of the join. boolean modified = false; if (pushDownFunctions(joinOp, 0, funcExprs, context)) { modified = true; } if (pushDownFunctions(joinOp, 1, funcExprs, context)) { modified = true; } if (modified) { context.computeAndSetTypeEnvironmentForOperator(joinOp); } return modified; }
@Override public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { ILogicalOperator op = opRef.getValue(); if (context.getOutputTypeEnvironment(op) != null) { return false; } context.computeAndSetTypeEnvironmentForOperator(op); return true; }
@Override public Void visitWriteOperator(WriteOperator op, Pair<LogicalVariable, LogicalVariable> pair) throws AlgebricksException { for (Mutable<ILogicalExpression> e : op.getExpressions()) { e.getValue().substituteVar(pair.first, pair.second); } substVarTypes(op, pair); return null; }
private boolean isRedundantSort(Mutable<ILogicalOperator> opRef, IPhysicalPropertiesVector delivered, IPhysicalPropertiesVector diffOfProperties, IOptimizationContext context) { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); if (op.getOperatorTag() != LogicalOperatorTag.ORDER || (op.getPhysicalOperator().getOperatorTag() != PhysicalOperatorTag.STABLE_SORT && op.getPhysicalOperator().getOperatorTag() != PhysicalOperatorTag.IN_MEMORY_STABLE_SORT) || delivered.getLocalProperties() == null) { return false; } AbstractStableSortPOperator sortOp = (AbstractStableSortPOperator) op.getPhysicalOperator(); sortOp.computeLocalProperties(op); ILocalStructuralProperty orderProp = sortOp.getOrderProperty(); return PropertiesUtil.matchLocalProperties(Collections.singletonList(orderProp), delivered.getLocalProperties(), context.getEquivalenceClassMap(op), context.getFDList(op)); }
@Override public int hashCode() { int h = finfo.hashCode(); for (Mutable<ILogicalExpression> e : arguments) { h = h * 41 + e.getValue().hashCode(); } if (opaqueParameters != null) { for (int i = 0; i < opaqueParameters.length; i++) { h = h * 31 + opaqueParameters[i].hashCode(); } } return h; }
public LinkedList<Mutable<ILogicalOperator>> allRootsInReverseOrder() { LinkedList<Mutable<ILogicalOperator>> allRoots = new LinkedList<Mutable<ILogicalOperator>>(); for (ILogicalPlan p : nestedPlans) { for (Mutable<ILogicalOperator> r : p.getRoots()) { allRoots.addFirst(r); } } return allRoots; }
@Override public Void visitWriteOperator(WriteOperator op, Void arg) { for (Mutable<ILogicalExpression> expr : op.getExpressions()) { expr.getValue().getUsedVariables(usedVariables); } return null; }
@Override public String visitOrderOperator(OrderOperator op, Integer indent) throws AlgebricksException { StringBuilder buffer = new StringBuilder(); addIndent(buffer, indent).append("order "); for (Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>> p : op.getOrderExpressions()) { String fst; if (op.getTopK() != -1) { buffer.append("(topK: " + op.getTopK() + ") "); } switch (p.first.getKind()) { case ASC: { fst = "ASC"; break; } case DESC: { fst = "DESC"; break; } default: { fst = p.first.getExpressionRef().toString(); } } buffer.append("(" + fst + ", " + p.second.getValue().accept(exprVisitor, indent) + ") "); } return buffer.toString(); }
private static void ntsToEtsInSubplan(SubplanOperator s, IOptimizationContext context) throws AlgebricksException { for (ILogicalPlan p : s.getNestedPlans()) { for (Mutable<ILogicalOperator> r : p.getRoots()) { OperatorManipulationUtil.ntsToEts(r, context); } } }
private boolean rewrite(IOptimizationContext context) throws AlgebricksException { boolean changed = false; for (List<Mutable<ILogicalOperator>> members : equivalenceClasses) { if (rewriteForOneEquivalentClass(members, context)) { changed = true; } } return changed; }
private static void cleanupJoins(SubplanOperator s) { for (ILogicalPlan p : s.getNestedPlans()) { for (Mutable<ILogicalOperator> r : p.getRoots()) { cleanupJoins(r); } } }
@Override public Void visitDistributeResultOperator(DistributeResultOperator op, Pair<LogicalVariable, LogicalVariable> pair) throws AlgebricksException { for (Mutable<ILogicalExpression> e : op.getExpressions()) { e.getValue().substituteVar(pair.first, pair.second); } substVarTypes(op, pair); return null; }
@Override public UnnestingFunctionCallExpression cloneExpression() { cloneAnnotations(); List<Mutable<ILogicalExpression>> clonedArgs = cloneArguments(); UnnestingFunctionCallExpression ufce = new UnnestingFunctionCallExpression(finfo, clonedArgs); ufce.setReturnsUniqueValues(returnsUniqueValues); ufce.setOpaqueParameters(this.getOpaqueParameters()); return ufce; }
public static boolean isFunctionExpression(Mutable<ILogicalExpression> mutableLe, AbstractFunctionCallExpression afce) { ILogicalExpression le = mutableLe.getValue(); if (le.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { return false; } AbstractFunctionCallExpression fc = (AbstractFunctionCallExpression) le; if (!fc.getFunctionIdentifier().equals(afce)) { return false; } return true; }
private static void copySelectToBranch(SelectOperator select, Mutable<ILogicalOperator> branch, IOptimizationContext context) throws AlgebricksException { ILogicalOperator newSelect = new SelectOperator(select.getCondition(), select.getRetainNull(), select.getNullPlaceholderVariable()); Mutable<ILogicalOperator> newRef = new MutableObject<ILogicalOperator>(branch.getValue()); newSelect.getInputs().add(newRef); branch.setValue(newSelect); context.computeAndSetTypeEnvironmentForOperator(newSelect); }
private Mutable<ILogicalOperator> getInputOperator(Mutable<ILogicalOperator> opRef) { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); switch (op.getOperatorTag()) { case SUBPLAN: SubplanOperator subplan = (SubplanOperator) op; return getInputOperator(subplan.getNestedPlans().get(0).getRoots().get(0)); case NESTEDTUPLESOURCE: NestedTupleSourceOperator nts = (NestedTupleSourceOperator) op; return getInputOperator(nts.getDataSourceReference()); default: return opRef; } }
public IndexBulkloadPOperator(List<LogicalVariable> primaryKeys, List<LogicalVariable> secondaryKeys, List<LogicalVariable> additionalFilteringKeys, Mutable<ILogicalExpression> filterExpr, IDataSourceIndex<?, ?> dataSourceIndex) { this.primaryKeys = primaryKeys; this.secondaryKeys = secondaryKeys; this.additionalFilteringKeys = additionalFilteringKeys; if (filterExpr != null) { this.filterExpr = filterExpr.getValue(); } else { this.filterExpr = null; } this.dataSourceIndex = dataSourceIndex; }
@Override public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); // if (context.checkIfInDontApplySet(this, op)) { // return false; // } if (op.getPhysicalOperator() != null) { return false; } computeDefaultPhysicalOp(op, true, context); // context.addToDontApplySet(this, op); return true; }
public static void ntsToEts(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); if (op.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) { EmptyTupleSourceOperator ets = new EmptyTupleSourceOperator(); context.computeAndSetTypeEnvironmentForOperator(ets); opRef.setValue(ets); } else { for (Mutable<ILogicalOperator> i : opRef.getValue().getInputs()) { ntsToEts(i, context); } } }
public static void getUsedVariablesInDescendantsAndSelf(ILogicalOperator op, Collection<LogicalVariable> vars) throws AlgebricksException { // DFS traversal VariableUtilities.getUsedVariables(op, vars); for (Mutable<ILogicalOperator> c : op.getInputs()) { getUsedVariablesInDescendantsAndSelf(c.getValue(), vars); } }
@SuppressWarnings("unchecked") private boolean convertAlgebricksExpression(Mutable<ILogicalExpression> searchM, IFunctionInfo funcInfo, boolean isBoolean) { AbstractFunctionCallExpression searchFunction = (AbstractFunctionCallExpression) searchM.getValue(); searchFunction.setFunctionInfo(funcInfo); if (isBoolean) { ScalarFunctionCallExpression functionCallExp = new ScalarFunctionCallExpression( BuiltinFunctions.FN_BOOLEAN_1, new MutableObject<ILogicalExpression>(searchM.getValue())); searchM.setValue(functionCallExp); } return true; }
private Mutable<ILogicalOperator> getNestedTupleSourceReference(Mutable<ILogicalOperator> nestedTopOperatorRef) { Mutable<ILogicalOperator> currentOpRef = nestedTopOperatorRef; while (currentOpRef.getValue().getInputs() != null && currentOpRef.getValue().getInputs().size() > 0) { currentOpRef = currentOpRef.getValue().getInputs().get(0); } return currentOpRef; }