001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 2007.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.query.parser.serql;
007:
008: import static org.openrdf.query.algebra.Compare.CompareOp.EQ;
009: import static org.openrdf.query.algebra.Compare.CompareOp.NE;
010:
011: import java.util.Iterator;
012:
013: import org.slf4j.Logger;
014: import org.slf4j.LoggerFactory;
015:
016: import org.openrdf.query.MalformedQueryException;
017: import org.openrdf.query.algebra.Compare.CompareOp;
018: import org.openrdf.query.parser.serql.ast.ASTBooleanConstant;
019: import org.openrdf.query.parser.serql.ast.ASTBooleanExpr;
020: import org.openrdf.query.parser.serql.ast.ASTBound;
021: import org.openrdf.query.parser.serql.ast.ASTCompare;
022: import org.openrdf.query.parser.serql.ast.ASTNot;
023: import org.openrdf.query.parser.serql.ast.ASTNull;
024: import org.openrdf.query.parser.serql.ast.ASTProjectionElem;
025: import org.openrdf.query.parser.serql.ast.ASTQueryContainer;
026: import org.openrdf.query.parser.serql.ast.ASTSelect;
027: import org.openrdf.query.parser.serql.ast.ASTValueExpr;
028: import org.openrdf.query.parser.serql.ast.ASTVar;
029: import org.openrdf.query.parser.serql.ast.Node;
030: import org.openrdf.query.parser.serql.ast.VisitorException;
031:
032: /**
033: * Processes {@link ASTNull} nodes in query models. Null's that appear in
034: * projections are simply removed as that doesn't change the semantics. Null's
035: * that appear in value comparisons are either replaced with {@link ASTBound}
036: * nodes or constants.
037: *
038: * @author Arjohn Kampman
039: */
040: class NullProcessor {
041:
042: /**
043: * Processes escape sequences in ASTString objects.
044: *
045: * @param qc
046: * The query that needs to be processed.
047: * @throws MalformedQueryException
048: * If an invalid escape sequence was found.
049: */
050: public static void process(ASTQueryContainer qc)
051: throws MalformedQueryException {
052: NullVisitor visitor = new NullVisitor();
053: try {
054: qc.jjtAccept(visitor, null);
055: } catch (VisitorException e) {
056: throw new MalformedQueryException(e.getMessage(), e);
057: }
058: }
059:
060: private static class NullVisitor extends ASTVisitorBase {
061:
062: protected final Logger logger = LoggerFactory.getLogger(this
063: .getClass());
064:
065: public NullVisitor() {
066: }
067:
068: @Override
069: public Object visit(ASTSelect selectNode, Object data)
070: throws VisitorException {
071: Iterator<Node> iter = selectNode.jjtGetChildren()
072: .iterator();
073:
074: while (iter.hasNext()) {
075: ASTProjectionElem pe = (ASTProjectionElem) iter.next();
076:
077: if (pe.getValueExpr() instanceof ASTNull) {
078: logger
079: .warn("Use of NULL values in SeRQL queries has been deprecated");
080: iter.remove();
081: }
082: }
083:
084: return null;
085: }
086:
087: @Override
088: public Object visit(ASTCompare compareNode, Object data)
089: throws VisitorException {
090: boolean leftIsNull = compareNode.getLeftOperand() instanceof ASTNull;
091: boolean rightIsNull = compareNode.getRightOperand() instanceof ASTNull;
092: CompareOp operator = compareNode.getOperator().getValue();
093:
094: if (leftIsNull && rightIsNull) {
095: switch (operator) {
096: case EQ:
097: logger
098: .warn("Use of NULL values in SeRQL queries has been deprecated, use BOUND(...) instead");
099: compareNode.jjtReplaceWith(new ASTBooleanConstant(
100: true));
101: break;
102: case NE:
103: logger
104: .warn("Use of NULL values in SeRQL queries has been deprecated, use BOUND(...) instead");
105: compareNode.jjtReplaceWith(new ASTBooleanConstant(
106: false));
107: break;
108: default:
109: throw new VisitorException(
110: "Use of NULL values in SeRQL queries has been deprecated, use BOUND(...) instead");
111: }
112: } else if (leftIsNull || rightIsNull) {
113: ASTValueExpr valueOperand;
114: if (leftIsNull) {
115: valueOperand = compareNode.getRightOperand();
116: } else {
117: valueOperand = compareNode.getLeftOperand();
118: }
119:
120: if (valueOperand instanceof ASTVar && operator == EQ
121: || operator == NE) {
122: ASTBooleanExpr replacementNode = new ASTBound(
123: valueOperand);
124:
125: if (operator == EQ) {
126: replacementNode = new ASTNot(replacementNode);
127: }
128:
129: compareNode.jjtReplaceWith(replacementNode);
130:
131: return null;
132: }
133:
134: throw new VisitorException(
135: "Use of NULL values in SeRQL queries has been deprecated, use BOUND(...) instead");
136: }
137:
138: return null;
139: }
140:
141: @Override
142: public Object visit(ASTNull nullNode, Object data)
143: throws VisitorException {
144: throw new VisitorException(
145: "Use of NULL values in SeRQL queries has been deprecated, use BOUND(...) instead");
146: }
147: }
148: }
|