MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SQLExecutor.java
1 /*
2  * Copyright (c) 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.jdbc;
19 
20 import com.mysql.clusterj.ClusterJFatalInternalException;
21 import com.mysql.clusterj.ClusterJUserException;
22 import com.mysql.clusterj.core.query.QueryDomainTypeImpl;
23 import com.mysql.clusterj.core.query.QueryExecutionContextImpl;
24 import com.mysql.clusterj.core.spi.DomainTypeHandler;
25 import com.mysql.clusterj.core.spi.QueryExecutionContext;
26 import com.mysql.clusterj.core.spi.SessionSPI;
27 import com.mysql.clusterj.core.spi.ValueHandler;
28 import com.mysql.clusterj.core.store.ResultData;
29 import com.mysql.clusterj.core.util.I18NHelper;
30 import com.mysql.clusterj.core.util.Logger;
31 import com.mysql.clusterj.core.util.LoggerFactoryService;
32 import com.mysql.jdbc.ParameterBindings;
33 import com.mysql.jdbc.ResultSetInternalMethods;
34 
35 import java.sql.SQLException;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 
44 public class SQLExecutor {
45 
47  static final I18NHelper local = I18NHelper.getInstance(SQLExecutor.class);
48 
50  static final Logger logger = LoggerFactoryService.getFactory().getInstance(SQLExecutor.class);
51 
53  DomainTypeHandler<?> domainTypeHandler = null;
54 
56  protected List<String> columnNames = null;
57 
59  protected int numberOfFields;
60 
62  protected int numberOfParameters;
63 
65  protected int[] fieldNumberToColumnNumberMap = null;
66 
68  protected int[] columnNumberToFieldNumberMap = null;
69 
71  protected Map<String, Integer> columnNameToFieldNumberMap = new HashMap<String, Integer>();
72 
74  protected QueryDomainTypeImpl<?> queryDomainType;
75 
76  public SQLExecutor(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames, int numberOfParameters) {
77  this(domainTypeHandler, columnNames);
78  this.numberOfParameters = numberOfParameters;
79  }
80 
81  public SQLExecutor(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames) {
82  this.domainTypeHandler = domainTypeHandler;
83  this.columnNames = columnNames;
84  initializeFieldNumberMap();
85  }
86 
87  public SQLExecutor(DomainTypeHandlerImpl<?> domainTypeHandler) {
88  this.domainTypeHandler = domainTypeHandler;
89  }
90 
91  public SQLExecutor(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames,
92  QueryDomainTypeImpl<?> queryDomainType) {
93  this(domainTypeHandler, columnNames);
94  this.queryDomainType = queryDomainType;
95  initializeFieldNumberMap();
96  }
97 
98  public SQLExecutor(DomainTypeHandlerImpl<?> domainTypeHandler, QueryDomainTypeImpl<?> queryDomainType,
99  int numberOfParameters) {
100  this.domainTypeHandler = domainTypeHandler;
101  this.queryDomainType = queryDomainType;
102  this.numberOfParameters = numberOfParameters;
103  }
104 
109  public interface Executor {
110 
117  ResultSetInternalMethods execute(InterceptorImpl interceptor,
118  ParameterBindings parameterBindings) throws SQLException;
119  }
120 
124  public static class Noop implements Executor {
125 
126  public ResultSetInternalMethods execute(InterceptorImpl interceptor,
127  ParameterBindings parameterBindings) throws SQLException {
128  return null;
129  }
130  }
131 
134  public static class Select extends SQLExecutor implements Executor {
135 
136  public Select(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames, QueryDomainTypeImpl<?> queryDomainType) {
137  super(domainTypeHandler, columnNames, queryDomainType);
138  if (queryDomainType == null) {
139  throw new ClusterJFatalInternalException("queryDomainType must not be null for Select.");
140  }
141  }
142 
143  public ResultSetInternalMethods execute(InterceptorImpl interceptor,
144  ParameterBindings parameterBindings) throws SQLException {
145  // create value handler to copy data from parameters to ndb
146  // count the parameters
147  int count = countParameters(parameterBindings);
148  SessionSPI session = interceptor.getSession();
149  Map<String, Object> parameters = createParameterMap(queryDomainType, parameterBindings, 0, count);
150  QueryExecutionContext context = new QueryExecutionContextImpl(session, parameters);
151  session.startAutoTransaction();
152  try {
153  ResultData resultData = queryDomainType.getResultData(context);
154  // session.endAutoTransaction();
155  return new ResultSetInternalMethodsImpl(resultData, columnNumberToFieldNumberMap,
156  columnNameToFieldNumberMap, session);
157  } catch (Exception e) {
158  e.printStackTrace();
159  session.failAutoTransaction();
160  return null;
161  }
162  }
163  }
164 
167  public static class Delete extends SQLExecutor implements Executor {
168 
169  public Delete (DomainTypeHandlerImpl<?> domainTypeHandler, QueryDomainTypeImpl<?> queryDomainType,
170  int numberOfParameters) {
171  super(domainTypeHandler, queryDomainType, numberOfParameters);
172  }
173 
174  public Delete (DomainTypeHandlerImpl<?> domainTypeHandler) {
175  super(domainTypeHandler);
176  }
177 
178  public ResultSetInternalMethods execute(InterceptorImpl interceptor,
179  ParameterBindings parameterBindings) throws SQLException {
180  SessionSPI session = interceptor.getSession();
181  if (queryDomainType == null) {
182  int rowsDeleted = session.deletePersistentAll(domainTypeHandler);
183  if (logger.isDebugEnabled()) logger.debug("deleteAll deleted: " + rowsDeleted);
184  return new ResultSetInternalMethodsUpdateCount(rowsDeleted);
185  } else {
186  int numberOfBoundParameters = countParameters(parameterBindings);
187  int numberOfStatements = numberOfBoundParameters / numberOfParameters;
188  long[] deleteResults = new long[numberOfStatements];
189  if (logger.isDebugEnabled()) logger.debug(
190  " numberOfParameters: " + numberOfParameters
191  + " numberOfBoundParameters: " + numberOfBoundParameters
192  + " numberOfStatements: " + numberOfStatements
193  );
194  QueryExecutionContextJDBCImpl context =
195  new QueryExecutionContextJDBCImpl(session, parameterBindings, numberOfParameters);
196  for (int i = 0; i < numberOfStatements; ++i) {
197  // this will execute each statement in the batch using different parameters
198  int statementRowsDeleted = queryDomainType.deletePersistentAll(context);
199  if (logger.isDebugEnabled()) logger.debug("statement " + i
200  + " deleted " + statementRowsDeleted);
201  deleteResults[i] = statementRowsDeleted;
202  context.nextStatement();
203  }
204  return new ResultSetInternalMethodsUpdateCount(deleteResults);
205  }
206  }
207  }
208 
211  public static class Insert extends SQLExecutor implements Executor {
212 
213  public Insert(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames) {
214  super(domainTypeHandler, columnNames, columnNames.size());
215  }
216 
217  public ResultSetInternalMethods execute(InterceptorImpl interceptor,
218  ParameterBindings parameterBindings) throws SQLException {
219  SessionSPI session = interceptor.getSession();
220  int numberOfBoundParameters = countParameters(parameterBindings);
221  int numberOfStatements = numberOfBoundParameters / numberOfParameters;
222  if (logger.isDebugEnabled()) logger.debug("SQLExecutor.Insert.execute"
223  + " numberOfParameters: " + numberOfParameters
224  + " numberOfBoundParameters: " + numberOfBoundParameters
225  + " numberOfFields: " + numberOfFields
226  + " numberOfStatements: " + numberOfStatements
227  );
228  // interceptor.beforeClusterjStart();
229  // session asks for values by field number which are converted to parameter number
230  for (int offset = 0; offset < numberOfBoundParameters; offset += numberOfParameters) {
231  ValueHandler valueHandler = getValueHandler(parameterBindings, fieldNumberToColumnNumberMap, offset);
232  session.insert(domainTypeHandler, valueHandler);
233  }
234  session.flush();
235  // interceptor.afterClusterjStart();
236  return new ResultSetInternalMethodsUpdateCount(numberOfStatements);
237  }
238  }
239 
251  protected Map<String, Object> createParameterMap(QueryDomainTypeImpl<?> queryDomainType,
252  ParameterBindings parameterBindings, int offset, int count) throws SQLException {
253  Map<String, Object> result = new HashMap<String, Object>();
254  int first = offset + 1;
255  int last = offset + count + 1;
256  for (int i = first; i < last; ++i) {
257  Object placeholder = parameterBindings.getObject(i);
258  if (logger.isDetailEnabled())
259  logger.detail("Put placeholder " + i + " value: " + placeholder + " of type " + placeholder.getClass());
260  result.put(String.valueOf(i), placeholder);
261  }
262  return result;
263  }
264 
275  private void initializeFieldNumberMap() {
276  // the index into the int[] is the 0-origin field number (columns in order of definition in the schema)
277  // the value is the index into the parameter bindings (columns in order of the sql insert statement)
278  String[] fieldNames = domainTypeHandler.getFieldNames();
279  numberOfFields = fieldNames.length;
281  columnNumberToFieldNumberMap = new int[1 + columnNames.size()];
282  for (int i= 0; i < numberOfFields; ++i) {
283  columnNameToFieldNumberMap.put(fieldNames[i], i);
284  int index = columnNames.indexOf(fieldNames[i]);
285  if (index >= 0) {
286  // index origin 1 for JDBC interfaces
287  fieldNumberToColumnNumberMap[i] = index + 1;
288  columnNumberToFieldNumberMap[index + 1] = i;
289  } else {
290  // field is not in column list
292  }
293  }
294  // make sure all columns are fields and if not, throw an exception
295  for (String columnName: columnNames) {
296  if (columnNameToFieldNumberMap.get(columnName) == null) {
297  throw new ClusterJUserException(
298  local.message("ERR_Column_Name_Not_In_Table", columnName,
299  Arrays.toString(fieldNames),
300  domainTypeHandler.getTableName()));
301  }
302  }
303  if (logger.isDetailEnabled()) {
304  StringBuilder buffer = new StringBuilder();
305  for (int i = 0; i < fieldNumberToColumnNumberMap.length; ++i) {
306  int columnNumber = fieldNumberToColumnNumberMap[i];
307  buffer.append("field ");
308  buffer.append(i);
309  buffer.append(" mapped to ");
310  buffer.append(columnNumber);
311  buffer.append("[");
312  buffer.append(columnNumber == -1?"nothing":(columnNames.get(columnNumber - 1)));
313  buffer.append("];");
314  }
315  logger.detail(buffer.toString());
316  }
317  }
318 
325  protected ValueHandler getValueHandler(ParameterBindings parameterBindings,
326  int[] fieldNumberToParameterNumberMap, int offset) {
327  return new ValueHandlerImpl(parameterBindings, fieldNumberToParameterNumberMap, offset);
328  }
329 
333  protected static void logParameterBindings(ParameterBindings parameterBindings) {
334  if (logger.isDetailEnabled()) {
335  int i = 0;
336  while (true) {
337  try {
338  String value = parameterBindings.getObject(++i).toString();
339  // parameters are 1-origin per jdbc specification
340  logger.detail("parameterBinding: parameter " + i + " has value: " + value);
341  } catch (Exception e) {
342  // we don't know how many parameters are bound...
343  break;
344  }
345  }
346  }
347  }
348 
355  protected static int countParameters(ParameterBindings parameterBindings) {
356  int i = 0;
357  while (true) {
358  try {
359  ++i;
360  // parameters are 1-origin per jdbc specification
361  Object objectValue = parameterBindings.getObject(i);
362  if (logger.isDetailEnabled()) {
363  logger.detail("parameterBinding: parameter " + i
364  + " has value: " + objectValue
365  + " of type " + objectValue.getClass());
366  }
367  } catch (Exception e) {
368  // we don't know how many parameters are bound...
369  break;
370  }
371  }
372  return i - 1;
373  }
374 
375 }