]> review.fuel-infra Code Review - packages/trusty/mysql-wsrep-5.6.git/blob
daa05b42419dfcff2cd7f012d24f385a9f8ec1ec
[packages/trusty/mysql-wsrep-5.6.git] /
1 /*
2    Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3
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.
7
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.
12
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
16 */
17
18 package com.mysql.clusterj.core.query;
19
20 import com.mysql.clusterj.ClusterJException;
21 import com.mysql.clusterj.ClusterJFatalInternalException;
22 import com.mysql.clusterj.ClusterJUserException;
23 import com.mysql.clusterj.Query;
24
25 import com.mysql.clusterj.core.query.PredicateImpl.ScanType;
26 import com.mysql.clusterj.core.spi.DomainFieldHandler;
27 import com.mysql.clusterj.core.spi.DomainTypeHandler;
28 import com.mysql.clusterj.core.spi.QueryExecutionContext;
29 import com.mysql.clusterj.core.spi.SessionSPI;
30 import com.mysql.clusterj.core.spi.ValueHandler;
31
32 import com.mysql.clusterj.core.store.Index;
33 import com.mysql.clusterj.core.store.IndexOperation;
34 import com.mysql.clusterj.core.store.IndexScanOperation;
35 import com.mysql.clusterj.core.store.Operation;
36 import com.mysql.clusterj.core.store.ResultData;
37 import com.mysql.clusterj.core.store.ScanOperation;
38
39 import com.mysql.clusterj.core.util.I18NHelper;
40 import com.mysql.clusterj.core.util.Logger;
41 import com.mysql.clusterj.core.util.LoggerFactoryService;
42
43 import com.mysql.clusterj.query.Predicate;
44 import com.mysql.clusterj.query.PredicateOperand;
45 import com.mysql.clusterj.query.QueryDefinition;
46 import com.mysql.clusterj.query.QueryDomainType;
47
48 import java.util.ArrayList;
49 import java.util.HashMap;
50 import java.util.List;
51 import java.util.Map;
52
53 public class QueryDomainTypeImpl<T> implements QueryDomainType<T> {
54
55     /** My message translator */
56     static final I18NHelper local = I18NHelper.getInstance(QueryDomainTypeImpl.class);
57
58     /** My logger */
59     static final Logger logger = LoggerFactoryService.getFactory().getInstance(QueryDomainTypeImpl.class);
60
61     /** My class. */
62     protected Class<T> cls;
63
64     /** My DomainTypeHandler. */
65     protected DomainTypeHandler<T> domainTypeHandler;
66
67     /** My where clause. */
68     protected PredicateImpl where;
69
70     /** My parameters. These encapsulate the parameter names not the values. */
71     protected Map<String, ParameterImpl> parameters =
72             new HashMap<String, ParameterImpl>();
73
74     /** My properties. These encapsulate the property names not the values. */
75     protected Map<String, PropertyImpl> properties =
76             new HashMap<String, PropertyImpl>();
77
78     public QueryDomainTypeImpl(DomainTypeHandler<T> domainTypeHandler, Class<T> cls) {
79         this.cls = cls;
80         this.domainTypeHandler = domainTypeHandler;
81     }
82
83     public QueryDomainTypeImpl(DomainTypeHandler<T> domainTypeHandler) {
84         this.domainTypeHandler = domainTypeHandler;
85     }
86
87     public PredicateOperand get(String propertyName) {
88         // if called multiple times for the same property,
89         // return the same PropertyImpl instance
90         PropertyImpl property = properties.get(propertyName);
91         if (property != null) {
92             return property;
93         } else {
94             DomainFieldHandler fmd = domainTypeHandler.getFieldHandler(propertyName);
95             property = new PropertyImpl(this, fmd);
96             properties.put(propertyName, property);
97             return property;
98         }
99     }
100
101     /** Set the where clause. Mark parameters used by this query.
102      * @param predicate the predicate
103      * @return the query definition (this)
104      */
105     public QueryDefinition<T> where(Predicate predicate) {
106         if (predicate == null) {
107             throw new ClusterJUserException(
108                     local.message("ERR_Query_Where_Must_Not_Be_Null"));
109         }
110         if (!(predicate instanceof PredicateImpl)) {
111             throw new UnsupportedOperationException(
112                     local.message("ERR_NotImplemented"));
113         }
114         // if a previous where clause, unmark the parameters
115         if (where != null) {
116             where.unmarkParameters();
117             where = null;
118         }
119         this.where = (PredicateImpl)predicate;
120         where.markParameters();
121         return this;
122     }
123
124     public PredicateOperand param(String parameterName) {
125         final ParameterImpl parameter = parameters.get(parameterName);
126         if (parameter != null) {
127             return parameter;
128         } else {
129             ParameterImpl result = new ParameterImpl(this, parameterName);
130             parameters.put(parameterName, result);
131             return result;
132         }
133     }
134
135     /** Convenience method to negate a predicate.
136      * @param predicate the predicate to negate
137      * @return the inverted predicate
138      */
139     public Predicate not(Predicate predicate) {
140         return predicate.not();
141     }
142
143     /** Query.getResultList delegates to this method.
144      * 
145      * @return the results of executing the query
146      */
147     public List<T> getResultList(QueryExecutionContext context) {
148         assertAllParametersBound(context);
149
150         SessionSPI session = context.getSession();
151         session.startAutoTransaction();
152         // set up results and table information
153         List<T> resultList = new ArrayList<T>();
154         try {
155             // execute the query
156             ResultData resultData = getResultData(context);
157             // put the result data into the result list
158             while (resultData.next()) {
159                 T row = (T) session.newInstance(cls);
160                 ValueHandler handler =domainTypeHandler.getValueHandler(row);
161                 // set values from result set into object
162                 domainTypeHandler.objectSetValues(resultData, handler);
163                 resultList.add(row);
164             }
165             session.endAutoTransaction();
166             return resultList;
167         } catch (ClusterJException ex) {
168             session.failAutoTransaction();
169             throw ex;
170         } catch (Exception ex) {
171             session.failAutoTransaction();
172             throw new ClusterJException(
173                     local.message("ERR_Exception_On_Query"), ex);
174         }
175     }
176
177     /** Execute the query and return the result data. The type of operation
178      * (primary key lookup, unique key lookup, index scan, or table scan) 
179      * depends on the where clause and the bound parameter values.
180      * 
181      * @param context the query context, including the bound parameters
182      * @return the raw result data from the query
183      * @throws ClusterJUserException if not all parameters are bound
184      */
185     public ResultData getResultData(QueryExecutionContext context) {
186         SessionSPI session = context.getSession();
187         // execute query based on what kind of scan is needed
188         // if no where clause, scan the entire table
189         CandidateIndexImpl index = where==null?
190             CandidateIndexImpl.getIndexForNullWhereClause():
191             where.getBestCandidateIndex(context);
192         ScanType scanType = index.getScanType();
193         Map<String, Object> explain = newExplain(index, scanType);
194         context.setExplain(explain);
195         ResultData result = null;
196         Index storeIndex;
197
198         switch (scanType) {
199
200             case PRIMARY_KEY: {
201                 // perform a select operation
202                 Operation op = session.getSelectOperation(domainTypeHandler.getStoreTable());
203                 // set key values into the operation
204                 index.operationSetKeys(context, op);
205                 // set the expected columns into the operation
206                 domainTypeHandler.operationGetValues(op);
207                 // execute the select and get results
208                 result = op.resultData();
209                 break;
210             }
211
212             case INDEX_SCAN: {
213                 storeIndex = index.getStoreIndex();
214                 if (logger.isDetailEnabled()) logger.detail("Using index scan with index " + index.getIndexName());
215                 IndexScanOperation op;
216                 // perform an index scan operation
217                 if (index.isMultiRange()) {
218                     op = session.getIndexScanOperationMultiRange(storeIndex, domainTypeHandler.getStoreTable());
219                     
220                 } else {
221                     op = session.getIndexScanOperation(storeIndex, domainTypeHandler.getStoreTable());
222                     
223                 }
224                 // set the expected columns into the operation
225                 domainTypeHandler.operationGetValues(op);
226                 // set the bounds into the operation
227                 index.operationSetBounds(context, op);
228                 // set additional filter conditions
229                 where.filterCmpValue(context, op);
230                 // execute the scan and get results
231                 result = op.resultData();
232                 break;
233             }
234
235             case TABLE_SCAN: {
236                 if (logger.isDetailEnabled()) logger.detail("Using table scan");
237                 // perform a table scan operation
238                 ScanOperation op = session.getTableScanOperation(domainTypeHandler.getStoreTable());
239                 // set the expected columns into the operation
240                 domainTypeHandler.operationGetValues(op);
241                 // set the bounds into the operation
242                 if (where != null) {
243                     where.filterCmpValue(context, op);
244                 }
245                 // execute the scan and get results
246                 result = op.resultData();
247                 break;
248             }
249
250             case UNIQUE_KEY: {
251                 storeIndex = index.getStoreIndex();
252                 if (logger.isDetailEnabled()) logger.detail("Using unique lookup with index " + index.getIndexName());
253                 // perform a unique lookup operation
254                 IndexOperation op = session.getUniqueIndexOperation(storeIndex, domainTypeHandler.getStoreTable());
255                 // set the keys of the indexName into the operation
256                 where.operationEqual(context, op);
257                 // set the expected columns into the operation
258                 //domainTypeHandler.operationGetValuesExcept(op, indexName);
259                 domainTypeHandler.operationGetValues(op);
260                 // execute the select and get results
261                 result = op.resultData();
262                 break;
263             }
264
265             default:
266                 session.failAutoTransaction();
267                 throw new ClusterJFatalInternalException(
268                         local.message("ERR_Illegal_Scan_Type", scanType));
269         }
270         context.deleteFilters();
271         return result;
272     }
273
274     /** Delete the instances that satisfy the query and return the number
275      * of instances deleted. The type of operation used to find the instances
276      * (primary key lookup, unique key lookup, index scan, or table scan) 
277      * depends on the where clause and the bound parameter values.
278      * 
279      * @param context the query context, including the bound parameters
280      * @return the number of instances deleted
281      * @throws ClusterJUserException if not all parameters are bound
282      */
283     public int deletePersistentAll(QueryExecutionContext context) {
284                                 SessionSPI session = context.getSession();
285         // calculate what kind of scan is needed
286         // if no where clause, scan the entire table
287         CandidateIndexImpl index = where==null?
288             CandidateIndexImpl.getIndexForNullWhereClause():
289             where.getBestCandidateIndex(context);
290         ScanType scanType = index.getScanType();
291         Map<String, Object> explain = newExplain(index, scanType);
292         context.setExplain(explain);
293         int result = 0;
294         int errorCode = 0;
295         Index storeIndex;
296         session.startAutoTransaction();
297
298         try {
299             switch (scanType) {
300
301                 case PRIMARY_KEY: {
302                     // perform a delete by primary key operation
303                     if (logger.isDetailEnabled()) logger.detail("Using delete by primary key.");
304                     Operation op = session.getDeleteOperation(domainTypeHandler.getStoreTable());
305                     // set key values into the operation
306                     index.operationSetKeys(context, op);
307                     // execute the delete operation
308                     session.executeNoCommit(false, true);
309                     errorCode = op.errorCode();
310                     // a non-zero result means the row was not deleted
311                     result = (errorCode == 0?1:0);
312                     break;
313                 }
314
315                 case UNIQUE_KEY: {
316                     storeIndex = index.getStoreIndex();
317                     if (logger.isDetailEnabled()) logger.detail(
318                             "Using delete by unique key  " + index.getIndexName());
319                     // perform a delete by unique key operation
320                     IndexOperation op = session.getUniqueIndexDeleteOperation(storeIndex,
321                             domainTypeHandler.getStoreTable());
322                     // set the keys of the indexName into the operation
323                     where.operationEqual(context, op);
324                     // execute the delete operation
325                     session.executeNoCommit(false, true);
326                     errorCode = op.errorCode();
327                     // a non-zero result means the row was not deleted
328                     result = (errorCode == 0?1:0);
329                     break;
330                 }
331
332                 case INDEX_SCAN: {
333                     storeIndex = index.getStoreIndex();
334                     if (logger.isDetailEnabled()) logger.detail(
335                             "Using delete by index scan with index " + index.getIndexName());
336                     // perform an index scan operation
337                     IndexScanOperation op = session.getIndexScanDeleteOperation(storeIndex,
338                             domainTypeHandler.getStoreTable());
339                     // set the expected columns into the operation
340                     domainTypeHandler.operationGetValues(op);
341                     // set the bounds into the operation
342                     index.operationSetBounds(context, op);
343                     // set additional filter conditions
344                     where.filterCmpValue(context, op);
345                     // delete results of the scan; don't abort if no row found
346                     result = session.deletePersistentAll(op, false);
347                     break;
348                 }
349
350                 case TABLE_SCAN: {
351                     if (logger.isDetailEnabled()) logger.detail("Using delete by table scan");
352                     // perform a table scan operation
353                     ScanOperation op = session.getTableScanDeleteOperation(domainTypeHandler.getStoreTable());
354                     // set the expected columns into the operation
355                     domainTypeHandler.operationGetValues(op);
356                     // set the bounds into the operation
357                     if (where != null) {
358                         where.filterCmpValue(context, op);
359                     }
360                     // delete results of the scan; don't abort if no row found
361                     result = session.deletePersistentAll(op, false);
362                     break;
363                 }
364
365                 default:
366                     throw new ClusterJFatalInternalException(
367                             local.message("ERR_Illegal_Scan_Type", scanType));
368             }
369             context.deleteFilters();
370             session.endAutoTransaction();
371             return result;
372         } catch (ClusterJException e) {
373             session.failAutoTransaction();
374             throw e;
375         } catch (Exception e) {
376             session.failAutoTransaction();
377             throw new ClusterJException(local.message("ERR_Exception_On_Query"), e);
378         } 
379     }
380
381     protected CandidateIndexImpl[] createCandidateIndexes() {
382         return domainTypeHandler.createCandidateIndexes();
383     }
384
385     /** Explain how this query will be or was executed and store
386      * the result in the context.
387      * 
388      * @param context the context, including bound parameters
389      */
390     public void explain(QueryExecutionContext context) {
391         assertAllParametersBound(context);
392         CandidateIndexImpl index = where==null?
393                 CandidateIndexImpl.getIndexForNullWhereClause():
394                 where.getBestCandidateIndex(context);
395         ScanType scanType = index.getScanType();
396         Map<String, Object> explain = newExplain(index, scanType);
397         context.setExplain(explain);
398     }
399
400     /** Create a new explain for this query.
401      * @param index the index used
402      * @param scanType the scan type
403      * @return the explain
404      */
405     protected Map<String, Object> newExplain(CandidateIndexImpl index,
406             ScanType scanType) {
407         Map<String, Object> explain = new HashMap<String, Object>();
408         explain.put(Query.SCAN_TYPE, scanType.toString());
409         explain.put(Query.INDEX_USED, index.getIndexName());
410         return explain;
411     }
412
413     /** Assert that all parameters used by this query are bound.
414      * @param context the context, including the parameter map
415      * @throws ClusterJUserException if not all parameters are bound
416      */
417     protected void assertAllParametersBound(QueryExecutionContext context) {
418         if (where != null) {
419             // Make sure all marked parameters (used in the query) are bound.
420             for (ParameterImpl param: parameters.values()) {
421                 if (param.isMarkedAndUnbound(context)) {
422                     throw new ClusterJUserException(
423                             local.message("ERR_Parameter_Not_Bound", param.getName()));
424                 }
425             }
426         }
427     }
428
429     public Class<T> getType() {
430         return cls;
431     }
432
433 }