001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
003: * Copyright James Leigh (c) 2006.
004: *
005: * Licensed under the Aduna BSD-style license.
006: */
007: package org.openrdf.query.algebra.evaluation.impl;
008:
009: import java.util.List;
010:
011: import org.slf4j.Logger;
012: import org.slf4j.LoggerFactory;
013:
014: import org.openrdf.model.Value;
015: import org.openrdf.model.impl.BooleanLiteralImpl;
016: import org.openrdf.query.BindingSet;
017: import org.openrdf.query.Dataset;
018: import org.openrdf.query.QueryEvaluationException;
019: import org.openrdf.query.algebra.And;
020: import org.openrdf.query.algebra.BinaryValueOperator;
021: import org.openrdf.query.algebra.Bound;
022: import org.openrdf.query.algebra.FunctionCall;
023: import org.openrdf.query.algebra.Or;
024: import org.openrdf.query.algebra.TupleExpr;
025: import org.openrdf.query.algebra.UnaryValueOperator;
026: import org.openrdf.query.algebra.ValueConstant;
027: import org.openrdf.query.algebra.ValueExpr;
028: import org.openrdf.query.algebra.Var;
029: import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
030: import org.openrdf.query.algebra.evaluation.QueryOptimizer;
031: import org.openrdf.query.algebra.evaluation.ValueExprEvaluationException;
032: import org.openrdf.query.algebra.helpers.QueryModelVisitorBase;
033: import org.openrdf.query.impl.EmptyBindingSet;
034:
035: /**
036: * A query optimizer that optimizes constant value expressions.
037: *
038: * @author James Leigh
039: * @author Arjohn Kampman
040: */
041: public class ConstantOptimizer implements QueryOptimizer {
042:
043: protected final Logger logger = LoggerFactory.getLogger(this
044: .getClass());
045:
046: protected final EvaluationStrategy strategy;
047:
048: public ConstantOptimizer(EvaluationStrategy strategy) {
049: this .strategy = strategy;
050: }
051:
052: /**
053: * Applies generally applicable optimizations to the supplied query: variable
054: * assignments are inlined.
055: *
056: * @param tupleExpr
057: * @return optimized TupleExpr
058: * @throws QueryEvaluationException
059: */
060: public void optimize(TupleExpr tupleExpr, Dataset dataset,
061: BindingSet bindings) {
062: tupleExpr.visit(new ConstantVisitor());
063: }
064:
065: protected class ConstantVisitor extends
066: QueryModelVisitorBase<RuntimeException> {
067:
068: @Override
069: public void meet(Or or) {
070: or.visitChildren(this );
071:
072: try {
073: if (isConstant(or.getLeftArg())
074: && isConstant(or.getRightArg())) {
075: boolean value = strategy.isTrue(or, EmptyBindingSet
076: .getInstance());
077: or.replaceWith(new ValueConstant(BooleanLiteralImpl
078: .valueOf(value)));
079: } else if (isConstant(or.getLeftArg())) {
080: boolean leftIsTrue = strategy.isTrue(or
081: .getLeftArg(), EmptyBindingSet
082: .getInstance());
083: if (leftIsTrue) {
084: or.replaceWith(new ValueConstant(
085: BooleanLiteralImpl.TRUE));
086: } else {
087: or.replaceWith(or.getRightArg());
088: }
089: } else if (isConstant(or.getRightArg())) {
090: boolean rightIsTrue = strategy.isTrue(or
091: .getRightArg(), EmptyBindingSet
092: .getInstance());
093: if (rightIsTrue) {
094: or.replaceWith(new ValueConstant(
095: BooleanLiteralImpl.TRUE));
096: } else {
097: or.replaceWith(or.getLeftArg());
098: }
099: }
100: } catch (ValueExprEvaluationException e) {
101: logger
102: .warn(
103: "Failed to evaluate BinaryValueOperator with two constant arguments",
104: e);
105: } catch (QueryEvaluationException e) {
106: logger.error("Query evaluation exception caught", e);
107: }
108: }
109:
110: @Override
111: public void meet(And and) {
112: and.visitChildren(this );
113:
114: try {
115: if (isConstant(and.getLeftArg())
116: && isConstant(and.getRightArg())) {
117: boolean value = strategy.isTrue(and,
118: EmptyBindingSet.getInstance());
119: and.replaceWith(new ValueConstant(
120: BooleanLiteralImpl.valueOf(value)));
121: } else if (isConstant(and.getLeftArg())) {
122: boolean leftIsTrue = strategy.isTrue(and
123: .getLeftArg(), EmptyBindingSet
124: .getInstance());
125: if (leftIsTrue) {
126: and.replaceWith(and.getRightArg());
127: } else {
128: and.replaceWith(new ValueConstant(
129: BooleanLiteralImpl.FALSE));
130: }
131: } else if (isConstant(and.getRightArg())) {
132: boolean rightIsTrue = strategy.isTrue(and
133: .getRightArg(), EmptyBindingSet
134: .getInstance());
135: if (rightIsTrue) {
136: and.replaceWith(and.getLeftArg());
137: } else {
138: and.replaceWith(new ValueConstant(
139: BooleanLiteralImpl.FALSE));
140: }
141: }
142: } catch (ValueExprEvaluationException e) {
143: logger
144: .warn(
145: "Failed to evaluate BinaryValueOperator with two constant arguments",
146: e);
147: } catch (QueryEvaluationException e) {
148: logger.error("Query evaluation exception caught", e);
149: }
150: }
151:
152: @Override
153: protected void meetBinaryValueOperator(
154: BinaryValueOperator binaryValueOp) {
155: super .meetBinaryValueOperator(binaryValueOp);
156:
157: if (isConstant(binaryValueOp.getLeftArg())
158: && isConstant(binaryValueOp.getRightArg())) {
159: try {
160: Value value = strategy.evaluate(binaryValueOp,
161: EmptyBindingSet.getInstance());
162: binaryValueOp.replaceWith(new ValueConstant(value));
163: } catch (ValueExprEvaluationException e) {
164: logger
165: .warn(
166: "Failed to evaluate BinaryValueOperator with two constant arguments",
167: e);
168: } catch (QueryEvaluationException e) {
169: logger
170: .error("Query evaluation exception caught",
171: e);
172: }
173: }
174: }
175:
176: @Override
177: protected void meetUnaryValueOperator(
178: UnaryValueOperator unaryValueOp) {
179: super .meetUnaryValueOperator(unaryValueOp);
180:
181: if (isConstant(unaryValueOp.getArg())) {
182: try {
183: Value value = strategy.evaluate(unaryValueOp,
184: EmptyBindingSet.getInstance());
185: unaryValueOp.replaceWith(new ValueConstant(value));
186: } catch (ValueExprEvaluationException e) {
187: logger
188: .warn(
189: "Failed to evaluate UnaryValueOperator with a constant argument",
190: e);
191: } catch (QueryEvaluationException e) {
192: logger
193: .error("Query evaluation exception caught",
194: e);
195: }
196: }
197: }
198:
199: @Override
200: public void meet(FunctionCall functionCall) {
201: super .meet(functionCall);
202:
203: List<ValueExpr> args = functionCall.getArgs();
204: for (ValueExpr arg : args) {
205: if (!isConstant(arg)) {
206: return;
207: }
208: }
209:
210: // All arguments are constant
211:
212: try {
213: Value value = strategy.evaluate(functionCall,
214: EmptyBindingSet.getInstance());
215: functionCall.replaceWith(new ValueConstant(value));
216: } catch (ValueExprEvaluationException e) {
217: logger
218: .warn(
219: "Failed to evaluate BinaryValueOperator with two constant arguments",
220: e);
221: } catch (QueryEvaluationException e) {
222: logger.error("Query evaluation exception caught", e);
223: }
224: }
225:
226: @Override
227: public void meet(Bound bound) {
228: super .meet(bound);
229:
230: if (bound.getArg().hasValue()) {
231: // variable is always bound
232: bound.replaceWith(new ValueConstant(
233: BooleanLiteralImpl.TRUE));
234: }
235: }
236:
237: private boolean isConstant(ValueExpr expr) {
238: return expr instanceof ValueConstant || expr instanceof Var
239: && ((Var) expr).hasValue();
240: }
241: }
242: }
|