You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/01/24 11:20:43 UTC
svn commit: r126276 - in incubator/jackrabbit/trunk/src: grammar/sql java/org/apache/jackrabbit/core/search java/org/apache/jackrabbit/core/search/lucene java/org/apache/jackrabbit/core/search/sql java/org/apache/jackrabbit/core/search/xpath test/org/apache/jackrabbit/test/search
Author: mreutegg
Date: Mon Jan 24 02:20:40 2005
New Revision: 126276
URL: http://svn.apache.org/viewcvs?view=rev&rev=126276
Log:
Implemented proper support for IS [NOT] NULL queries.
Modified:
incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java
Modified: incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt&r1=126275&p2=incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt (original)
+++ incubator/jackrabbit/trunk/src/grammar/sql/JCRSQL.jjt Mon Jan 24 02:20:40 2005
@@ -325,7 +325,11 @@
)
)
|
- (<IS> (<NOT> { jjtThis.setNegate(true); })? <NULL> { jjtThis.setOperationType(Constants.OPERATION_NULL); } )
+ (<IS> (<NOT> { jjtThis.setNegate(true); })? <NULL>
+ {
+ jjtThis.setOperationType(jjtThis.isNegate() ? Constants.OPERATION_NOT_NULL : Constants.OPERATION_NULL);
+ }
+ )
)
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java Mon Jan 24 02:20:40 2005
@@ -93,7 +93,12 @@
public static int OPERATION_IN = 18;
/**
- * is null operation: identifier IS [ NOT ] NULL
+ * is null operation: identifier IS NULL
*/
public static int OPERATION_NULL = 19;
+
+ /**
+ * is not null operation: identifier IS NOT NULL
+ */
+ public static int OPERATION_NOT_NULL = 20;
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java Mon Jan 24 02:20:40 2005
@@ -73,6 +73,21 @@
}
/**
+ * Removes an <code>operand</code> (child node) from this query node.
+ *
+ * @param operand the child to remove.
+ * @return <code>true</code> if the operand was in the list of child nodes
+ * and has been removed; <code>false</code> if this node does not contain
+ * <code>operand</code> as a child node.
+ */
+ public boolean removeOperand(QueryNode operand) {
+ if (operands == null) {
+ return false;
+ }
+ return operands.remove(operand);
+ }
+
+ /**
* Returns an array of currently set <code>QueryNode</code> operands of this
* <code>QueryNode</code>. Returns an empty array if no operands are set.
*
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java Mon Jan 24 02:20:40 2005
@@ -43,23 +43,41 @@
import java.util.Arrays;
/**
+ * Implements a query builder that takes an abstract query tree and creates
+ * a lucene {@link org.apache.lucene.search.Query} tree that can be executed
+ * on an index.
+ * todo introduce a node type hierarchy for efficient translation of NodeTypeQueryNode
*/
class LuceneQueryBuilder implements QueryNodeVisitor {
+ /** Logger for this class */
private static final Logger log = Logger.getLogger(LuceneQueryBuilder.class);
+ /** QName for jcr:primaryType */
private static QName primaryType = new QName(NamespaceRegistryImpl.NS_JCR_URI, "primaryType");
+ /** Root node of the abstract query tree */
private QueryRootNode root;
+ /** Session of the user executing this query */
private SessionImpl session;
+ /** Namespace mappings to internal prefixes */
private NamespaceMappings nsMappings;
+ /** The analyzer instance to use for contains function query parsing */
private Analyzer analyzer;
+ /** Exceptions thrown during tree translation */
private List exceptions = new ArrayList();
+ /**
+ * Creates a new <code>LuceneQueryBuilder</code> instance.
+ * @param root the root node of the abstract query tree.
+ * @param session of the user executing this query.
+ * @param nsMappings namespace resolver for internal prefixes.
+ * @param analyzer for parsing the query statement of the contains function.
+ */
private LuceneQueryBuilder(QueryRootNode root,
SessionImpl session,
NamespaceMappings nsMappings,
@@ -70,6 +88,16 @@
this.analyzer = analyzer;
}
+ /**
+ * Creates a lucene {@link org.apache.lucene.search.Query} tree from an
+ * abstract query tree.
+ * @param root the root node of the abstract query tree.
+ * @param session of the user executing the query.
+ * @param nsMappings namespace resolver for internal prefixes.
+ * @param analyzer for parsing the query statement of the contains function.
+ * @return the lucene query tree.
+ * @throws RepositoryException if an error occurs during the translation.
+ */
public static Query createQuery(QueryRootNode root,
SessionImpl session,
NamespaceMappings nsMappings,
@@ -85,15 +113,22 @@
for (Iterator it = builder.exceptions.iterator(); it.hasNext();) {
msg.append(it.next().toString()).append('\n');
}
- throw new RepositoryException("Exception parsing query: " + msg.toString());
+ throw new RepositoryException("Exception building query: " + msg.toString());
}
return q;
}
+ /**
+ * Starts the tree traversal and returns the lucene
+ * {@link org.apache.lucene.search.Query}.
+ * @return the lucene <code>Query</code>.
+ */
private Query createLuceneQuery() {
return (Query) root.accept(this, null);
}
+ //---------------------< QueryNodeVisitor interface >-----------------------
+
public Object visit(QueryRootNode node, Object data) {
BooleanQuery root = new BooleanQuery();
@@ -333,8 +368,11 @@
public Object visit(RelationQueryNode node, Object data) {
Query query;
- String stringValue;
+ String stringValue = null;
switch (node.getType()) {
+ case 0:
+ // not set: either IS NULL or IS NOT NULL
+ break;
case Constants.TYPE_DATE:
stringValue = DateField.dateToString(node.getDateValue());
break;
@@ -353,8 +391,10 @@
}
String field = "";
+ String primaryTypeField = "";
try {
field = node.getProperty().toJCRName(nsMappings);
+ primaryTypeField = primaryType.toJCRName(nsMappings);
} catch (NoPrefixDeclaredException e) {
// should never happen
exceptions.add(e);
@@ -388,6 +428,15 @@
notQuery.add(new MatchAllQuery(field), false, false);
notQuery.add(new TermQuery(new Term(field, stringValue)), false, true);
query = notQuery;
+ break;
+ case Constants.OPERATION_NULL:
+ notQuery = new BooleanQuery();
+ notQuery.add(new MatchAllQuery(primaryTypeField), false, false);
+ notQuery.add(new MatchAllQuery(field), false, true);
+ query = notQuery;
+ break;
+ case Constants.OPERATION_NOT_NULL:
+ query = new MatchAllQuery(field);
break;
default:
throw new IllegalArgumentException("Unknown relation operation: "
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java Mon Jan 24 02:20:40 2005
@@ -16,10 +16,18 @@
*/
package org.apache.jackrabbit.core.search.lucene;
-import org.apache.jackrabbit.core.*;
-import org.apache.jackrabbit.core.state.*;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NoPrefixDeclaredException;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.InternalValue;
+import org.apache.jackrabbit.core.QName;
import javax.jcr.NamespaceException;
import javax.jcr.PropertyType;
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java Mon Jan 24 02:20:40 2005
@@ -182,15 +182,11 @@
return node.childrenAccept(new DefaultParserVisitor() {
public Object visit(ASTIdentifier node, Object data) {
- try {
- if (!node.getName().equals(NodeTypeRegistry.NT_BASE.toJCRName(resolver))) {
- // node is either primary or mixin node type
- NodeTypeQueryNode nodeType
- = new NodeTypeQueryNode(constraintNode, node.getName());
- constraintNode.addOperand(nodeType);
- }
- } catch (NoPrefixDeclaredException e) {
- throw new IllegalArgumentException("No prefix declared for name: " + node.getName());
+ if (!node.getName().equals(NodeTypeRegistry.NT_BASE)) {
+ // node is either primary or mixin node type
+ NodeTypeQueryNode nodeType
+ = new NodeTypeQueryNode(constraintNode, node.getName());
+ constraintNode.addOperand(nodeType);
}
return data;
}
@@ -204,10 +200,6 @@
public Object visit(ASTPredicate node, Object data) {
NAryQueryNode parent = (NAryQueryNode) data;
- if (node.isNegate()) {
- parent = new NotQueryNode(parent);
- }
-
int type = node.getOperationType();
QueryNode predicateNode = null;
@@ -271,12 +263,16 @@
in.addOperand(rel);
}
predicateNode = in;
- } else if (type == Constants.OPERATION_NULL) {
+ } else if (type == Constants.OPERATION_NULL
+ || type == Constants.OPERATION_NOT_NULL) {
+ // create a dummy literal
ASTLiteral star = new ASTLiteral(JCRSQLParserTreeConstants.JJTLITERAL);
star.setType(Constants.TYPE_STRING);
star.setValue("%");
predicateNode = createRelationQueryNode(parent,
- identifier, Constants.OPERATION_LIKE, star);
+ identifier, type, star);
+ } else {
+ throw new IllegalArgumentException("Unknown operation type: " + type);
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Too few arguments in predicate");
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java Mon Jan 24 02:20:40 2005
@@ -317,37 +317,33 @@
if (node.getOperation() == OPERATION_EQ) {
sb.append(" = ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_GE) {
sb.append(" >= ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_GT) {
sb.append(" > ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_LE) {
sb.append(" <= ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_LIKE) {
sb.append(" LIKE ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_LT) {
sb.append(" < ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_NE) {
sb.append(" <> ");
+ appendValue(node, sb);
+ } else if (node.getOperation() == OPERATION_NULL) {
+ sb.append(" IS NULL");
+ } else if (node.getOperation() == OPERATION_NOT_NULL) {
+ sb.append(" IS NOT NULL");
} else {
exceptions.add(new InvalidQueryException("Invalid operation: " + node.getOperation()));
}
-
- if (node.getType() == TYPE_LONG) {
- sb.append(node.getLongValue());
- } else if (node.getType() == TYPE_DOUBLE) {
- sb.append(node.getDoubleValue());
- } else if (node.getType() == TYPE_STRING) {
- sb.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
- } else if (node.getType() == TYPE_DATE || node.getType() == TYPE_TIMESTAMP) {
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- cal.setTime(node.getDateValue());
- sb.append("TIMESTAMP '").append(ISO8601.format(cal)).append("'");
- } else {
- exceptions.add(new InvalidQueryException("Invalid type: " + node.getType()));
- }
-
if (node.getOperation() == OPERATION_LIKE && node.getStringValue().indexOf('\\') > -1) {
sb.append(" ESCAPE '\\'");
}
@@ -404,5 +400,22 @@
if (quote) {
b.append('"');
}
+ }
+
+ private void appendValue(RelationQueryNode node, StringBuffer b) {
+ if (node.getType() == TYPE_LONG) {
+ b.append(node.getLongValue());
+ } else if (node.getType() == TYPE_DOUBLE) {
+ b.append(node.getDoubleValue());
+ } else if (node.getType() == TYPE_STRING) {
+ b.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
+ } else if (node.getType() == TYPE_DATE || node.getType() == TYPE_TIMESTAMP) {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.setTime(node.getDateValue());
+ b.append("TIMESTAMP '").append(ISO8601.format(cal)).append("'");
+ } else {
+ exceptions.add(new InvalidQueryException("Invalid type: " + node.getType()));
+ }
+
}
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java Mon Jan 24 02:20:40 2005
@@ -258,46 +258,40 @@
StringBuffer sb = (StringBuffer) data;
try {
- int propIdx = sb.length();
- sb.append("@" + ISO9075.encode(node.getProperty()).toJCRName(resolver));
+ //int propIdx = sb.length();
+ String propName = "@" + ISO9075.encode(node.getProperty()).toJCRName(resolver);
if (node.getOperation() == OPERATION_EQ) {
- sb.append(" = ");
+ sb.append(propName).append(" = ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_GE) {
- sb.append(" >= ");
+ sb.append(propName).append(" >= ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_GT) {
- sb.append(" > ");
+ sb.append(propName).append(" > ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_LE) {
- sb.append(" <= ");
+ sb.append(propName).append(" <= ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_LIKE) {
- sb.insert(propIdx, XPathQueryBuilder.JCRFN_LIKE.toJCRName(resolver) + "(");
- sb.append(",");
+ sb.append(XPathQueryBuilder.JCRFN_LIKE.toJCRName(resolver));
+ sb.append("(").append(propName).append(", ");
+ appendValue(node, sb);
+ sb.append(")");
} else if (node.getOperation() == OPERATION_LT) {
- sb.append(" < ");
+ sb.append(propName).append(" < ");
+ appendValue(node, sb);
} else if (node.getOperation() == OPERATION_NE) {
- sb.append(" != ");
+ sb.append(propName).append(" != ");
+ appendValue(node, sb);
+ } else if (node.getOperation() == OPERATION_NULL) {
+ sb.append(XPathQueryBuilder.FN_NOT.toJCRName(resolver));
+ sb.append("(").append(propName).append(")");
+ } else if (node.getOperation() == OPERATION_NOT_NULL) {
+ sb.append(propName);
} else {
exceptions.add(new InvalidQueryException("Invalid operation: " + node.getOperation()));
}
-
- if (node.getType() == TYPE_LONG) {
- sb.append(node.getLongValue());
- } else if (node.getType() == TYPE_DOUBLE) {
- sb.append(node.getDoubleValue());
- } else if (node.getType() == TYPE_STRING) {
- sb.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
- } else if (node.getType() == TYPE_DATE || node.getType() == TYPE_TIMESTAMP) {
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- cal.setTime(node.getDateValue());
- sb.append(XPathQueryBuilder.XS_DATETIME.toJCRName(resolver));
- sb.append("('").append(ISO8601.format(cal)).append("')");
- } else {
- exceptions.add(new InvalidQueryException("Invalid type: " + node.getType()));
- }
-
- if (node.getOperation() == OPERATION_LIKE) {
- sb.append(")");
- }
} catch (NoPrefixDeclaredException e) {
exceptions.add(e);
}
@@ -307,5 +301,26 @@
public Object visit(OrderQueryNode node, Object data) {
// @todo implement
return data;
+ }
+
+ //----------------------------< internal >----------------------------------
+
+ private void appendValue(RelationQueryNode node, StringBuffer b)
+ throws NoPrefixDeclaredException {
+ if (node.getType() == TYPE_LONG) {
+ b.append(node.getLongValue());
+ } else if (node.getType() == TYPE_DOUBLE) {
+ b.append(node.getDoubleValue());
+ } else if (node.getType() == TYPE_STRING) {
+ b.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
+ } else if (node.getType() == TYPE_DATE || node.getType() == TYPE_TIMESTAMP) {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.setTime(node.getDateValue());
+ b.append(XPathQueryBuilder.XS_DATETIME.toJCRName(resolver));
+ b.append("('").append(ISO8601.format(cal)).append("')");
+ } else {
+ exceptions.add(new InvalidQueryException("Invalid type: " + node.getType()));
+ }
+
}
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java&r1=126275&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java Mon Jan 24 02:20:40 2005
@@ -203,8 +203,27 @@
break;
case XPathTreeConstants.JJTSTEPEXPR:
if (isAttributeAxis(node)) {
- // traverse
- node.childrenAccept(this, data);
+ if (data instanceof RelationQueryNode) {
+ // traverse
+ node.childrenAccept(this, data);
+ } else if (data instanceof NotQueryNode) {
+ // is null expression
+ RelationQueryNode isNull
+ = new RelationQueryNode((QueryNode) data,
+ RelationQueryNode.OPERATION_NULL);
+ node.childrenAccept(this, isNull);
+ NotQueryNode notNode = (NotQueryNode) data;
+ NAryQueryNode parent = (NAryQueryNode) notNode.getParent();
+ parent.removeOperand(notNode);
+ parent.addOperand(isNull);
+ } else {
+ // not null expression
+ RelationQueryNode notNull
+ = new RelationQueryNode((QueryNode) data,
+ RelationQueryNode.OPERATION_NOT_NULL);
+ node.childrenAccept(this, notNull);
+ ((NAryQueryNode) data).addOperand(notNull);
+ }
} else {
if (data instanceof PathQueryNode) {
data = createLocationStep(node, (PathQueryNode) data);
Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java?view=diff&rev=126276&p1=incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java&r1=126275&p2=incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java&r2=126276
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java Mon Jan 24 02:20:40 2005
@@ -296,4 +296,44 @@
}
+ public void testIsNull() throws Exception {
+ Node foo = testRootNode.addNode("foo");
+ foo.setProperty("mytext", "the quick brown fox jumps over the lazy dog.");
+ Node bar = testRootNode.addNode("bar");
+ bar.setProperty("text", "the quick brown fox jumps over the lazy dog.");
+
+ testRootNode.save();
+
+ String sql = "SELECT * FROM nt:unstructured WHERE mytext is null and jcr:path LIKE '/"
+ + testRoot + "/%'";
+ Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+ QueryResult result = q.execute();
+ checkResult(result, 1);
+
+ String xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured' and fn:not(@mytext)]";
+ q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+ result = q.execute();
+ checkResult(result, 1);
+
+ }
+
+ public void testIsNotNull() throws Exception {
+ Node foo = testRootNode.addNode("foo");
+ foo.setProperty("mytext", "the quick brown fox jumps over the lazy dog.");
+ Node bar = testRootNode.addNode("bar");
+ bar.setProperty("text", "the quick brown fox jumps over the lazy dog.");
+
+ testRootNode.save();
+
+ String sql = "SELECT * FROM nt:unstructured WHERE mytext is not null";
+ Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+ QueryResult result = q.execute();
+ checkResult(result, 1);
+
+ String xpath = "//*[@jcr:primaryType='nt:unstructured' and @mytext]";
+ q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+ result = q.execute();
+ checkResult(result, 1);
+ }
+
}