package com.tesora.dve.sql.expression; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import com.tesora.dve.db.mysql.MysqlNativeConstants; import com.tesora.dve.sql.node.expression.CastFunctionCall; import com.tesora.dve.sql.node.expression.ColumnInstance; import com.tesora.dve.sql.node.expression.ConvertFunctionCall; import com.tesora.dve.sql.node.expression.ExpressionAlias; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.expression.FunctionCall; import com.tesora.dve.sql.node.expression.LiteralExpression; import com.tesora.dve.sql.schema.FunctionName; import com.tesora.dve.sql.schema.UnqualifiedName; import com.tesora.dve.sql.util.ListSet; import com.tesora.dve.sql.util.Pair; public class ExpressionUtils { public static FunctionCall buildIn(ExpressionNode lhs, List<ExpressionNode> rhs) { ArrayList<ExpressionNode> params = new ArrayList<ExpressionNode>(); params.add(lhs); params.addAll(rhs); return new FunctionCall(FunctionName.makeIn(),params); } public static FunctionCall buildOr(List<ExpressionNode> args) { if (args.size() < 2) return null; return buildBinary(args,FunctionName.makeOr()); } public static FunctionCall buildAnd(List<ExpressionNode> args) { if (args.size() < 2) return null; return buildBinary(args,FunctionName.makeAnd()); } public static ExpressionNode safeBuildAnd(List<ExpressionNode> args) { ExpressionNode out = buildAnd(args); if (out == null) { if (!args.isEmpty()) out = args.get(0); } return out; } public static ExpressionNode safeBuildOr(List<ExpressionNode> args) { ExpressionNode out = buildOr(args); if (out == null) out = args.get(0); return out; } public static ExpressionNode buildWhereClause(List<ExpressionNode> args) { if (args.isEmpty()) return null; else if (args.size() == 1) return args.get(0); else return buildAnd(args); } public static Pair<ColumnInstance,LiteralExpression> decomposeKeyAssignment(FunctionCall fc) { ColumnInstance ci = null; LiteralExpression le = null; if (fc.getFunctionName().isEquals()) { for(ExpressionNode e : fc.getParameters()) { if (e instanceof ColumnInstance) ci = (ColumnInstance)e; else if (e instanceof LiteralExpression) le = (LiteralExpression)e; } if (ci != null && le != null) return new Pair<ColumnInstance,LiteralExpression>(ci,le); } return null; } private static FunctionCall buildBinary(List<ExpressionNode> args, FunctionName fn) { if (args.size() == 2) { return new FunctionCall(fn, args); } else { ArrayList<ExpressionNode> params = new ArrayList<ExpressionNode>(); params.add(args.get(0)); ArrayList<ExpressionNode> subargs = new ArrayList<ExpressionNode>(); for(int i = 1; i < args.size(); i++) subargs.add(args.get(i)); params.add(buildBinary(subargs, fn)); return new FunctionCall(fn, params); } } public static ListSet<ExpressionNode> decomposeOrClause(ExpressionNode in) { OrDecomposer od = new OrDecomposer(); od.visit(in); return od.getDecomposed(); } public static ListSet<ExpressionNode> decomposeAndClause(ExpressionNode in) { AndDecomposer ad = new AndDecomposer(); ad.visit(in); return ad.getDecomposed(); } private static class OrDecomposer extends Visitor { private ListSet<ExpressionNode> acc; public OrDecomposer() { acc = new ListSet<ExpressionNode>(); } public ListSet<ExpressionNode> getDecomposed() { return acc; } @Override public ExpressionNode visitFunctionCall(FunctionCall fc, VisitorContext vc) { if (fc.getFunctionName().isOr()) { return super.visitFunctionCall(fc, vc); } else { acc.add(fc); return fc; } } } private static class AndDecomposer extends Visitor { private ListSet<ExpressionNode> acc; public AndDecomposer() { acc = new ListSet<ExpressionNode>(); } public ListSet<ExpressionNode> getDecomposed() { return acc; } @Override public ExpressionNode visitFunctionCall(FunctionCall fc, VisitorContext vc) { if (fc.getFunctionName().isAnd()) { return super.visitFunctionCall(fc, vc); } else { acc.add(fc); return fc; } } } public static FunctionCall buildConvert(ExpressionNode whatToConvert, String convertToType) { return new ConvertFunctionCall(whatToConvert, new UnqualifiedName(convertToType), false); } public static Map<RewriteKey, ExpressionNode> buildRewriteMap(Collection<ExpressionNode> in) { HashMap<RewriteKey, ExpressionNode> out = new HashMap<RewriteKey, ExpressionNode>(); for(ExpressionNode n : in) { out.put(n.getRewriteKey(),n); if (n instanceof ExpressionAlias) { ExpressionAlias ea = (ExpressionAlias) n; out.put(ea.getTarget().getRewriteKey(), ea.getTarget()); } } return out; } public static ExpressionNode getTarget(ExpressionNode in) { if (in instanceof ExpressionAlias) return ((ExpressionAlias)in).getTarget(); return in; } static public ExpressionNode getUnaryColumnInstance(ExpressionNode n) { ExpressionNode ci = null; if (n instanceof FunctionCall) { if (((FunctionCall)n).isUnaryFunction()) { ci = getUnaryColumnInstance(((FunctionCall) n).getParameters().get(0)); } } else { ci = n; } return ci; } public static FunctionCall buildNullBinaryCast() { return new CastFunctionCall(LiteralExpression.makeNullLiteral(), new UnqualifiedName("BINARY(" + MysqlNativeConstants.MAX_PACKET_SIZE + ")")); } }