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 }