You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/10/18 14:55:40 UTC
svn commit: r1023777 [2/2] -
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java?rev=1023777&r1=1023776&r2=1023777&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java Mon Oct 18 12:55:39 2010
@@ -16,9 +16,8 @@
*/
package org.apache.jackrabbit.core.query.lucene.join;
-import static java.util.Locale.ENGLISH;
-import static javax.jcr.PropertyType.NAME;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_ORDER_DESCENDING;
import java.util.ArrayList;
@@ -33,7 +32,6 @@ import java.util.Set;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RangeIterator;
import javax.jcr.RepositoryException;
@@ -51,48 +49,74 @@ import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
import javax.jcr.query.qom.And;
-import javax.jcr.query.qom.BindVariableValue;
import javax.jcr.query.qom.ChildNode;
-import javax.jcr.query.qom.ChildNodeJoinCondition;
import javax.jcr.query.qom.Column;
import javax.jcr.query.qom.Comparison;
import javax.jcr.query.qom.Constraint;
-import javax.jcr.query.qom.DescendantNode;
-import javax.jcr.query.qom.DescendantNodeJoinCondition;
-import javax.jcr.query.qom.DynamicOperand;
-import javax.jcr.query.qom.EquiJoinCondition;
-import javax.jcr.query.qom.FullTextSearchScore;
import javax.jcr.query.qom.Join;
-import javax.jcr.query.qom.JoinCondition;
-import javax.jcr.query.qom.Length;
import javax.jcr.query.qom.Literal;
-import javax.jcr.query.qom.LowerCase;
-import javax.jcr.query.qom.NodeLocalName;
-import javax.jcr.query.qom.NodeName;
import javax.jcr.query.qom.Not;
import javax.jcr.query.qom.Operand;
import javax.jcr.query.qom.Or;
import javax.jcr.query.qom.Ordering;
-import javax.jcr.query.qom.PropertyExistence;
import javax.jcr.query.qom.PropertyValue;
-import javax.jcr.query.qom.QueryObjectModelConstants;
import javax.jcr.query.qom.QueryObjectModelFactory;
-import javax.jcr.query.qom.SameNode;
-import javax.jcr.query.qom.SameNodeJoinCondition;
import javax.jcr.query.qom.Selector;
import javax.jcr.query.qom.Source;
-import javax.jcr.query.qom.UpperCase;
import org.apache.jackrabbit.commons.JcrUtils;
-import org.apache.jackrabbit.commons.iterator.FilteredRangeIterator;
import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
import org.apache.jackrabbit.commons.iterator.RowIteratorAdapter;
-import org.apache.jackrabbit.commons.predicate.Predicate;
-import org.apache.jackrabbit.commons.predicate.Predicates;
-import org.apache.jackrabbit.commons.predicate.RowPredicate;
public class QueryEngine {
+ /**
+ * Row comparator.
+ */
+ private class RowComparator implements Comparator<Row> {
+
+ private final ValueComparator comparator = new ValueComparator();
+
+ private final Ordering[] orderings;
+
+ private RowComparator(Ordering[] orderings) {
+ this.orderings = orderings;
+ }
+
+ public int compare(Row a, Row b) {
+ try {
+ for (Ordering ordering : orderings) {
+ Operand operand = ordering.getOperand();
+ Value[] va = evaluator.getValues(operand, a);
+ Value[] vb = evaluator.getValues(operand, b);
+ int d = compare(va, vb);
+ if (d != 0) {
+ if (JCR_ORDER_DESCENDING.equals(ordering.getOrder())) {
+ return -d;
+ } else {
+ return d;
+ }
+ }
+ }
+ return 0;
+ } catch (RepositoryException e) {
+ throw new RuntimeException(
+ "Unable to compare rows " + a + " and " + b, e);
+ }
+ }
+
+ private int compare(Value[] a, Value[] b) {
+ for (int i = 0; i < a.length && i < b.length; i++) {
+ int d = comparator.compare(a[i], b[i]);
+ if (d != 0) {
+ return d;
+ }
+ }
+ return a.length - b.length;
+ }
+
+ }
+
private final Session session;
private final NodeTypeManager ntManager;
@@ -101,7 +125,7 @@ public class QueryEngine {
private final ValueFactory valueFactory;
- private final Map<String, Value> variables;
+ private final OperandEvaluator evaluator;
public QueryEngine(Session session, Map<String, Value> variables)
throws RepositoryException {
@@ -112,7 +136,7 @@ public class QueryEngine {
this.qomFactory = workspace.getQueryManager().getQOMFactory();
this.valueFactory = session.getValueFactory();
- this.variables = variables;
+ this.evaluator = new OperandEvaluator(valueFactory, variables);
}
public QueryEngine(Session session) throws RepositoryException {
@@ -139,370 +163,33 @@ public class QueryEngine {
Column[] columns, Join join,
Constraint constraint, Ordering[] orderings)
throws RepositoryException {
- Source left = join.getLeft();
- Map<String, NodeType> leftSelectors = getSelectorNames(left);
+ JoinMerger merger = JoinMerger.getJoinMerger(
+ join, getColumnMap(columns, getSelectorNames(join)),
+ evaluator, qomFactory);
+ ConstraintSplitter splitter = new ConstraintSplitter(
+ constraint, qomFactory,
+ merger.getLeftSelectors(), merger.getRightSelectors());
- Source right = join.getRight();
- Map<String, NodeType> rightSelectors = getSelectorNames(right);
-
- Constraint leftConstraint =
- mapConstraintToSelectors(constraint, leftSelectors.keySet());
+ Source left = join.getLeft();
+ Constraint leftConstraint = splitter.getLeftConstraint();
System.out.println("FROM " + left + " WHERE " + leftConstraint);
QueryResult leftResult = execute(null, left, leftConstraint, null);
-
List<Row> leftRows = new ArrayList<Row>();
for (Row row : JcrUtils.getRows(leftResult)) {
System.out.println(row);
leftRows.add(row);
}
- Constraint joinConstraint = getJoinConstraint(
- join.getJoinCondition(), leftSelectors.keySet(), leftRows);
+ Source right = join.getRight();
Constraint rightConstraint = Constraints.and(
- qomFactory, joinConstraint,
- mapConstraintToSelectors(constraint, rightSelectors.keySet()));
+ qomFactory,
+ merger.getRightJoinConstraint(leftRows),
+ splitter.getRightConstraint());
System.out.println("FROM " + right + " WHERE " + rightConstraint);
QueryResult rightResult = execute(null, right, rightConstraint, null);
- List<Row> rightRows = new ArrayList<Row>();
- for (Row row : JcrUtils.getRows(rightResult)) {
- System.out.println(row);
- rightRows.add(row);
- }
-
- Map<String, NodeType> selectors = new LinkedHashMap<String, NodeType>();
- selectors.putAll(leftSelectors);
- selectors.putAll(rightSelectors);
- String[] selectorNames =
- selectors.keySet().toArray(new String[selectors.size()]);
-
- Map<String, PropertyValue> columnMap = getColumnMap(columns, selectors);
- String[] columnNames =
- columnMap.keySet().toArray(new String[columnMap.size()]);
- PropertyValue[] operands =
- columnMap.values().toArray(new PropertyValue[columnMap.size()]);
-
- double[] scores = new double[selectorNames.length];
- for (int i = 0; i < scores.length; i++) {
- scores[i] = 1.0;
- }
-
- Predicate predicate = Predicates.and(
- getPredicate(join.getJoinCondition()),
- getPredicate(constraint));
-
- List<Row> joinRows = new ArrayList<Row>();
- for (Row leftRow : leftRows) {
- for (Row rightRow : rightRows) {
- Node[] nodes = new Node[selectorNames.length];
- for (int i = 0; i < selectorNames.length; i++) {
- String selector = selectorNames[i];
- if (leftSelectors.containsKey(selector)) {
- nodes[i] = leftRow.getNode(selector);
- } else {
- nodes[i] = rightRow.getNode(selector);
- }
- }
- Value[] values = new Value[operands.length];
- Row row = new SimpleRow(
- columnNames, values, selectorNames, nodes, scores);
- for (int i = 0; i < operands.length; i++) {
- values[i] = combine(getPropertyValues(operands[i], row));
- }
- if (predicate.evaluate(row)) {
- joinRows.add(row);
- }
- }
- }
-
- return new SimpleQueryResult(
- columnNames, selectorNames, new RowIteratorAdapter(joinRows));
- }
-
- /**
- * Returns a mapped constraint that only refers to the given set of
- * selectors. The returned constraint is guaranteed to match an as small
- * as possible superset of the node tuples matched by the given original
- * constraints.
- *
- * @param constraint original constraint
- * @param selectors target selectors
- * @return mapped constraint
- * @throws RepositoryException if the constraint mapping fails
- */
- private Constraint mapConstraintToSelectors(
- Constraint constraint, Set<String> selectors)
- throws RepositoryException {
- if (constraint == Constraints.TRUE || constraint == Constraints.FALSE) {
- return constraint;
- } else if (constraint instanceof And) {
- And and = (And) constraint;
- return Constraints.and(
- qomFactory,
- mapConstraintToSelectors(and.getConstraint1(), selectors),
- mapConstraintToSelectors(and.getConstraint2(), selectors));
- } else if (constraint instanceof Or) {
- Or or = (Or) constraint;
- return Constraints.or(
- qomFactory,
- mapConstraintToSelectors(or.getConstraint1(), selectors),
- mapConstraintToSelectors(or.getConstraint2(), selectors));
- } else if (constraint instanceof Not) {
- Not not = (Not) constraint;
- Constraint mapped =
- mapConstraintToSelectors(not.getConstraint(), selectors);
- // Tricky handling of NOT constraints, even NOT TRUE maps to TRUE
- // to guarantee that the mapped result set remains a superset
- if (mapped == Constraints.TRUE || mapped == Constraints.FALSE) {
- return Constraints.TRUE;
- } else {
- return Constraints.not(qomFactory, mapped);
- }
- } else if (selectors.contains(getSelectorName(constraint))) {
- // This constraint refers to one of the target selectors, keep it
- return constraint;
- } else {
- // This constraint refers to some other selector, drop it
- return Constraints.TRUE;
- }
- }
-
- /**
- * Returns the name of the selector referenced by the given constraint.
- *
- * @param constraint concrete constraint (i.e. not a logical construct)
- * @return selector name
- * @throws UnsupportedRepositoryOperationException
- * if the constraint type is unknown
- */
- private String getSelectorName(Constraint constraint)
- throws UnsupportedRepositoryOperationException {
- if (constraint instanceof PropertyExistence) {
- PropertyExistence pe = (PropertyExistence) constraint;
- return pe.getSelectorName();
- } else if (constraint instanceof Comparison) {
- Comparison c = (Comparison) constraint;
- return getSelectorName(c.getOperand1());
- } else if (constraint instanceof SameNode) {
- SameNode sn = (SameNode) constraint;
- return sn.getSelectorName();
- } else if (constraint instanceof ChildNode) {
- ChildNode cn = (ChildNode) constraint;
- return cn.getSelectorName();
- } else if (constraint instanceof DescendantNode) {
- DescendantNode dn = (DescendantNode) constraint;
- return dn.getSelectorName();
- } else {
- throw new UnsupportedRepositoryOperationException(
- "Unknown constraint type: " + constraint);
- }
- }
-
- /**
- * Returns the selector name referenced by the given dynamic operand.
- *
- * @param operand dynamic operand
- * @return selector name
- * @throws UnsupportedRepositoryOperationException
- * if the operand type is unknown
- */
- private String getSelectorName(DynamicOperand operand)
- throws UnsupportedRepositoryOperationException {
- if (operand instanceof FullTextSearchScore) {
- FullTextSearchScore ftss = (FullTextSearchScore) operand;
- return ftss.getSelectorName();
- } else if (operand instanceof Length) {
- Length length = (Length) operand;
- return getSelectorName(length.getPropertyValue());
- } else if (operand instanceof LowerCase) {
- LowerCase lower = (LowerCase) operand;
- return getSelectorName(lower.getOperand());
- } else if (operand instanceof NodeLocalName) {
- NodeLocalName local = (NodeLocalName) operand;
- return local.getSelectorName();
- } else if (operand instanceof NodeName) {
- NodeName name = (NodeName) operand;
- return name.getSelectorName();
- } else if (operand instanceof PropertyValue) {
- PropertyValue value = (PropertyValue) operand;
- return value.getSelectorName();
- } else if (operand instanceof UpperCase) {
- UpperCase upper = (UpperCase) operand;
- return getSelectorName(upper.getOperand());
- } else {
- throw new UnsupportedRepositoryOperationException(
- "Unknown dynamic operand type: " + operand);
- }
- }
-
- private Predicate getPredicate(JoinCondition condition)
- throws RepositoryException {
- if (condition instanceof EquiJoinCondition) {
- return getEquiJoinPredicate((EquiJoinCondition) condition);
- } else if (condition instanceof SameNodeJoinCondition) {
- return Predicate.TRUE; // FIXME
- } else if (condition instanceof ChildNodeJoinCondition) {
- return Predicate.TRUE; // FIXME
- } else if (condition instanceof DescendantNodeJoinCondition) {
- return Predicate.TRUE; // FIXME
- } else {
- return Predicate.TRUE; // FIXME
- }
- }
-
- private Predicate getEquiJoinPredicate(final EquiJoinCondition condition)
- throws RepositoryException {
- final Operand operand1 = qomFactory.propertyValue(
- condition.getSelector1Name(),
- condition.getProperty1Name());
- final Operand operand2 = qomFactory.propertyValue(
- condition.getSelector2Name(),
- condition.getProperty2Name());
- return new RowPredicate() {
- @Override
- protected boolean evaluate(Row row) throws RepositoryException {
- return new ValueComparator().evaluate(
- QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO,
- getValues(operand1, row), getValues(operand2, row));
- }
- };
- }
-
- protected Constraint getJoinConstraint(
- JoinCondition condition, Set<String> selectors, List<Row> rows)
- throws RepositoryException {
- if (condition instanceof EquiJoinCondition) {
- return getJoinConstraint(
- (EquiJoinCondition) condition, rows, selectors);
- } else if (condition instanceof SameNodeJoinCondition) {
- return getJoinConstraint(
- (SameNodeJoinCondition) condition, rows, selectors);
- } else if (condition instanceof ChildNodeJoinCondition) {
- return getJoinConstraint(
- (ChildNodeJoinCondition) condition, rows, selectors);
- } else if (condition instanceof DescendantNodeJoinCondition) {
- return getJoinConstraint(
- (DescendantNodeJoinCondition) condition, rows, selectors);
- } else {
- return Constraints.TRUE;
- }
- }
-
- /**
- * Constructs a query constraint for the right side of an equi-join
- * whose left side results are already known.
- *
- * @param condition the equi-join condition
- * @param leftRows results of the left side of the join
- * @return constraint for right side results that can possibly match
- * one or more of the left side results
- * @throws RepositoryException if the constraint can't be constructed
- */
- private Constraint getJoinConstraint(
- EquiJoinCondition condition, List<Row> leftRows,
- Set<String> rightSelectors) throws RepositoryException {
- String selector1 = condition.getSelector1Name();
- String property1 = condition.getProperty1Name();
- String selector2 = condition.getSelector2Name();
- String property2 = condition.getProperty2Name();
- if (!rightSelectors.contains(selector2)) {
- if (rightSelectors.contains(selector1)) {
- selector1 = condition.getSelector2Name();
- property1 = condition.getProperty2Name();
- selector2 = condition.getSelector1Name();
- property2 = condition.getProperty1Name();
- } else {
- return Constraints.TRUE;
- }
- }
-
- // Collect all matching values from the left source
- Set<Value> values = new HashSet<Value>();
- PropertyValue left = qomFactory.propertyValue(selector2, property2);
- for (Row row : leftRows) {
- for (Value value : getPropertyValues(left, row)) {
- values.add(value);
- }
- }
-
- // Convert each distinct value into a comparison constraint
- List<Constraint> constraints = new ArrayList<Constraint>(values.size());
- PropertyValue right = qomFactory.propertyValue(selector1, property1);
- for (Value value : values) {
- Literal literal = qomFactory.literal(value);
- constraints.add(qomFactory.comparison(
- right, JCR_OPERATOR_EQUAL_TO, literal));
- }
-
- // Build a big OR constraint over all the collected comparisons
- return Constraints.or(qomFactory, constraints.toArray(
- new Constraint[constraints.size()]));
- }
-
- private Constraint getJoinConstraint(
- SameNodeJoinCondition condition, List<Row> leftRows,
- Set<String> rightSelectors) throws RepositoryException {
- String selector1 = condition.getSelector1Name();
- String selector2 = condition.getSelector2Name();
- String relativePath = condition.getSelector2Path();
- if (!rightSelectors.contains(selector1)) {
- if (relativePath == null && rightSelectors.contains(selector2)) {
- selector1 = condition.getSelector2Name();
- selector2 = condition.getSelector1Name();
- } else {
- return Constraints.TRUE;
- }
- }
-
- // Collect all matching paths and convert them into constraints
- List<Constraint> constraints = new ArrayList<Constraint>();
- for (String path : getPaths(selector2, relativePath, leftRows)) {
- constraints.add(qomFactory.descendantNode(selector1, path));
- }
-
- // Build a big OR constraint over all the collected comparisons
- return Constraints.or(qomFactory, constraints.toArray(
- new Constraint[constraints.size()]));
- }
-
- private Constraint getJoinConstraint(
- ChildNodeJoinCondition condition, List<Row> leftRows,
- Set<String> rightSelectors) throws RepositoryException {
- String parent = condition.getParentSelectorName();
- String child = condition.getChildSelectorName();
- if (!rightSelectors.contains(child)) {
- return Constraints.TRUE;
- }
-
- // Collect all matching paths and convert them into constraints
- List<Constraint> constraints = new ArrayList<Constraint>();
- for (String path : getPaths(parent, null, leftRows)) {
- constraints.add(qomFactory.descendantNode(child, path));
- }
-
- // Build a big OR constraint over all the collected comparisons
- return Constraints.or(qomFactory, constraints.toArray(
- new Constraint[constraints.size()]));
- }
-
- private Constraint getJoinConstraint(
- DescendantNodeJoinCondition condition, List<Row> leftRows,
- Set<String> rightSelectors) throws RepositoryException {
- String ancestor = condition.getAncestorSelectorName();
- String descendant = condition.getDescendantSelectorName();
- if (!rightSelectors.contains(descendant)) {
- return Constraints.TRUE;
- }
-
- // Collect all matching paths and convert them into constraints
- List<Constraint> constraints = new ArrayList<Constraint>();
- for (String path : getPaths(ancestor, null, leftRows)) {
- constraints.add(qomFactory.descendantNode(descendant, path));
- }
-
- // Build a big OR constraint over all the collected comparisons
- return Constraints.or(qomFactory, constraints.toArray(
- new Constraint[constraints.size()]));
+ return merger.merge(
+ new RowIteratorAdapter(leftRows), rightResult.getRows());
}
private Set<String> getPaths(
@@ -544,6 +231,8 @@ public class QueryEngine {
String right = toSqlOperand(c.getOperand2());
if (c.getOperator().equals(JCR_OPERATOR_EQUAL_TO)) {
return left + " = " + right;
+ } else if (c.getOperator().equals(JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO)) {
+ return left + " >= " + right;
} else {
throw new RepositoryException("Unsupported comparison: " + c);
}
@@ -565,6 +254,8 @@ public class QueryEngine {
int type = value.getType();
if (type == PropertyType.LONG || type == PropertyType.DOUBLE) {
return value.getString();
+ } else if (type == PropertyType.DATE) {
+ return "TIMESTAMP '" + value.getString() + "'";
} else {
return "'" + value.getString() + "'";
}
@@ -611,7 +302,7 @@ public class QueryEngine {
columnNames, values, selectorNames,
new Node[] { (Node) super.next() }, scores);
for (int i = 0; i < values.length; i++) {
- values[i] = combine(getPropertyValues(
+ values[i] = combine(evaluator.getValues(
columnMap.get(columnNames[i]), row));
}
return row;
@@ -643,24 +334,6 @@ public class QueryEngine {
}
}
- private Predicate getPredicate(Selector selector, Constraint constraint)
- throws RepositoryException {
- final String name = selector.getNodeTypeName();
- Predicate predicate = getPredicate(constraint);
- if (name.equals(ntManager.getNodeType(NodeType.NT_BASE).getName())) {
- return predicate;
- } else {
- Predicate typeCheck = new RowPredicate(selector.getSelectorName()) {
- @Override
- protected boolean evaluate(Node node)
- throws RepositoryException {
- return node.isNodeType(name);
- }
- };
- return Predicates.and(typeCheck, predicate);
- }
- }
-
private Map<String, PropertyValue> getColumnMap(
Column[] columns, Map<String, NodeType> selectors)
throws RepositoryException {
@@ -742,30 +415,7 @@ public class QueryEngine {
rows.add(iterator.nextRow());
}
- Collections.sort(rows, new Comparator<Row>() {
- public int compare(Row a, Row b) {
- try {
- ValueComparator comparator = new ValueComparator();
- for (Ordering ordering : orderings) {
- Operand operand = ordering.getOperand();
- Value[] va = getValues(operand, a);
- Value[] vb = getValues(operand, b);
- if (va.length == 1 && vb.length == 1) {
- int order = comparator.compare(va[0], vb[0]);
- if (JCR_ORDER_DESCENDING.equals(ordering.getOrder())) {
- order = -order;
- }
- if (order != 0) {
- return order;
- }
- }
- }
- return 0;
- } catch (RepositoryException e) {
- throw new RuntimeException("Unable to compare rows", e);
- }
- }
- });
+ Collections.sort(rows, new RowComparator(orderings));
return new SimpleQueryResult(
result.getColumnNames(), result.getSelectorNames(),
@@ -775,314 +425,4 @@ public class QueryEngine {
}
}
- public Predicate getPredicate(Constraint constraint) {
- if (constraint == Constraints.TRUE) {
- return Predicate.TRUE;
- } else if (constraint == Constraints.FALSE) {
- return Predicate.FALSE;
- } else if (constraint instanceof And) {
- And and = (And) constraint;
- return Predicates.and(
- getPredicate(and.getConstraint1()),
- getPredicate(and.getConstraint2()));
- } else if (constraint instanceof Or) {
- Or or = (Or) constraint;
- return Predicates.or(
- getPredicate(or.getConstraint1()),
- getPredicate(or.getConstraint2()));
- } else if (constraint instanceof Not) {
- Not not = (Not) constraint;
- return Predicates.not(getPredicate(not.getConstraint()));
- } else if (constraint instanceof Not) {
- Not not = (Not) constraint;
- return Predicates.not(getPredicate(not.getConstraint()));
- } else if (constraint instanceof PropertyExistence) {
- final PropertyExistence pe = (PropertyExistence) constraint;
- return new RowPredicate(pe.getSelectorName()) {
- @Override
- protected boolean evaluate(Node node)
- throws RepositoryException {
- return node.hasProperty(pe.getPropertyName());
- }
- };
- } else if (constraint instanceof Comparison) {
- final Comparison c = (Comparison) constraint;
- return new RowPredicate() {
- @Override
- protected boolean evaluate(Row row)
- throws RepositoryException {
- return new ValueComparator().evaluate(
- c.getOperator(),
- getValues(c.getOperand1(), row),
- getValues(c.getOperand2(), row));
- }
- };
- } else if (constraint instanceof SameNode) {
- final SameNode sn = (SameNode) constraint;
- return new RowPredicate(sn.getSelectorName()) {
- @Override
- protected boolean evaluate(Node node)
- throws RepositoryException {
- return node.getPath().equals(sn.getPath());
- }
- };
- } else if (constraint instanceof ChildNode) {
- final ChildNode cn = (ChildNode) constraint;
- return new RowPredicate(cn.getSelectorName()) {
- @Override
- protected boolean evaluate(Node node)
- throws RepositoryException {
- if (node.getDepth() > 0) {
- String path = node.getParent().getPath();
- return path.equals(cn.getParentPath());
- } else {
- return false;
- }
- }
- };
- } else if (constraint instanceof DescendantNode) {
- final DescendantNode dn = (DescendantNode) constraint;
- return new RowPredicate(dn.getSelectorName()) {
- @Override
- protected boolean evaluate(Node node)
- throws RepositoryException {
- if (node.getDepth() > 0) {
- Node parent = node.getParent();
- if (parent.getPath().equals(dn.getAncestorPath())) {
- return true;
- } else {
- return evaluate(parent);
- }
- } else {
- return false;
- }
- }
- };
- } else {
- throw new IllegalArgumentException(
- "Unknown constraint type: " + constraint);
- }
- }
-
- /**
- * Evaluates the given operand against the given row. Subclasses can
- * customise the evaluation process by overriding one or more of the
- * protected getValue() methods to which this method dispatches the
- * evaluation process.
- *
- * @param operand operand
- * @param row row
- * @return value of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- public Value[] getValues(Operand operand, Row row)
- throws RepositoryException {
- if (operand instanceof BindVariableValue) {
- return getBindVariableValues((BindVariableValue) operand);
- } else if (operand instanceof FullTextSearchScore) {
- return getFullTextSearchScoreValues(
- (FullTextSearchScore) operand, row);
- } else if (operand instanceof Length) {
- return getLengthValues((Length) operand, row);
- } else if (operand instanceof Literal) {
- return getLiteralValues((Literal) operand);
- } else if (operand instanceof LowerCase) {
- return getLowerCaseValues((LowerCase) operand, row);
- } else if (operand instanceof NodeLocalName) {
- return getNodeLocalNameValues((NodeLocalName) operand, row);
- } else if (operand instanceof NodeName) {
- return getNodeNameValues((NodeName) operand, row);
- } else if (operand instanceof PropertyValue) {
- return getPropertyValues((PropertyValue) operand, row);
- } else if (operand instanceof UpperCase) {
- return getUpperCaseValues((UpperCase) operand, row);
- } else {
- throw new UnsupportedRepositoryOperationException(
- "Unknown operand type: " + operand);
- }
- }
-
- /**
- * Returns the value of the given variable value operand at the given row.
- *
- * @param operand variable value operand
- * @return value of the operand at the given row
- */
- private Value[] getBindVariableValues(BindVariableValue operand) {
- Value value = variables.get(operand.getBindVariableName());
- if (value != null) {
- return new Value[] { value };
- } else {
- return new Value[0];
- }
- }
-
- /**
- * Returns the value of the given search score operand at the given row.
- *
- * @param operand search score operand
- * @param row row
- * @return value of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getFullTextSearchScoreValues(
- FullTextSearchScore operand, Row row) throws RepositoryException {
- double score = row.getScore(operand.getSelectorName());
- return new Value[] { valueFactory.createValue(score) };
- }
-
- /**
- * Returns the values of the given value length operand at the given row.
- *
- * @see #getProperty(PropertyValue, Row)
- * @param operand value length operand
- * @param row row
- * @return values of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getLengthValues(Length operand, Row row)
- throws RepositoryException {
- Property property = getProperty(operand.getPropertyValue(), row);
- if (property == null) {
- return new Value[0];
- } else if (property.isMultiple()) {
- long[] lengths = property.getLengths();
- Value[] values = new Value[lengths.length];
- for (int i = 0; i < lengths.length; i++) {
- values[i] = valueFactory.createValue(lengths[i]);
- }
- return values;
- } else {
- long length = property.getLength();
- return new Value[] { valueFactory.createValue(length) };
- }
- }
-
- /**
- * Returns the value of the given literal value operand.
- *
- * @param operand literal value operand
- * @return value of the operand
- */
- protected Value[] getLiteralValues(Literal operand) {
- return new Value[] { operand.getLiteralValue() };
- }
-
- /**
- * Returns the values of the given lower case operand at the given row.
- *
- * @param operand lower case operand
- * @param row row
- * @return values of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getLowerCaseValues(LowerCase operand, Row row)
- throws RepositoryException {
- Value[] values = getValues(operand.getOperand(), row);
- for (int i = 0; i < values.length; i++) {
- String value = values[i].getString();
- String lower = value.toLowerCase(ENGLISH);
- if (!value.equals(lower)) {
- values[i] = valueFactory.createValue(lower);
- }
- }
- return values;
- }
-
- /**
- * Returns the value of the given local name operand at the given row.
- *
- * @param operand local name operand
- * @param row row
- * @return value of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getNodeLocalNameValues(NodeLocalName operand, Row row)
- throws RepositoryException {
- String name = row.getNode(operand.getSelectorName()).getName();
- int colon = name.indexOf(':');
- if (colon != -1) {
- name = name.substring(colon + 1);
- }
- return new Value[] { valueFactory.createValue(name, NAME) };
- }
-
- /**
- * Returns the value of the given node name operand at the given row.
- *
- * @param operand node name operand
- * @param row row
- * @return value of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getNodeNameValues(NodeName operand, Row row)
- throws RepositoryException {
- Node node = row.getNode(operand.getSelectorName());
- return new Value[] { valueFactory.createValue(node.getName(), NAME) };
- }
-
- /**
- * Returns the values of the given property value operand at the given row.
- *
- * @see #getProperty(PropertyValue, Row)
- * @param operand property value operand
- * @param row row
- * @return values of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getPropertyValues(PropertyValue operand, Row row)
- throws RepositoryException {
- Property property = getProperty(operand, row);
- if (property == null) {
- return new Value[0];
- } else if (property.isMultiple()) {
- return property.getValues();
- } else {
- return new Value[] { property.getValue() };
- }
- }
-
- /**
- * Returns the values of the given upper case operand at the given row.
- *
- * @param operand upper case operand
- * @param row row
- * @return values of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getUpperCaseValues(UpperCase operand, Row row)
- throws RepositoryException {
- Value[] values = getValues(operand.getOperand(), row);
- for (int i = 0; i < values.length; i++) {
- String value = values[i].getString();
- String upper = value.toLowerCase(ENGLISH);
- if (!value.equals(upper)) {
- values[i] = valueFactory.createValue(upper);
- }
- }
- return values;
- }
-
- /**
- * Returns the identified property from the given row. This method
- * is used by both the {@link #getValue(Length, Row)} and the
- * {@link #getValue(PropertyValue, Row)} methods to access properties.
- * Subclasses can override this method to customise property access.
- *
- * @param operand property value operand
- * @param row row
- * @return the identified property, or <code>null</code>
- * @throws RepositoryException if the property can't be accessed
- */
- protected Property getProperty(PropertyValue operand, Row row)
- throws RepositoryException {
- try {
- String selector = operand.getSelectorName();
- String property = operand.getPropertyName();
- return row.getNode(selector).getProperty(property);
- } catch (PathNotFoundException e) {
- return null;
- }
- }
-
}
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java?rev=1023777&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java Mon Oct 18 12:55:39 2010
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query.lucene.join;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Row;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.Join;
+import javax.jcr.query.qom.PropertyValue;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.SameNodeJoinCondition;
+
+class SameNodeJoinMerger extends JoinMerger {
+
+ private final String selector1;
+
+ private final String selector2;
+
+ private final String path;
+
+ public SameNodeJoinMerger(
+ Join join, Map<String, PropertyValue> columns,
+ OperandEvaluator evaluator, QueryObjectModelFactory factory,
+ SameNodeJoinCondition condition) throws RepositoryException {
+ super(join, columns, evaluator, factory);
+ this.selector1 = condition.getSelector1Name();
+ this.selector2 = condition.getSelector2Name();
+ this.path = condition.getSelector2Path();
+ }
+
+ @Override
+ public Set<String> getLeftValues(Row row) throws RepositoryException {
+ return getValues(leftSelectors, row);
+ }
+
+ @Override
+ public Set<String> getRightValues(Row row) throws RepositoryException {
+ return getValues(rightSelectors, row);
+ }
+
+ @Override
+ public Constraint getRightJoinConstraint(List<Row> leftRows)
+ throws RepositoryException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private Set<String> getValues(Set<String> selectors, Row row)
+ throws RepositoryException {
+ if (selectors.contains(selector1)) {
+ Node node = row.getNode(selector1);
+ if (node != null) {
+ return Collections.singleton(node.getPath());
+ }
+ } else if (selectors.contains(selector2)) {
+ Node node = row.getNode(selector2);
+ if (node != null) {
+ try {
+ if (path != null) {
+ node = node.getNode(path);
+ }
+ return Collections.singleton(node.getPath());
+ } catch (PathNotFoundException e) {
+ // fall through
+ }
+ }
+ } else {
+ throw new RepositoryException("Invalid same node join");
+ }
+ return Collections.emptySet();
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java
------------------------------------------------------------------------------
svn:eol-style = native