@Override public Part copy() { FunctionCall nfc = (FunctionCall) getParent().copy(null); ColumnInstance ci = (ColumnInstance) nfc.getParametersEdge().get(0); ConstantExpression litex = (ConstantExpression) nfc.getParametersEdge().get(1); return new EqualityPart(nfc, ci, litex, complete); }
private boolean applies(SchemaContext sc, DMLStatement stmt) throws PEException { if (stmt instanceof UpdateStatement) { UpdateStatement us = (UpdateStatement) stmt; for (Iterator<ExpressionNode> iter = us.getUpdateExpressionsEdge().iterator(); iter.hasNext(); ) { FunctionCall fc = (FunctionCall) iter.next(); ColumnInstance lhs = (ColumnInstance) fc.getParametersEdge().get(0); if (lhs.getPEColumn().isPartOfContainerDistributionVector()) throw new SchemaException( new ErrorInfo( AvailableErrors.INVALID_CONTAINER_DISCRIMINANT_COLUMN_UPDATE, lhs.getPEColumn().getName().getUnquotedName().get(), lhs.getPEColumn().getTable().getName().getUnquotedName().get())); } return false; } else if (stmt instanceof DeleteStatement) { DeleteStatement ds = (DeleteStatement) stmt; PETable pet = ds.getTargetDeleteEdge().get().getAbstractTable().asTable(); if (pet.isContainerBaseTable(sc)) { List<Part> parts = DiscriminantCollector.getDiscriminants(sc, ds.getWhereClause()); if (parts == null || parts.isEmpty()) throw new SchemaException( new ErrorInfo( AvailableErrors.INVALID_CONTAINER_DELETE, pet.getName().getUnquotedName().get())); else { List<SchemaCacheKey<PEContainerTenant>> matchingTenants = convert(sc, parts); stmt.getBlock().store(ContainerBaseTableRewriteTransformFactory.class, matchingTenants); return true; } } return false; } return false; }
private LanguageNode handleInFunction(FunctionCall fc) { ExpressionNode lhs = fc.getParameters().get(0); if (EngineConstant.COLUMN.has(lhs) && parent.isQualifyingColumn((ColumnInstance) lhs)) { // only matches if all the rhs are constant for (ExpressionNode en : fc.getParameters(1)) { if (!EngineConstant.CONSTANT.has(en)) return fc; } ColumnInstance ci = (ColumnInstance) lhs; if (!parent.isQualifyingColumn(ci.getPEColumn())) return fc; ArrayList<ExpressionNode> subexprs = new ArrayList<ExpressionNode>(); ArrayList<Part> parts = new ArrayList<Part>(); for (ExpressionNode en : fc.getParameters(1)) { ColumnInstance tci = (ColumnInstance) ci.copy(null); ConstantExpression litex = (ConstantExpression) en; ExpressionNode subeq = new FunctionCall(FunctionName.makeEquals(), tci, litex); Part p = buildPart(subeq, tci, litex); parts.add(p); subexprs.add((ExpressionNode) p.getParent()); } if (subexprs.size() > 1) { FunctionCall orcall = new FunctionCall(FunctionName.makeOr(), subexprs); OredParts pc = parent.buildOredParts(orcall, parts); if (pc.isComplete()) setComplete(pc); orcall.setGrouped(); state.put(orcall, pc); return orcall; } else { Part p = parts.get(0); return p.getParent(); } } return fc; }
@Override public LanguageNode action(LanguageNode in) { if (stopped) return in; if (EngineConstant.FUNCTION.has(in)) { FunctionCall fc = (FunctionCall) in; LanguageNode after = in; if (fc.getFunctionName().isEquals()) after = handleEqualsFunction(fc); else if (fc.getFunctionName().isAnd()) after = handleAndFunction(fc); else if (fc.getFunctionName().isOr()) after = handleOrFunction(fc); else if (fc.getFunctionName().isEffectiveNot()) after = handleNotFunction(fc); else if (fc.getFunctionName().isIn()) after = handleInFunction(fc); return after; } return in; }
public static boolean isNowFunctionCallSpecified(ListSet<FunctionCall> functions) { boolean usesNowFunction = false; if (functions == null) { return usesNowFunction; } for (FunctionCall fc : functions) { if (isTimestampFunction(fc.getFunctionName().getUnquotedName().get())) { usesNowFunction = true; break; } } return usesNowFunction; }
private LanguageNode handleOrFunction(FunctionCall fc) { ArrayList<Part> subparts = new ArrayList<Part>(); for (ExpressionNode en : fc.getParameters()) { Part p = state.get(en); if (p == null) { broadening(); return fc; } subparts.add(p); } // now to figure out what we have. we may have a a bunch of incomplete subexprs, // in which case we took a = 1 or a = 2 or a = 3 => a part collection of incompletes // or we may have (a = 1 and b = 2) or (a =3 and b =4) ... - likewise // or they maybe complete. regardless, just build a partcollection and move on. // sort subparts by table key; if there's more than one let's just set broadening for now TableKey tk = null; for (Part p : subparts) { if (tk == null) tk = p.getTableKey(); else if (!tk.equals(p.getTableKey())) { broadening(); return fc; } } OredParts op = parent.buildOredParts(fc, subparts); if (op.isComplete()) setComplete(op); state.put(fc, op); return fc; }
private LanguageNode fold(LanguageNode in, EngineToken variety) { FunctionCall fc = (FunctionCall) in; ArrayList<ExpressionNode> grouped = new ArrayList<ExpressionNode>(); ArrayList<ExpressionNode> same = new ArrayList<ExpressionNode>(); ArrayList<ExpressionNode> others = new ArrayList<ExpressionNode>(); for (ExpressionNode p : fc.getParameters()) { if (EngineConstant.FUNCTION.has(p, variety)) { if (p.isGrouped()) grouped.add(p); else same.add(p); } else { others.add(p); } } if (same.isEmpty() || !grouped.isEmpty()) return in; // if others is empty, this is op(op(a,b),op(c,d)), build op(a,b,c,d) // if others is not empty, this is op(a,op(b,c)) or op(op(a,b),c), build op(a,b,c) ArrayList<ExpressionNode> allsubs = new ArrayList<ExpressionNode>(); for (ExpressionNode p : same) { FunctionCall pfc = (FunctionCall) p; allsubs.addAll(pfc.getParameters()); } allsubs.addAll(others); // we're going to group this as well FunctionCall ofc = new FunctionCall(fc.getFunctionName(), allsubs); ofc.setGrouped(); return ofc; }
private LanguageNode handleAndFunction(FunctionCall fc) { // and functions take incomplete simple parts and turn them into complete parts, if so desired ArrayList<Part> incompletes = new ArrayList<Part>(); ArrayList<ExpressionNode> ok = new ArrayList<ExpressionNode>(); ArrayList<Part> subparts = new ArrayList<Part>(); for (ExpressionNode en : fc.getParameters()) { Part p = state.get(en); if (p == null || p.isComplete()) { ok.add(en); if (p != null) subparts.add(p); continue; } incompletes.add(p); } if (incompletes.isEmpty()) return fc; // now we have the problem of a mishmash of incompletes. some may be complex, some may be // simple // some may be collections. we need to handle cases like the following: // (a = 1) and (b = 2) {a,b} (1 key) // (a = 1) and (b = 2 or b = 3) {a,b} (2 keys) // (a = 1 or a = 2) and (b = 3) {a,b} (2 keys) // (a = 1 or a = 2) and (b = 3 or b = 4) {a,b} (4 keys here) // all of the above, where the result is still not complete due to missing tenant column MultiMap<Part, ColumnKey> needed = new MultiMap<Part, ColumnKey>(); MultiMap<ColumnKey, Part> classified = new MultiMap<ColumnKey, Part>(); for (Part p : incompletes) { ListSet<ColumnKey> has = new ListSet<ColumnKey>(); has.addAll(p.getColumns()); needed.putAll(p, parent.getNeeded(has)); for (ColumnKey ck : has) { classified.put(ck, p); } } // so let's say we have a part that is (a = 1 and b = 2), needs c and tenant, and we have a // part // that is c in (1,2,3). The needed for (a = 1 and b = 2) is {c,tenant}. we'll pull (c in // (1,2,3)) // so we'll get at least (a = 1 and b = 2 and c = 3) or (a = 1 and b =2 and c = 3) ... // these we can then individually try to complete. while (!needed.isEmpty()) { combineParts(needed, classified, ok, subparts); } for (Part p : subparts) state.put(p.getParent(), p); if (ok.size() == 1) return ok.get(0); else { // what's left is a mix of unrelated and complete or incomplete subexprs. unrelated nodes // would come in from above, as would previously complete. return new FunctionCall(FunctionName.makeAnd(), ok); } }
/** @param useRhs Collect RHS columns if TRUE, and LHS columns otherwise. */ private Set<ColumnKey> collectColumnsFromJoinConditions( final ListSet<ExpressionNode> joinConditions, final boolean useRhs) { final int sideIndex = (useRhs) ? 1 : 0; final Set<ColumnKey> columnKeys = new TreeSet<ColumnKey>( new Comparator<ColumnKey>() { @Override public int compare(ColumnKey c1, ColumnKey c2) { final int p1 = c1.getPEColumn().getPosition(); final int p2 = c2.getPEColumn().getPosition(); return p1 - p2; } }); for (final ExpressionNode condition : joinConditions) { final FunctionCall columnEquality = (FunctionCall) condition; final ColumnInstance ci = (ColumnInstance) columnEquality.getParameters().get(sideIndex); columnKeys.add(ci.getColumnKey()); } return columnKeys; }
private List<SchemaCacheKey<PEContainerTenant>> getPertinentTenants( PlannerContext pc, DMLStatement stmt) throws PEException { SchemaContext sc = pc.getContext(); if (stmt instanceof UpdateStatement) { UpdateStatement us = (UpdateStatement) stmt; for (Iterator<ExpressionNode> iter = us.getUpdateExpressionsEdge().iterator(); iter.hasNext(); ) { FunctionCall fc = (FunctionCall) iter.next(); ColumnInstance lhs = (ColumnInstance) fc.getParametersEdge().get(0); if (lhs.getPEColumn().isPartOfContainerDistributionVector()) throw new SchemaException( Pass.PLANNER, "Invalid update: discriminant column " + lhs.getPEColumn().getName().getSQL() + " of container base table " + lhs.getPEColumn().getTable().getName().getSQL() + " cannot be updated"); } } else if (stmt instanceof DeleteStatement) { DeleteStatement ds = (DeleteStatement) stmt; PETable pet = ds.getTargetDeleteEdge().get().getAbstractTable().asTable(); if (pet.isContainerBaseTable(sc)) { List<Part> parts = DiscriminantCollector.getDiscriminants(sc, ds.getWhereClause()); if (parts == null || parts.isEmpty()) throw new SchemaException( Pass.PLANNER, "Invalid delete on container base table " + pet.getName().getSQL() + ". Not restricted by discriminant columns"); else { List<SchemaCacheKey<PEContainerTenant>> matchingTenants = convert(sc, parts); return matchingTenants; } } } return null; }
private LanguageNode handleEqualsFunction(FunctionCall fc) { ExpressionNode lhs = fc.getParameters().get(0); ExpressionNode rhs = fc.getParameters().get(1); if (EngineConstant.CONSTANT.has(rhs) && EngineConstant.COLUMN.has(lhs) && parent.isQualifyingColumn((ColumnInstance) lhs)) { ColumnInstance ci = (ColumnInstance) lhs; ConstantExpression litex = (ConstantExpression) rhs; PEColumn c = ci.getPEColumn(); if (parent.isQualifyingColumn(c)) { Part p = buildPart(fc, ci, litex); return p.getParent(); } } return fc; }