001 /*
002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003 * Copyright (C) 2011 NightLabs Consulting GmbH
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
017 */
018 package org.cumulus4j.store.query.eval;
019
020 import java.util.HashSet;
021 import java.util.Set;
022
023 import org.cumulus4j.store.query.QueryEvaluator;
024 import org.cumulus4j.store.query.QueryHelper;
025 import org.datanucleus.query.expression.DyadicExpression;
026 import org.datanucleus.query.expression.Expression;
027 import org.datanucleus.util.NucleusLogger;
028
029 /**
030 * <p>
031 * Evaluator handling the boolean operation "||" (OR).
032 * </p>
033 * <p>
034 * This evaluator works just like the {@link AndExpressionEvaluator} with the only difference
035 * that it unites the partial results instead of intersecting them.
036 * </p>
037 * <p>
038 * If the {@link ResultDescriptor} indicates a {@link ResultDescriptor#isNegated() negation}, this evaluator
039 * delegates to the {@link AndExpressionEvaluator}, because a query like
040 * "!( a > 5 || b <= 12 )" is internally converted to "a <= 5 && b > 12" for performance reasons.
041 * See {@link NotExpressionEvaluator} as well as
042 * <a target="_blank" href="http://en.wikipedia.org/wiki/De_Morgan%27s_laws">De Morgan's laws</a> in wikipedia for details.
043 * </p>
044 *
045 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
046 * @see AndExpressionEvaluator
047 */
048 public class OrExpressionEvaluator
049 extends AbstractExpressionEvaluator<DyadicExpression>
050 {
051 private AndExpressionEvaluator negatedExpressionEvaluator;
052
053 public OrExpressionEvaluator(QueryEvaluator queryEvaluator, AbstractExpressionEvaluator<?> parent, DyadicExpression expression) {
054 super(queryEvaluator, parent, expression);
055 }
056
057 public OrExpressionEvaluator(AndExpressionEvaluator negatedExpressionEvaluator)
058 {
059 this(negatedExpressionEvaluator.getQueryEvaluator(), negatedExpressionEvaluator.getParent(), negatedExpressionEvaluator.getExpression());
060 this.negatedExpressionEvaluator = negatedExpressionEvaluator;
061 }
062
063 @Override
064 public AbstractExpressionEvaluator<? extends Expression> getLeft() {
065 if (negatedExpressionEvaluator != null)
066 return negatedExpressionEvaluator.getLeft();
067
068 return super.getLeft();
069 }
070
071 @Override
072 public AbstractExpressionEvaluator<? extends Expression> getRight() {
073 if (negatedExpressionEvaluator != null)
074 return negatedExpressionEvaluator.getRight();
075
076 return super.getRight();
077 }
078
079 @Override
080 protected Set<Long> _queryResultDataEntryIDs(ResultDescriptor resultDescriptor)
081 {
082 if (resultDescriptor.isNegated())
083 return new AndExpressionEvaluator(this)._queryResultDataEntryIDsIgnoringNegation(resultDescriptor);
084 else
085 return _queryResultDataEntryIDsIgnoringNegation(resultDescriptor);
086 }
087
088 protected Set<Long> _queryResultDataEntryIDsIgnoringNegation(ResultDescriptor resultDescriptor)
089 {
090 if (getLeft() == null)
091 throw new IllegalStateException("getLeft() == null");
092
093 if (getRight() == null)
094 throw new IllegalStateException("getRight() == null");
095
096 Set<Long> leftResult = null;
097 boolean leftEvaluated = true;
098 try {
099 leftResult = getLeft().queryResultDataEntryIDs(resultDescriptor);
100 }
101 catch (UnsupportedOperationException uoe) {
102 leftEvaluated = false;
103 getQueryEvaluator().setIncomplete();
104 NucleusLogger.QUERY.debug("Unsupported operation in LEFT : "+getLeft().getExpression() + " so deferring evaluation to in-memory");
105 }
106
107 Set<Long> rightResult = null;
108 boolean rightEvaluated = true;
109 try {
110 rightResult = getRight().queryResultDataEntryIDs(resultDescriptor);
111 }
112 catch (UnsupportedOperationException uoe) {
113 rightEvaluated = false;
114 getQueryEvaluator().setIncomplete();
115 NucleusLogger.QUERY.debug("Unsupported operation in RIGHT : "+getRight().getExpression() + " so deferring evaluation to in-memory");
116 }
117
118 if (leftEvaluated && !rightEvaluated) {
119 rightResult = QueryHelper.getAllDataEntryIdsForCandidate(getQueryEvaluator().getPersistenceManagerForData(),
120 getQueryEvaluator().getExecutionContext(), getQueryEvaluator().getQuery().getCandidateClass(), getQueryEvaluator().getQuery().isSubclasses());
121 }
122 else if (!leftEvaluated && rightEvaluated) {
123 leftResult = QueryHelper.getAllDataEntryIdsForCandidate(getQueryEvaluator().getPersistenceManagerForData(),
124 getQueryEvaluator().getExecutionContext(), getQueryEvaluator().getQuery().getCandidateClass(), getQueryEvaluator().getQuery().isSubclasses());
125 }
126 else if (!leftEvaluated && !rightEvaluated) {
127 leftResult = QueryHelper.getAllDataEntryIdsForCandidate(getQueryEvaluator().getPersistenceManagerForData(),
128 getQueryEvaluator().getExecutionContext(), getQueryEvaluator().getQuery().getCandidateClass(), getQueryEvaluator().getQuery().isSubclasses());
129 }
130
131 if (leftResult != null && rightResult != null) {
132 Set<Long> result = new HashSet<Long>(leftResult.size() + rightResult.size());
133 result.addAll(leftResult);
134 result.addAll(rightResult);
135 return result;
136 }
137 else if (leftResult != null)
138 return leftResult;
139 else
140 return rightResult;
141 }
142 }