2 Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 package com.mysql.clusterj.core.query;
20 import java.util.List;
22 import com.mysql.clusterj.ClusterJException;
23 import com.mysql.clusterj.ClusterJUserException;
24 import com.mysql.clusterj.core.spi.QueryExecutionContext;
25 import com.mysql.clusterj.core.store.IndexScanOperation;
26 import com.mysql.clusterj.core.store.ScanFilter;
27 import com.mysql.clusterj.core.store.ScanOperation;
28 import com.mysql.clusterj.core.store.IndexScanOperation.BoundType;
29 import com.mysql.clusterj.core.store.ScanFilter.BinaryCondition;
30 import com.mysql.clusterj.core.store.ScanFilter.Group;
32 public class InPredicateImpl extends PredicateImpl {
35 protected PropertyImpl property;
37 /** The parameter containing the values */
38 protected ParameterImpl parameter;
40 public InPredicateImpl(QueryDomainTypeImpl<?> dobj,
41 PropertyImpl property, ParameterImpl parameter) {
43 this.property = property;
44 this.parameter = parameter;
45 parameter.setProperty(property);
46 // mark this property as having complex values
47 property.setComplexParameter();
51 public void markParameters() {
56 public void unmarkParameters() {
61 void markBoundsForCandidateIndices(QueryExecutionContext context,
62 CandidateIndexImpl[] candidateIndices) {
63 if (parameter.getParameterValue(context) == null) {
64 // null parameters cannot be used with index scans
67 property.markInBound(candidateIndices, this);
70 /** Set bound for the multi-valued parameter identified by the index.
72 * @param context the query execution context
73 * @param op the operation to set bounds on
74 * @param index the index into the parameter list
75 * @param lastColumn if true, can set strict bound
77 public void operationSetBound(
78 QueryExecutionContext context, IndexScanOperation op, int index, boolean lastColumn) {
80 // last column can be strict
81 operationSetBound(context, op, index, BoundType.BoundEQ);
83 // not last column cannot be strict
84 operationSetBound(context, op, index, BoundType.BoundLE);
85 operationSetBound(context, op, index, BoundType.BoundGE);
89 public void operationSetUpperBound(QueryExecutionContext context, IndexScanOperation op, int index) {
90 operationSetBound(context, op, index, BoundType.BoundGE);
93 public void operationSetLowerBound(QueryExecutionContext context, IndexScanOperation op, int index) {
94 operationSetBound(context, op, index, BoundType.BoundLE);
97 private void operationSetBound(
98 QueryExecutionContext context, IndexScanOperation op, int index, BoundType boundType) {
99 Object parameterValue = parameter.getParameterValue(context);
100 if (parameterValue == null) {
101 throw new ClusterJUserException(
102 local.message("ERR_Parameter_Cannot_Be_Null", "operator in", parameter.parameterName));
103 } else if (parameterValue instanceof List<?>) {
104 List<?> parameterList = (List<?>)parameterValue;
105 Object value = parameterList.get(index);
106 property.operationSetBounds(value, boundType, op);
107 if (logger.isDetailEnabled()) logger.detail("InPredicateImpl.operationSetBound for " + property.fmd.getName() + " List index: " + index + " value: " + value + " boundType: " + boundType);
108 } else if (parameterValue.getClass().isArray()) {
109 Object[] parameterArray = (Object[])parameterValue;
110 Object value = parameterArray[index];
111 property.operationSetBounds(value, boundType, op);
112 if (logger.isDetailEnabled()) logger.detail("InPredicateImpl.operationSetBound for " + property.fmd.getName() + " array index: " + index + " value: " + value + " boundType: " + boundType);
114 throw new ClusterJUserException(
115 local.message("ERR_Parameter_Wrong_Type", parameter.parameterName,
116 parameterValue.getClass().getName(), "List<?> or Object[]"));
120 /** Set bounds for the multi-valued parameter identified by the index.
121 * There is only one column in the bound, so set each bound and then end the bound.
123 * @param context the query execution context
124 * @param op the operation to set bounds on
125 * @param index the index into the parameter list
127 public void operationSetAllBounds(QueryExecutionContext context,
128 IndexScanOperation op) {
129 Object parameterValue = parameter.getParameterValue(context);
131 if (parameterValue == null) {
132 throw new ClusterJUserException(
133 local.message("ERR_Parameter_Cannot_Be_Null", "operator in", parameter.parameterName));
134 } else if (parameterValue instanceof List<?>) {
135 List<?> parameterList = (List<?>)parameterValue;
136 for (Object value: parameterList) {
137 property.operationSetBounds(value, BoundType.BoundEQ, op);
138 if (logger.isDetailEnabled()) logger.detail("InPredicateImpl.operationSetAllBounds for List index: " + index + " value: " + value);
139 op.endBound(index++);
141 } else if (parameterValue.getClass().isArray()) {
142 Object[] parameterArray = (Object[])parameterValue;
143 for (Object value: parameterArray) {
144 property.operationSetBounds(value, BoundType.BoundEQ, op);
145 if (logger.isDetailEnabled()) logger.detail("InPredicateImpl.operationSetAllBounds for array index: " + index + " value: " + value);
146 op.endBound(index++);
149 throw new ClusterJUserException(
150 local.message("ERR_Parameter_Wrong_Type", parameter.parameterName,
151 parameterValue.getClass().getName(), "List<?> or Object[]"));
155 /** Create a filter for the operation. Call the property to set the filter
156 * from the parameter values.
157 * @param context the query execution context with the parameter values
158 * @param op the operation
160 public void filterCmpValue(QueryExecutionContext context,
163 ScanFilter filter = op.getScanFilter(context);
164 filterCmpValue(context, op, filter);
165 } catch (ClusterJException ex) {
167 } catch (Exception ex) {
168 throw new ClusterJException(
169 local.message("ERR_Get_NdbFilter"), ex);
173 /** Use an existing filter for the operation. Call the property to set the filter
174 * from the parameter values.
175 * @param context the query execution context with the parameter values
176 * @param op the operation
177 * @param filter the existing filter
179 public void filterCmpValue(QueryExecutionContext context, ScanOperation op, ScanFilter filter) {
181 filter.begin(Group.GROUP_OR);
182 Object parameterValue = parameter.getParameterValue(context);
183 if (parameterValue == null) {
184 throw new ClusterJUserException(
185 local.message("ERR_Parameter_Cannot_Be_Null", "operator in", parameter.parameterName));
186 } else if (parameterValue instanceof Iterable<?>) {
187 Iterable<?> iterable = (Iterable<?>)parameterValue;
188 for (Object value: iterable) {
189 property.filterCmpValue(value, BinaryCondition.COND_EQ, filter);
191 } else if (parameterValue.getClass().isArray()) {
192 Object[] parameterArray = (Object[])parameterValue;
193 for (Object parameter: parameterArray) {
194 property.filterCmpValue(parameter, BinaryCondition.COND_EQ, filter);
197 throw new ClusterJUserException(
198 local.message("ERR_Parameter_Wrong_Type", parameter.parameterName,
199 parameterValue.getClass().getName(), "Iterable<?> or Object[]"));
202 } catch (ClusterJException ex) {
204 } catch (Exception ex) {
205 throw new ClusterJException(
206 local.message("ERR_Get_NdbFilter"), ex);
210 public int getParameterSize(QueryExecutionContext context) {
212 Object parameterValue = parameter.getParameterValue(context);
213 if (parameterValue instanceof List<?>) {
214 result = ((List<?>)parameterValue).size();
216 Class<?> cls = parameterValue.getClass();
218 if (!Object.class.isAssignableFrom(cls.getComponentType())) {
219 throw new ClusterJUserException(local.message("ERR_Wrong_Parameter_Type_For_In",
220 property.fmd.getName()));
222 Object[] parameterArray = (Object[])parameterValue;
223 result = parameterArray.length;
226 throw new ClusterJUserException(local.message("ERR_Parameter_Too_Big_For_In",
227 property.fmd.getName(), result));
229 // single value parameter