PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/EQEmuJSM/mysql-connector-java-5.1.13/src/com/mysql/jdbc/ServerPreparedStatement.java

http://cubbers-eqemu-utils.googlecode.com/
Java | 2358 lines | 1472 code | 407 blank | 479 comment | 285 complexity | c998aec71828fb17aaf47ac6985f8e7a MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Copyright 2002-2007 MySQL AB, 2008-2010 Sun Microsystems
  3. All rights reserved. Use is subject to license terms.
  4. The MySQL Connector/J is licensed under the terms of the GPL,
  5. like most MySQL Connectors. There are special exceptions to the
  6. terms and conditions of the GPL as it is applied to this software,
  7. see the FLOSS License Exception available on mysql.com.
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation; version 2 of the
  11. License.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  19. 02110-1301 USA
  20. */
  21. package com.mysql.jdbc;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.Reader;
  25. import java.io.UnsupportedEncodingException;
  26. import java.lang.reflect.Constructor;
  27. import java.lang.reflect.InvocationTargetException;
  28. import java.math.BigDecimal;
  29. import java.net.URL;
  30. import java.sql.Array;
  31. import java.sql.Blob;
  32. import java.sql.Clob;
  33. import java.sql.Date;
  34. import java.sql.ParameterMetaData;
  35. import java.sql.Ref;
  36. import java.sql.ResultSet;
  37. import java.sql.SQLException;
  38. import java.sql.Time;
  39. import java.sql.Timestamp;
  40. import java.sql.Types;
  41. import java.util.ArrayList;
  42. import java.util.Calendar;
  43. import java.util.GregorianCalendar;
  44. import java.util.TimeZone;
  45. import com.mysql.jdbc.exceptions.MySQLStatementCancelledException;
  46. import com.mysql.jdbc.exceptions.MySQLTimeoutException;
  47. import com.mysql.jdbc.profiler.ProfilerEvent;
  48. /**
  49. * JDBC Interface for MySQL-4.1 and newer server-side PreparedStatements.
  50. *
  51. * @author Mark Matthews
  52. * @version $Id: ServerPreparedStatement.java,v 1.1.2.2 2005/05/17 14:58:56
  53. * mmatthews Exp $
  54. */
  55. public class ServerPreparedStatement extends PreparedStatement {
  56. private static final Constructor JDBC_4_SPS_CTOR;
  57. static {
  58. if (Util.isJdbc4()) {
  59. try {
  60. JDBC_4_SPS_CTOR = Class.forName("com.mysql.jdbc.JDBC4ServerPreparedStatement")
  61. .getConstructor(
  62. new Class[] { MySQLConnection.class, String.class, String.class,
  63. Integer.TYPE, Integer.TYPE});
  64. } catch (SecurityException e) {
  65. throw new RuntimeException(e);
  66. } catch (NoSuchMethodException e) {
  67. throw new RuntimeException(e);
  68. } catch (ClassNotFoundException e) {
  69. throw new RuntimeException(e);
  70. }
  71. } else {
  72. JDBC_4_SPS_CTOR = null;
  73. }
  74. }
  75. protected static final int BLOB_STREAM_READ_BUF_SIZE = 8192;
  76. static class BatchedBindValues {
  77. BindValue[] batchedParameterValues;
  78. BatchedBindValues(BindValue[] paramVals) {
  79. int numParams = paramVals.length;
  80. this.batchedParameterValues = new BindValue[numParams];
  81. for (int i = 0; i < numParams; i++) {
  82. this.batchedParameterValues[i] = new BindValue(paramVals[i]);
  83. }
  84. }
  85. }
  86. public static class BindValue {
  87. long boundBeforeExecutionNum = 0;
  88. public long bindLength; /* Default length of data */
  89. int bufferType; /* buffer type */
  90. byte byteBinding;
  91. double doubleBinding;
  92. float floatBinding;
  93. int intBinding;
  94. public boolean isLongData; /* long data indicator */
  95. public boolean isNull; /* NULL indicator */
  96. boolean isSet = false; /* has this parameter been set? */
  97. long longBinding;
  98. short shortBinding;
  99. public Object value; /* The value to store */
  100. BindValue() {
  101. }
  102. BindValue(BindValue copyMe) {
  103. this.value = copyMe.value;
  104. this.isSet = copyMe.isSet;
  105. this.isLongData = copyMe.isLongData;
  106. this.isNull = copyMe.isNull;
  107. this.bufferType = copyMe.bufferType;
  108. this.bindLength = copyMe.bindLength;
  109. this.byteBinding = copyMe.byteBinding;
  110. this.shortBinding = copyMe.shortBinding;
  111. this.intBinding = copyMe.intBinding;
  112. this.longBinding = copyMe.longBinding;
  113. this.floatBinding = copyMe.floatBinding;
  114. this.doubleBinding = copyMe.doubleBinding;
  115. }
  116. void reset() {
  117. this.isSet = false;
  118. this.value = null;
  119. this.isLongData = false;
  120. this.byteBinding = 0;
  121. this.shortBinding = 0;
  122. this.intBinding = 0;
  123. this.longBinding = 0L;
  124. this.floatBinding = 0;
  125. this.doubleBinding = 0D;
  126. }
  127. public String toString() {
  128. return toString(false);
  129. }
  130. public String toString(boolean quoteIfNeeded) {
  131. if (this.isLongData) {
  132. return "' STREAM DATA '";
  133. }
  134. switch (this.bufferType) {
  135. case MysqlDefs.FIELD_TYPE_TINY:
  136. return String.valueOf(byteBinding);
  137. case MysqlDefs.FIELD_TYPE_SHORT:
  138. return String.valueOf(shortBinding);
  139. case MysqlDefs.FIELD_TYPE_LONG:
  140. return String.valueOf(intBinding);
  141. case MysqlDefs.FIELD_TYPE_LONGLONG:
  142. return String.valueOf(longBinding);
  143. case MysqlDefs.FIELD_TYPE_FLOAT:
  144. return String.valueOf(floatBinding);
  145. case MysqlDefs.FIELD_TYPE_DOUBLE:
  146. return String.valueOf(doubleBinding);
  147. case MysqlDefs.FIELD_TYPE_TIME:
  148. case MysqlDefs.FIELD_TYPE_DATE:
  149. case MysqlDefs.FIELD_TYPE_DATETIME:
  150. case MysqlDefs.FIELD_TYPE_TIMESTAMP:
  151. case MysqlDefs.FIELD_TYPE_VAR_STRING:
  152. case MysqlDefs.FIELD_TYPE_STRING:
  153. case MysqlDefs.FIELD_TYPE_VARCHAR:
  154. if (quoteIfNeeded) {
  155. return "'" + String.valueOf(value) + "'";
  156. } else {
  157. return String.valueOf(value);
  158. }
  159. default:
  160. if (value instanceof byte[]) {
  161. return "byte data";
  162. } else {
  163. if (quoteIfNeeded) {
  164. return "'" + String.valueOf(value) + "'";
  165. } else {
  166. return String.valueOf(value);
  167. }
  168. }
  169. }
  170. }
  171. long getBoundLength() {
  172. if (isNull) {
  173. return 0;
  174. }
  175. if (isLongData) {
  176. return bindLength;
  177. }
  178. switch (bufferType) {
  179. case MysqlDefs.FIELD_TYPE_TINY:
  180. return 1;
  181. case MysqlDefs.FIELD_TYPE_SHORT:
  182. return 2;
  183. case MysqlDefs.FIELD_TYPE_LONG:
  184. return 4;
  185. case MysqlDefs.FIELD_TYPE_LONGLONG:
  186. return 8;
  187. case MysqlDefs.FIELD_TYPE_FLOAT:
  188. return 4;
  189. case MysqlDefs.FIELD_TYPE_DOUBLE:
  190. return 8;
  191. case MysqlDefs.FIELD_TYPE_TIME:
  192. return 9;
  193. case MysqlDefs.FIELD_TYPE_DATE:
  194. return 7;
  195. case MysqlDefs.FIELD_TYPE_DATETIME:
  196. case MysqlDefs.FIELD_TYPE_TIMESTAMP:
  197. return 11;
  198. case MysqlDefs.FIELD_TYPE_VAR_STRING:
  199. case MysqlDefs.FIELD_TYPE_STRING:
  200. case MysqlDefs.FIELD_TYPE_VARCHAR:
  201. case MysqlDefs.FIELD_TYPE_DECIMAL:
  202. case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
  203. if (value instanceof byte[]) {
  204. return ((byte[]) value).length;
  205. } else {
  206. return ((String) value).length();
  207. }
  208. default:
  209. return 0;
  210. }
  211. }
  212. }
  213. /* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
  214. private static final byte MAX_DATE_REP_LENGTH = (byte) 5;
  215. /*
  216. * 1 (length) + 2 (year) + 1 (month) + 1 (day) + 1 (hour) + 1 (minute) + 1
  217. * (second) + 4 (microseconds)
  218. */
  219. private static final byte MAX_DATETIME_REP_LENGTH = 12;
  220. /*
  221. * 1 (length) + 1 (is negative) + 4 (day count) + 1 (hour) + 1 (minute) + 1
  222. * (seconds) + 4 (microseconds)
  223. */
  224. private static final byte MAX_TIME_REP_LENGTH = 13;
  225. private boolean hasOnDuplicateKeyUpdate = false;
  226. private void storeTime(Buffer intoBuf, Time tm) throws SQLException {
  227. intoBuf.ensureCapacity(9);
  228. intoBuf.writeByte((byte) 8); // length
  229. intoBuf.writeByte((byte) 0); // neg flag
  230. intoBuf.writeLong(0); // tm->day, not used
  231. Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
  232. synchronized (sessionCalendar) {
  233. java.util.Date oldTime = sessionCalendar.getTime();
  234. try {
  235. sessionCalendar.setTime(tm);
  236. intoBuf.writeByte((byte) sessionCalendar.get(Calendar.HOUR_OF_DAY));
  237. intoBuf.writeByte((byte) sessionCalendar.get(Calendar.MINUTE));
  238. intoBuf.writeByte((byte) sessionCalendar.get(Calendar.SECOND));
  239. // intoBuf.writeLongInt(0); // tm-second_part
  240. } finally {
  241. sessionCalendar.setTime(oldTime);
  242. }
  243. }
  244. }
  245. /**
  246. * Flag indicating whether or not the long parameters have been 'switched'
  247. * back to normal parameters. We can not execute() if clearParameters()
  248. * hasn't been called in this case.
  249. */
  250. private boolean detectedLongParameterSwitch = false;
  251. /**
  252. * The number of fields in the result set (if any) for this
  253. * PreparedStatement.
  254. */
  255. private int fieldCount;
  256. /** Has this prepared statement been marked invalid? */
  257. private boolean invalid = false;
  258. /** If this statement has been marked invalid, what was the reason? */
  259. private SQLException invalidationException;
  260. /** Does this query modify data? */
  261. private boolean isSelectQuery;
  262. private Buffer outByteBuffer;
  263. /** Bind values for individual fields */
  264. private BindValue[] parameterBindings;
  265. /** Field-level metadata for parameters */
  266. private Field[] parameterFields;
  267. /** Field-level metadata for result sets. */
  268. private Field[] resultFields;
  269. /** Do we need to send/resend types to the server? */
  270. private boolean sendTypesToServer = false;
  271. /** The ID that the server uses to identify this PreparedStatement */
  272. private long serverStatementId;
  273. /** The type used for string bindings, changes from version-to-version */
  274. private int stringTypeCode = MysqlDefs.FIELD_TYPE_STRING;
  275. private boolean serverNeedsResetBeforeEachExecution;
  276. /**
  277. * Creates a prepared statement instance -- We need to provide factory-style
  278. * methods so we can support both JDBC3 (and older) and JDBC4 runtimes,
  279. * otherwise the class verifier complains when it tries to load JDBC4-only
  280. * interface classes that are present in JDBC4 method signatures.
  281. */
  282. protected static ServerPreparedStatement getInstance(MySQLConnection conn,
  283. String sql, String catalog, int resultSetType,
  284. int resultSetConcurrency) throws SQLException {
  285. if (!Util.isJdbc4()) {
  286. return new ServerPreparedStatement(conn, sql, catalog,
  287. resultSetType, resultSetConcurrency);
  288. }
  289. try {
  290. return (ServerPreparedStatement) JDBC_4_SPS_CTOR.newInstance(new Object[] { conn,
  291. sql, catalog, Constants.integerValueOf(resultSetType),
  292. Constants.integerValueOf(resultSetConcurrency) });
  293. } catch (IllegalArgumentException e) {
  294. throw new SQLException(e.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
  295. } catch (InstantiationException e) {
  296. throw new SQLException(e.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
  297. } catch (IllegalAccessException e) {
  298. throw new SQLException(e.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
  299. } catch (InvocationTargetException e) {
  300. Throwable target = e.getTargetException();
  301. if (target instanceof SQLException) {
  302. throw (SQLException)target;
  303. }
  304. throw new SQLException(target.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
  305. }
  306. }
  307. /**
  308. * Creates a new ServerPreparedStatement object.
  309. *
  310. * @param conn
  311. * the connection creating us.
  312. * @param sql
  313. * the SQL containing the statement to prepare.
  314. * @param catalog
  315. * the catalog in use when we were created.
  316. *
  317. * @throws SQLException
  318. * If an error occurs
  319. */
  320. protected ServerPreparedStatement(MySQLConnection conn, String sql, String catalog,
  321. int resultSetType, int resultSetConcurrency)
  322. throws SQLException {
  323. super(conn, catalog);
  324. checkNullOrEmptyQuery(sql);
  325. this.hasOnDuplicateKeyUpdate = containsOnDuplicateKeyInString(sql);
  326. int startOfStatement = findStartOfStatement(sql);
  327. this.firstCharOfStmt = StringUtils.firstAlphaCharUc(sql, startOfStatement);
  328. this.isSelectQuery = 'S' == this.firstCharOfStmt;
  329. if (this.connection.versionMeetsMinimum(5, 0, 0)) {
  330. this.serverNeedsResetBeforeEachExecution =
  331. !this.connection.versionMeetsMinimum(5, 0, 3);
  332. } else {
  333. this.serverNeedsResetBeforeEachExecution =
  334. !this.connection.versionMeetsMinimum(4, 1, 10);
  335. }
  336. this.useAutoSlowLog = this.connection.getAutoSlowLog();
  337. this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
  338. this.hasLimitClause = (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1); //$NON-NLS-1$
  339. String statementComment = this.connection.getStatementComment();
  340. this.originalSql = (statementComment == null) ? sql : "/* "
  341. + statementComment + " */ " + sql;
  342. if (this.connection.versionMeetsMinimum(4, 1, 2)) {
  343. this.stringTypeCode = MysqlDefs.FIELD_TYPE_VAR_STRING;
  344. } else {
  345. this.stringTypeCode = MysqlDefs.FIELD_TYPE_STRING;
  346. }
  347. try {
  348. serverPrepare(sql);
  349. } catch (SQLException sqlEx) {
  350. realClose(false, true);
  351. // don't wrap SQLExceptions
  352. throw sqlEx;
  353. } catch (Exception ex) {
  354. realClose(false, true);
  355. SQLException sqlEx = SQLError.createSQLException(ex.toString(),
  356. SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
  357. sqlEx.initCause(ex);
  358. throw sqlEx;
  359. }
  360. setResultSetType(resultSetType);
  361. setResultSetConcurrency(resultSetConcurrency);
  362. this.parameterTypes = new int[this.parameterCount];
  363. }
  364. /**
  365. * JDBC 2.0 Add a set of parameters to the batch.
  366. *
  367. * @exception SQLException
  368. * if a database-access error occurs.
  369. *
  370. * @see StatementImpl#addBatch
  371. */
  372. public synchronized void addBatch() throws SQLException {
  373. checkClosed();
  374. if (this.batchedArgs == null) {
  375. this.batchedArgs = new ArrayList();
  376. }
  377. this.batchedArgs.add(new BatchedBindValues(this.parameterBindings));
  378. }
  379. protected String asSql(boolean quoteStreamsAndUnknowns) throws SQLException {
  380. if (this.isClosed) {
  381. return "statement has been closed, no further internal information available";
  382. }
  383. PreparedStatement pStmtForSub = null;
  384. try {
  385. pStmtForSub = PreparedStatement.getInstance(this.connection,
  386. this.originalSql, this.currentCatalog);
  387. int numParameters = pStmtForSub.parameterCount;
  388. int ourNumParameters = this.parameterCount;
  389. for (int i = 0; (i < numParameters) && (i < ourNumParameters); i++) {
  390. if (this.parameterBindings[i] != null) {
  391. if (this.parameterBindings[i].isNull) {
  392. pStmtForSub.setNull(i + 1, Types.NULL);
  393. } else {
  394. BindValue bindValue = this.parameterBindings[i];
  395. //
  396. // Handle primitives first
  397. //
  398. switch (bindValue.bufferType) {
  399. case MysqlDefs.FIELD_TYPE_TINY:
  400. pStmtForSub.setByte(i + 1, bindValue.byteBinding);
  401. break;
  402. case MysqlDefs.FIELD_TYPE_SHORT:
  403. pStmtForSub.setShort(i + 1, bindValue.shortBinding);
  404. break;
  405. case MysqlDefs.FIELD_TYPE_LONG:
  406. pStmtForSub.setInt(i + 1, bindValue.intBinding);
  407. break;
  408. case MysqlDefs.FIELD_TYPE_LONGLONG:
  409. pStmtForSub.setLong(i + 1, bindValue.longBinding);
  410. break;
  411. case MysqlDefs.FIELD_TYPE_FLOAT:
  412. pStmtForSub.setFloat(i + 1, bindValue.floatBinding);
  413. break;
  414. case MysqlDefs.FIELD_TYPE_DOUBLE:
  415. pStmtForSub.setDouble(i + 1,
  416. bindValue.doubleBinding);
  417. break;
  418. default:
  419. pStmtForSub.setObject(i + 1,
  420. this.parameterBindings[i].value);
  421. break;
  422. }
  423. }
  424. }
  425. }
  426. return pStmtForSub.asSql(quoteStreamsAndUnknowns);
  427. } finally {
  428. if (pStmtForSub != null) {
  429. try {
  430. pStmtForSub.close();
  431. } catch (SQLException sqlEx) {
  432. ; // ignore
  433. }
  434. }
  435. }
  436. }
  437. /*
  438. * (non-Javadoc)
  439. *
  440. * @see com.mysql.jdbc.Statement#checkClosed()
  441. */
  442. protected void checkClosed() throws SQLException {
  443. if (this.invalid) {
  444. throw this.invalidationException;
  445. }
  446. super.checkClosed();
  447. }
  448. /**
  449. * @see java.sql.PreparedStatement#clearParameters()
  450. */
  451. public void clearParameters() throws SQLException {
  452. checkClosed();
  453. clearParametersInternal(true);
  454. }
  455. private void clearParametersInternal(boolean clearServerParameters)
  456. throws SQLException {
  457. boolean hadLongData = false;
  458. if (this.parameterBindings != null) {
  459. for (int i = 0; i < this.parameterCount; i++) {
  460. if ((this.parameterBindings[i] != null)
  461. && this.parameterBindings[i].isLongData) {
  462. hadLongData = true;
  463. }
  464. this.parameterBindings[i].reset();
  465. }
  466. }
  467. if (clearServerParameters && hadLongData) {
  468. serverResetStatement();
  469. this.detectedLongParameterSwitch = false;
  470. }
  471. }
  472. protected boolean isCached = false;
  473. private boolean useAutoSlowLog;
  474. private Calendar serverTzCalendar;
  475. private Calendar defaultTzCalendar;
  476. protected void setClosed(boolean flag) {
  477. this.isClosed = flag;
  478. }
  479. /**
  480. * @see java.sql.Statement#close()
  481. */
  482. public synchronized void close() throws SQLException {
  483. if (this.isCached && !this.isClosed) {
  484. clearParameters();
  485. this.isClosed = true;
  486. this.connection.recachePreparedStatement(this);
  487. return;
  488. }
  489. realClose(true, true);
  490. }
  491. private void dumpCloseForTestcase() {
  492. StringBuffer buf = new StringBuffer();
  493. this.connection.generateConnectionCommentBlock(buf);
  494. buf.append("DEALLOCATE PREPARE debug_stmt_");
  495. buf.append(this.statementId);
  496. buf.append(";\n");
  497. this.connection.dumpTestcaseQuery(buf.toString());
  498. }
  499. private void dumpExecuteForTestcase() throws SQLException {
  500. StringBuffer buf = new StringBuffer();
  501. for (int i = 0; i < this.parameterCount; i++) {
  502. this.connection.generateConnectionCommentBlock(buf);
  503. buf.append("SET @debug_stmt_param");
  504. buf.append(this.statementId);
  505. buf.append("_");
  506. buf.append(i);
  507. buf.append("=");
  508. if (this.parameterBindings[i].isNull) {
  509. buf.append("NULL");
  510. } else {
  511. buf.append(this.parameterBindings[i].toString(true));
  512. }
  513. buf.append(";\n");
  514. }
  515. this.connection.generateConnectionCommentBlock(buf);
  516. buf.append("EXECUTE debug_stmt_");
  517. buf.append(this.statementId);
  518. if (this.parameterCount > 0) {
  519. buf.append(" USING ");
  520. for (int i = 0; i < this.parameterCount; i++) {
  521. if (i > 0) {
  522. buf.append(", ");
  523. }
  524. buf.append("@debug_stmt_param");
  525. buf.append(this.statementId);
  526. buf.append("_");
  527. buf.append(i);
  528. }
  529. }
  530. buf.append(";\n");
  531. this.connection.dumpTestcaseQuery(buf.toString());
  532. }
  533. private void dumpPrepareForTestcase() throws SQLException {
  534. StringBuffer buf = new StringBuffer(this.originalSql.length() + 64);
  535. this.connection.generateConnectionCommentBlock(buf);
  536. buf.append("PREPARE debug_stmt_");
  537. buf.append(this.statementId);
  538. buf.append(" FROM \"");
  539. buf.append(this.originalSql);
  540. buf.append("\";\n");
  541. this.connection.dumpTestcaseQuery(buf.toString());
  542. }
  543. protected int[] executeBatchSerially(int batchTimeout) throws SQLException {
  544. MySQLConnection locallyScopedConn = this.connection;
  545. if (locallyScopedConn == null) {
  546. checkClosed();
  547. }
  548. if (locallyScopedConn.isReadOnly()) {
  549. throw SQLError.createSQLException(Messages
  550. .getString("ServerPreparedStatement.2") //$NON-NLS-1$
  551. + Messages.getString("ServerPreparedStatement.3"), //$NON-NLS-1$
  552. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
  553. }
  554. checkClosed();
  555. synchronized (locallyScopedConn.getMutex()) {
  556. clearWarnings();
  557. // Store this for later, we're going to 'swap' them out
  558. // as we execute each batched statement...
  559. BindValue[] oldBindValues = this.parameterBindings;
  560. try {
  561. int[] updateCounts = null;
  562. if (this.batchedArgs != null) {
  563. int nbrCommands = this.batchedArgs.size();
  564. updateCounts = new int[nbrCommands];
  565. if (this.retrieveGeneratedKeys) {
  566. this.batchedGeneratedKeys = new ArrayList(nbrCommands);
  567. }
  568. for (int i = 0; i < nbrCommands; i++) {
  569. updateCounts[i] = -3;
  570. }
  571. SQLException sqlEx = null;
  572. int commandIndex = 0;
  573. BindValue[] previousBindValuesForBatch = null;
  574. CancelTask timeoutTask = null;
  575. try {
  576. if (locallyScopedConn.getEnableQueryTimeouts() &&
  577. batchTimeout != 0
  578. && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
  579. timeoutTask = new CancelTask(this);
  580. locallyScopedConn.getCancelTimer().schedule(timeoutTask,
  581. batchTimeout);
  582. }
  583. for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
  584. Object arg = this.batchedArgs.get(commandIndex);
  585. if (arg instanceof String) {
  586. updateCounts[commandIndex] = executeUpdate((String) arg);
  587. } else {
  588. this.parameterBindings = ((BatchedBindValues) arg).batchedParameterValues;
  589. try {
  590. // We need to check types each time, as
  591. // the user might have bound different
  592. // types in each addBatch()
  593. if (previousBindValuesForBatch != null) {
  594. for (int j = 0; j < this.parameterBindings.length; j++) {
  595. if (this.parameterBindings[j].bufferType != previousBindValuesForBatch[j].bufferType) {
  596. this.sendTypesToServer = true;
  597. break;
  598. }
  599. }
  600. }
  601. try {
  602. updateCounts[commandIndex] = executeUpdate(false, true);
  603. } finally {
  604. previousBindValuesForBatch = this.parameterBindings;
  605. }
  606. if (this.retrieveGeneratedKeys) {
  607. java.sql.ResultSet rs = null;
  608. try {
  609. // we don't want to use our version,
  610. // because we've altered the behavior of
  611. // ours to support batch updates
  612. // (catch-22)
  613. // Ideally, what we need here is
  614. // super.super.getGeneratedKeys()
  615. // but that construct doesn't exist in
  616. // Java, so that's why there's
  617. // this kludge.
  618. rs = getGeneratedKeysInternal();
  619. while (rs.next()) {
  620. this.batchedGeneratedKeys
  621. .add(new ByteArrayRow(new byte[][] { rs
  622. .getBytes(1) }, getExceptionInterceptor()));
  623. }
  624. } finally {
  625. if (rs != null) {
  626. rs.close();
  627. }
  628. }
  629. }
  630. } catch (SQLException ex) {
  631. updateCounts[commandIndex] = EXECUTE_FAILED;
  632. if (this.continueBatchOnError &&
  633. !(ex instanceof MySQLTimeoutException) &&
  634. !(ex instanceof MySQLStatementCancelledException)
  635. && !hasDeadlockOrTimeoutRolledBackTx(ex)) {
  636. sqlEx = ex;
  637. } else {
  638. int[] newUpdateCounts = new int[commandIndex];
  639. System.arraycopy(updateCounts, 0,
  640. newUpdateCounts, 0, commandIndex);
  641. throw new java.sql.BatchUpdateException(ex
  642. .getMessage(), ex.getSQLState(), ex
  643. .getErrorCode(), newUpdateCounts);
  644. }
  645. }
  646. }
  647. }
  648. } finally {
  649. if (timeoutTask != null) {
  650. timeoutTask.cancel();
  651. locallyScopedConn.getCancelTimer().purge();
  652. }
  653. resetCancelledState();
  654. }
  655. if (sqlEx != null) {
  656. throw new java.sql.BatchUpdateException(sqlEx
  657. .getMessage(), sqlEx.getSQLState(), sqlEx
  658. .getErrorCode(), updateCounts);
  659. }
  660. }
  661. return (updateCounts != null) ? updateCounts : new int[0];
  662. } finally {
  663. this.parameterBindings = oldBindValues;
  664. this.sendTypesToServer = true;
  665. clearBatch();
  666. }
  667. }
  668. }
  669. /**
  670. * @see com.mysql.jdbc.PreparedStatement#executeInternal(int,
  671. * com.mysql.jdbc.Buffer, boolean, boolean)
  672. */
  673. protected com.mysql.jdbc.ResultSetInternalMethods executeInternal(int maxRowsToRetrieve,
  674. Buffer sendPacket, boolean createStreamingResultSet,
  675. boolean queryIsSelectOnly, Field[] metadataFromCache,
  676. boolean isBatch)
  677. throws SQLException {
  678. this.numberOfExecutions++;
  679. // We defer to server-side execution
  680. try {
  681. return serverExecute(maxRowsToRetrieve, createStreamingResultSet,
  682. metadataFromCache);
  683. } catch (SQLException sqlEx) {
  684. // don't wrap SQLExceptions
  685. if (this.connection.getEnablePacketDebug()) {
  686. this.connection.getIO().dumpPacketRingBuffer();
  687. }
  688. if (this.connection.getDumpQueriesOnException()) {
  689. String extractedSql = toString();
  690. StringBuffer messageBuf = new StringBuffer(extractedSql
  691. .length() + 32);
  692. messageBuf
  693. .append("\n\nQuery being executed when exception was thrown:\n");
  694. messageBuf.append(extractedSql);
  695. messageBuf.append("\n\n");
  696. sqlEx = ConnectionImpl.appendMessageToException(sqlEx, messageBuf
  697. .toString(), getExceptionInterceptor());
  698. }
  699. throw sqlEx;
  700. } catch (Exception ex) {
  701. if (this.connection.getEnablePacketDebug()) {
  702. this.connection.getIO().dumpPacketRingBuffer();
  703. }
  704. SQLException sqlEx = SQLError.createSQLException(ex.toString(),
  705. SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
  706. if (this.connection.getDumpQueriesOnException()) {
  707. String extractedSql = toString();
  708. StringBuffer messageBuf = new StringBuffer(extractedSql
  709. .length() + 32);
  710. messageBuf
  711. .append("\n\nQuery being executed when exception was thrown:\n");
  712. messageBuf.append(extractedSql);
  713. messageBuf.append("\n\n");
  714. sqlEx = ConnectionImpl.appendMessageToException(sqlEx, messageBuf
  715. .toString(), getExceptionInterceptor());
  716. }
  717. sqlEx.initCause(ex);
  718. throw sqlEx;
  719. }
  720. }
  721. /**
  722. * @see com.mysql.jdbc.PreparedStatement#fillSendPacket()
  723. */
  724. protected Buffer fillSendPacket() throws SQLException {
  725. return null; // we don't use this type of packet
  726. }
  727. /**
  728. * @see com.mysql.jdbc.PreparedStatement#fillSendPacket(byte,
  729. * java.io.InputStream, boolean, int)
  730. */
  731. protected Buffer fillSendPacket(byte[][] batchedParameterStrings,
  732. InputStream[] batchedParameterStreams, boolean[] batchedIsStream,
  733. int[] batchedStreamLengths) throws SQLException {
  734. return null; // we don't use this type of packet
  735. }
  736. /**
  737. * Returns the structure representing the value that (can be)/(is)
  738. * bound at the given parameter index.
  739. *
  740. * @param parameterIndex 1-based
  741. * @param forLongData is this for a stream?
  742. * @return
  743. * @throws SQLException
  744. */
  745. protected BindValue getBinding(int parameterIndex, boolean forLongData)
  746. throws SQLException {
  747. checkClosed();
  748. if (this.parameterBindings.length == 0) {
  749. throw SQLError.createSQLException(Messages
  750. .getString("ServerPreparedStatement.8"), //$NON-NLS-1$
  751. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
  752. }
  753. parameterIndex--;
  754. if ((parameterIndex < 0)
  755. || (parameterIndex >= this.parameterBindings.length)) {
  756. throw SQLError.createSQLException(Messages
  757. .getString("ServerPreparedStatement.9") //$NON-NLS-1$
  758. + (parameterIndex + 1)
  759. + Messages.getString("ServerPreparedStatement.10") //$NON-NLS-1$
  760. + this.parameterBindings.length,
  761. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
  762. }
  763. if (this.parameterBindings[parameterIndex] == null) {
  764. this.parameterBindings[parameterIndex] = new BindValue();
  765. } else {
  766. if (this.parameterBindings[parameterIndex].isLongData
  767. && !forLongData) {
  768. this.detectedLongParameterSwitch = true;
  769. }
  770. }
  771. this.parameterBindings[parameterIndex].isSet = true;
  772. this.parameterBindings[parameterIndex].boundBeforeExecutionNum = this.numberOfExecutions;
  773. return this.parameterBindings[parameterIndex];
  774. }
  775. /**
  776. * @see com.mysql.jdbc.PreparedStatement#getBytes(int)
  777. */
  778. byte[] getBytes(int parameterIndex) throws SQLException {
  779. BindValue bindValue = getBinding(parameterIndex, false);
  780. if (bindValue.isNull) {
  781. return null;
  782. } else if (bindValue.isLongData) {
  783. throw SQLError.notImplemented();
  784. } else {
  785. if (this.outByteBuffer == null) {
  786. this.outByteBuffer = new Buffer(this.connection
  787. .getNetBufferLength());
  788. }
  789. this.outByteBuffer.clear();
  790. int originalPosition = this.outByteBuffer.getPosition();
  791. storeBinding(this.outByteBuffer, bindValue, this.connection.getIO());
  792. int newPosition = this.outByteBuffer.getPosition();
  793. int length = newPosition - originalPosition;
  794. byte[] valueAsBytes = new byte[length];
  795. System.arraycopy(this.outByteBuffer.getByteBuffer(),
  796. originalPosition, valueAsBytes, 0, length);
  797. return valueAsBytes;
  798. }
  799. }
  800. /**
  801. * @see java.sql.PreparedStatement#getMetaData()
  802. */
  803. public java.sql.ResultSetMetaData getMetaData() throws SQLException {
  804. checkClosed();
  805. if (this.resultFields == null) {
  806. return null;
  807. }
  808. return new ResultSetMetaData(this.resultFields,
  809. this.connection.getUseOldAliasMetadataBehavior(), getExceptionInterceptor());
  810. }
  811. /**
  812. * @see java.sql.PreparedStatement#getParameterMetaData()
  813. */
  814. public ParameterMetaData getParameterMetaData() throws SQLException {
  815. checkClosed();
  816. if (this.parameterMetaData == null) {
  817. this.parameterMetaData = new MysqlParameterMetadata(
  818. this.parameterFields, this.parameterCount, getExceptionInterceptor());
  819. }
  820. return this.parameterMetaData;
  821. }
  822. /**
  823. * @see com.mysql.jdbc.PreparedStatement#isNull(int)
  824. */
  825. boolean isNull(int paramIndex) {
  826. throw new IllegalArgumentException(Messages
  827. .getString("ServerPreparedStatement.7")); //$NON-NLS-1$
  828. }
  829. /**
  830. * Closes this connection and frees all resources.
  831. *
  832. * @param calledExplicitly
  833. * was this called from close()?
  834. *
  835. * @throws SQLException
  836. * if an error occurs
  837. */
  838. protected void realClose(boolean calledExplicitly,
  839. boolean closeOpenResults) throws SQLException {
  840. if (this.isClosed) {
  841. return;
  842. }
  843. if (this.connection != null) {
  844. if (this.connection.getAutoGenerateTestcaseScript()) {
  845. dumpCloseForTestcase();
  846. }
  847. //
  848. // Don't communicate with the server if we're being
  849. // called from the finalizer...
  850. //
  851. // This will leak server resources, but if we don't do this,
  852. // we'll deadlock (potentially, because there's no guarantee
  853. // when, what order, and what concurrency finalizers will be
  854. // called with). Well-behaved programs won't rely on finalizers
  855. // to clean up their statements.
  856. //
  857. SQLException exceptionDuringClose = null;
  858. if (calledExplicitly && !this.connection.isClosed()) {
  859. synchronized (this.connection.getMutex()) {
  860. try {
  861. MysqlIO mysql = this.connection.getIO();
  862. Buffer packet = mysql.getSharedSendPacket();
  863. packet.writeByte((byte) MysqlDefs.COM_CLOSE_STATEMENT);
  864. packet.writeLong(this.serverStatementId);
  865. mysql.sendCommand(MysqlDefs.COM_CLOSE_STATEMENT, null,
  866. packet, true, null, 0);
  867. } catch (SQLException sqlEx) {
  868. exceptionDuringClose = sqlEx;
  869. }
  870. }
  871. }
  872. super.realClose(calledExplicitly, closeOpenResults);
  873. clearParametersInternal(false);
  874. this.parameterBindings = null;
  875. this.parameterFields = null;
  876. this.resultFields = null;
  877. if (exceptionDuringClose != null) {
  878. throw exceptionDuringClose;
  879. }
  880. }
  881. }
  882. /**
  883. * Used by Connection when auto-reconnecting to retrieve 'lost' prepared
  884. * statements.
  885. *
  886. * @throws SQLException
  887. * if an error occurs.
  888. */
  889. protected void rePrepare() throws SQLException {
  890. this.invalidationException = null;
  891. try {
  892. serverPrepare(this.originalSql);
  893. } catch (SQLException sqlEx) {
  894. // don't wrap SQLExceptions
  895. this.invalidationException = sqlEx;
  896. } catch (Exception ex) {
  897. this.invalidationException = SQLError.createSQLException(ex.toString(),
  898. SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
  899. this.invalidationException.initCause(ex);
  900. }
  901. if (this.invalidationException != null) {
  902. this.invalid = true;
  903. this.parameterBindings = null;
  904. this.parameterFields = null;
  905. this.resultFields = null;
  906. if (this.results != null) {
  907. try {
  908. this.results.close();
  909. } catch (Exception ex) {
  910. ;
  911. }
  912. }
  913. if (this.connection != null) {
  914. if (this.maxRowsChanged) {
  915. this.connection.unsetMaxRows(this);
  916. }
  917. if (!this.connection.getDontTrackOpenResources()) {
  918. this.connection.unregisterStatement(this);
  919. }
  920. }
  921. }
  922. }
  923. /**
  924. * Tells the server to execute this prepared statement with the current
  925. * parameter bindings.
  926. *
  927. * <pre>
  928. *
  929. *
  930. * - Server gets the command 'COM_EXECUTE' to execute the
  931. * previously prepared query. If there is any param markers;
  932. * then client will send the data in the following format:
  933. *
  934. * [COM_EXECUTE:1]
  935. * [STMT_ID:4]
  936. * [NULL_BITS:(param_count+7)/8)]
  937. * [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
  938. * [[length]data]
  939. * [[length]data] .. [[length]data].
  940. *
  941. * (Note: Except for string/binary types; all other types will not be
  942. * supplied with length field)
  943. *
  944. *
  945. * </pre>
  946. *
  947. * @param maxRowsToRetrieve
  948. * DOCUMENT ME!
  949. * @param createStreamingResultSet
  950. * DOCUMENT ME!
  951. *
  952. * @return DOCUMENT ME!
  953. *
  954. * @throws SQLException
  955. */
  956. private com.mysql.jdbc.ResultSetInternalMethods serverExecute(int maxRowsToRetrieve,
  957. boolean createStreamingResultSet,
  958. Field[] metadataFromCache) throws SQLException {
  959. synchronized (this.connection.getMutex()) {
  960. MysqlIO mysql = this.connection.getIO();
  961. if (mysql.shouldIntercept()) {
  962. ResultSetInternalMethods interceptedResults =
  963. mysql.invokeStatementInterceptorsPre(this.originalSql, this, true);
  964. if (interceptedResults != null) {
  965. return interceptedResults;
  966. }
  967. }
  968. if (this.detectedLongParameterSwitch) {
  969. // Check when values were bound
  970. boolean firstFound = false;
  971. long boundTimeToCheck = 0;
  972. for (int i = 0; i < this.parameterCount - 1; i++) {
  973. if (this.parameterBindings[i].isLongData) {
  974. if (firstFound && boundTimeToCheck !=
  975. this.parameterBindings[i].boundBeforeExecutionNum) {
  976. throw SQLError.createSQLException(Messages
  977. .getString("ServerPreparedStatement.11") //$NON-NLS-1$
  978. + Messages.getString("ServerPreparedStatement.12"), //$NON-NLS-1$
  979. SQLError.SQL_STATE_DRIVER_NOT_CAPABLE, getExceptionInterceptor());
  980. } else {
  981. firstFound = true;
  982. boundTimeToCheck = this.parameterBindings[i].boundBeforeExecutionNum;
  983. }
  984. }
  985. }
  986. // Okay, we've got all "newly"-bound streams, so reset
  987. // server-side state to clear out previous bindings
  988. serverResetStatement();
  989. }
  990. // Check bindings
  991. for (int i = 0; i < this.parameterCount; i++) {
  992. if (!this.parameterBindings[i].isSet) {
  993. throw SQLError.createSQLException(Messages
  994. .getString("ServerPreparedStatement.13") + (i + 1) //$NON-NLS-1$
  995. + Messages.getString("ServerPreparedStatement.14"),
  996. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
  997. }
  998. }
  999. //
  1000. // Send all long data
  1001. //
  1002. for (int i = 0; i < this.parameterCount; i++) {
  1003. if (this.parameterBindings[i].isLongData) {
  1004. serverLongData(i, this.parameterBindings[i]);
  1005. }
  1006. }
  1007. if (this.connection.getAutoGenerateTestcaseScript()) {
  1008. dumpExecuteForTestcase();
  1009. }
  1010. //
  1011. // store the parameter values
  1012. //
  1013. Buffer packet = mysql.getSharedSendPacket();
  1014. packet.clear();
  1015. packet.writeByte((byte) MysqlDefs.COM_EXECUTE);
  1016. packet.writeLong(this.serverStatementId);
  1017. boolean usingCursor = false;
  1018. if (this.connection.versionMeetsMinimum(4, 1, 2)) {
  1019. // we only create cursor-backed result sets if
  1020. // a) The query is a SELECT
  1021. // b) The server supports it
  1022. // c) We know it is forward-only (note this doesn't
  1023. // preclude updatable result sets)
  1024. // d) The user has set a fetch size
  1025. if (this.resultFields != null &&
  1026. this.connection.isCursorFetchEnabled()
  1027. && getResultSetType() == ResultSet.TYPE_FORWARD_ONLY
  1028. && getResultSetConcurrency() == ResultSet.CONCUR_READ_ONLY
  1029. && getFetchSize() > 0) {
  1030. packet.writeByte(MysqlDefs.OPEN_CURSOR_FLAG);
  1031. usingCursor = true;
  1032. } else {
  1033. packet.writeByte((byte) 0); // placeholder for flags
  1034. }
  1035. packet.writeLong(1); // placeholder for parameter
  1036. // iterations
  1037. }
  1038. /* Reserve place for null-marker bytes */
  1039. int nullCount = (this.parameterCount + 7) / 8;
  1040. // if (mysql.versionMeetsMinimum(4, 1, 2)) {
  1041. // nullCount = (this.parameterCount + 9) / 8;
  1042. // }
  1043. int nullBitsPosition = packet.getPosition();
  1044. for (int i = 0; i < nullCount; i++) {
  1045. packet.writeByte((byte) 0);
  1046. }
  1047. byte[] nullBitsBuffer = new byte[nullCount];
  1048. /* In case if buffers (type) altered, indicate to server */
  1049. packet.writeByte(this.sendTypesToServer ? (byte) 1 : (byte) 0);
  1050. if (this.sendTypesToServer) {
  1051. /*
  1052. * Store types of parameters in first in first package that is
  1053. * sent to the server.
  1054. */
  1055. for (int i = 0; i < this.parameterCount; i++) {
  1056. packet.writeInt(this.parameterBindings[i].bufferType);
  1057. }
  1058. }
  1059. //
  1060. // store the parameter values
  1061. //
  1062. for (int i = 0; i < this.parameterCount; i++) {
  1063. if (!this.parameterBindings[i].isLongData) {
  1064. if (!this.parameterBindings[i].isNull) {
  1065. storeBinding(packet, this.parameterBindings[i], mysql);
  1066. } else {
  1067. nullBitsBuffer[i / 8] |= (1 << (i & 7));
  1068. }
  1069. }
  1070. }
  1071. //
  1072. // Go back and write the NULL flags
  1073. // to the beginning of the packet
  1074. //
  1075. int endPosition = packet.getPosition();
  1076. packet.setPosition(nullBitsPosition);
  1077. packet.writeBytesNoNull(nullBitsBuffer);
  1078. packet.setPosition(endPosition);
  1079. long begin = 0;
  1080. boolean logSlowQueries = this.connection.getLogSlowQueries();
  1081. boolean gatherPerformanceMetrics = this.connection
  1082. .getGatherPerformanceMetrics();
  1083. if (this.profileSQL || logSlowQueries || gatherPerformanceMetrics) {
  1084. begin = mysql.getCurrentTimeNanosOrMillis();
  1085. }
  1086. resetCancelledState();
  1087. CancelTask timeoutTask = null;
  1088. try {
  1089. if (this.connection.getEnableQueryTimeouts() &&
  1090. this.timeoutInMillis != 0
  1091. && this.connection.versionMeetsMinimum(5, 0, 0)) {
  1092. timeoutTask = new CancelTask(this);
  1093. this.connection.getCancelTimer().schedule(timeoutTask,
  1094. this.timeoutInMillis);
  1095. }
  1096. Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE,
  1097. null, packet, false, null, 0);
  1098. long queryEndTime = 0L;
  1099. if (logSlowQueries || gatherPerformanceMetrics || this.profileSQL) {
  1100. queryEndTime = mysql.getCurrentTimeNanosOrMillis();
  1101. }
  1102. if (timeoutTask != null) {
  1103. timeoutTask.cancel();
  1104. this.connection.getCancelTimer().purge();
  1105. if (timeoutTask.caughtWhileCancelling != null) {
  1106. throw timeoutTask.caughtWhileCancelling;
  1107. }
  1108. timeoutTask = null;
  1109. }
  1110. synchronized (this.cancelTimeoutMutex) {
  1111. if (this.wasCancelled) {
  1112. SQLException cause = null;
  1113. if (this.wasCancelledByTimeout) {
  1114. cause = new MySQLTimeoutException();
  1115. } else {
  1116. cause = new MySQLStatementCancelledException();
  1117. }
  1118. resetCancelledState();
  1119. throw cause;
  1120. }
  1121. }
  1122. boolean queryWasSlow = false;
  1123. if (logSlowQueries || gatherPerformanceMetrics) {
  1124. long elapsedTime = queryEndTime - begin;
  1125. if (logSlowQueries) {
  1126. if (this.useAutoSlowLog) {
  1127. queryWasSlow = elapsedTime > this.connection.getSlowQueryThresholdMillis();
  1128. } else {
  1129. queryWasSlow = this.connection.isAbonormallyLongQuery(elapsedTime);
  1130. this.connection.reportQueryTime(elapsedTime);
  1131. }
  1132. }
  1133. if (queryWasSlow) {
  1134. StringBuffer mesgBuf = new StringBuffer(
  1135. 48 + this.originalSql.length());
  1136. mesgBuf.append(Messages
  1137. .getString("ServerPreparedStatement.15")); //$NON-NLS-1$
  1138. mesgBuf.append(mysql.getSlowQueryThreshold());
  1139. mesgBuf.append(Messages
  1140. .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$
  1141. mesgBuf.append(elapsedTime);
  1142. mesgBuf.append(Messages
  1143. .getString("ServerPreparedStatement.16")); //$NON-NLS-1$
  1144. mesgBuf.append("as prepared: ");
  1145. mesgBuf.append(this.originalSql);
  1146. mesgBuf.append("\n\n with parameters bound:\n\n");
  1147. mesgBuf.append(asSql(true));
  1148. this.eventSink
  1149. .consumeEvent(new ProfilerEvent(
  1150. ProfilerEvent.TYPE_SLOW_QUERY,
  1151. "", this.currentCatalog, this.connection.getId(), //$NON-NLS-1$
  1152. getId(), 0, System.currentTimeMillis(),
  1153. elapsedTime, mysql
  1154. .getQueryTimingUnits(), null,
  1155. new Throwable(), mesgBuf.toString()));
  1156. }
  1157. if (gatherPerformanceMetrics) {
  1158. this.connection.registerQueryExecutionTime(elapsedTime);
  1159. }
  1160. }
  1161. this.connection.incrementNumberOfPreparedExecutes();
  1162. if (this.profileSQL) {
  1163. this.eventSink = ProfilerEventHandlerFactory
  1164. .getInstance(this.connection);
  1165. this.eventSink.consumeEvent(new ProfilerEvent(
  1166. ProfilerEvent.TYPE_EXECUTE,
  1167. "", this.currentCatalog, //$NON-NLS-1$
  1168. this.connectionId, this.statementId, -1, System
  1169. .currentTimeMillis(), (int) (mysql
  1170. .getCurrentTimeNanosOrMillis() - begin),
  1171. mysql.getQueryTimingUnits(), null, new Throwable(),
  1172. truncateQueryToLog(asSql(true))));
  1173. }
  1174. com.mysql.jdbc.ResultSetInternalMethods rs = mysql.readAllResults(this,
  1175. maxRowsToRetrieve, this.resultSetType,
  1176. this.resultSetConcurrency, createStreamingResultSet,
  1177. this.currentCatalog, resultPacket, true, this.fieldCount,
  1178. metadataFromCache);
  1179. if (mysql.shouldIntercept()) {
  1180. ResultSetInternalMethods interceptedResults =
  1181. mysql.invokeStatementInterceptorsPost(this.originalSql, this, rs, true, null);
  1182. if (interceptedResults != null) {
  1183. rs = interceptedResults;
  1184. }
  1185. }
  1186. if (this.profileSQL) {
  1187. long fetchEndTime = mysql.getCurrentTimeNanosOrMillis();
  1188. this.eventSink.consumeEvent(new ProfilerEvent(
  1189. ProfilerEvent.TYPE_FETCH,
  1190. "", this.currentCatalog, this.connection.getId(), //$NON-NLS-1$
  1191. getId(), 0 /* FIXME rs.resultId */, System.currentTimeMillis(),
  1192. (fetchEndTime - queryEndTime), mysql
  1193. .getQueryTimingUnits(), null,
  1194. new Throwable(), null));
  1195. }
  1196. if (queryWasSlow && this.connection.getExplainSlowQueries()) {
  1197. String queryAsString = asSql(true);
  1198. mysql.explainSlowQuery(queryAsString.getBytes(),
  1199. queryAsString);
  1200. }
  1201. if (!createStreamingResultSet &&
  1202. this.serverNeedsResetBeforeEachExecution) {
  1203. serverResetStatement(); // clear any long data...
  1204. }
  1205. this.sendTypesToServer = false;
  1206. this.results = rs;
  1207. if (mysql.hadWarnings()) {
  1208. mysql.scanForAndThrowDataTruncation();
  1209. }
  1210. return rs;
  1211. } catch (SQLException sqlEx) {
  1212. if (mysql.shouldIntercept()) {
  1213. mysql.invokeStatementInterceptorsPost(this.originalSql, this, null, true, sqlEx);
  1214. }
  1215. throw sqlEx;
  1216. } finally {
  1217. if (timeoutTask != null) {
  1218. timeoutTask.cancel();
  1219. this.connection.getCancelTimer().purge();
  1220. }
  1221. }
  1222. }
  1223. }
  1224. /**
  1225. * Sends stream-type data parameters to the server.
  1226. *
  1227. * <pre>
  1228. *
  1229. * Long data handling:
  1230. *
  1231. * - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
  1232. * - The packet recieved will have the format as:
  1233. * [COM_LONG_DATA: 1][STMT_ID:4][parameter_number:2][type:2][data]
  1234. * - Checks if the type is specified by client, and if yes reads the type,
  1235. * and stores the data in that format.
  1236. * - It's up to the client to check for read data ended. The server doesn't
  1237. * care; and also server doesn't notify to the client that it got the
  1238. * data or not; if there is any error; then during execute; the error
  1239. * will be returned
  1240. *
  1241. * </pre>
  1242. *
  1243. * @param parameterIndex
  1244. * DOCUMENT ME!
  1245. * @param longData
  1246. * DOCUMENT ME!
  1247. *
  1248. * @throws SQLException
  1249. * if an error occurs.
  1250. */
  1251. private void serverLongData(int parameterIndex, BindValue longData)
  1252. throws SQLException {
  1253. synchronized (this.connection.getMutex()) {
  1254. MysqlIO mysql = this.connection.getIO();
  1255. Buffer packet = mysql.getSharedSendPacket();
  1256. Object value = longData.value;
  1257. if (value instanceof byte[]) {
  1258. packet.clear();
  1259. packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
  1260. packet.writeLong(this.serverStatementId);
  1261. packet.writeInt((parameterIndex));
  1262. packet.writeBytesNoNull((byte[]) longData.value);
  1263. mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
  1264. null, 0);
  1265. } else if (value instanceof InputStream) {
  1266. storeStream(mysql, parameterIndex, packet, (InputStream) value);
  1267. } else if (value instanceof java.sql.Blob) {
  1268. storeStream(mysql, parameterIndex, packet,
  1269. ((java.sql.Blob) value).getBinaryStream());
  1270. } else if (value instanceof Reader) {
  1271. storeReader(mysql, parameterIndex, packet, (Reader) value);
  1272. } else {
  1273. throw SQLError.createSQLException(Messages
  1274. .getString("ServerPreparedStatement.18") //$NON-NLS-1$
  1275. + value.getClass().getName() + "'", //$NON-NLS-1$
  1276. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
  1277. }
  1278. }
  1279. }
  1280. private void serverPrepare(String sql) throws SQLException {
  1281. synchronized (this.connection.getMutex()) {
  1282. MysqlIO mysql = this.connection.getIO();
  1283. if (this.connection.getAutoGenerateTestcaseScript()) {
  1284. dumpPrepareForTestcase();
  1285. }
  1286. try {
  1287. long begin = 0;
  1288. if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) { //$NON-NLS-1$
  1289. this.isLoadDataQuery = true;
  1290. } else {
  1291. this.isLoadDataQuery = false;
  1292. }
  1293. if (this.connection.getProfileSql()) {
  1294. begin = System.currentTimeMillis();
  1295. }
  1296. String characterEncoding = null;
  1297. String connectionEncoding = this.connection.getEncoding();
  1298. if (!this.isLoadDataQuery && this.connection.getUseUnicode()
  1299. && (connectionEncoding != null)) {
  1300. characterEncoding = connectionEncoding;
  1301. }
  1302. Buffer prepareResultPacket = mysql.sendCommand(
  1303. MysqlDefs.COM_PREPARE, sql, null, false,
  1304. characterEncoding, 0);
  1305. if (this.connection.versionMeetsMinimum(4, 1, 1)) {
  1306. // 4.1.1 and newer use the first byte
  1307. // as an 'ok' or 'error' flag, so move
  1308. // the buffer pointer past it to
  1309. // start reading the statement id.
  1310. prepareResultPacket.setPosition(1);
  1311. } else {
  1312. // 4.1.0 doesn't use the first byte as an
  1313. // 'ok' or 'error' flag
  1314. prepareResultPacket.setPosition(0);
  1315. }
  1316. this.serverStatementId = prepareResultPacket.readLong();
  1317. this.fieldCount = prepareResultPacket.readInt();
  1318. this.parameterCount = prepareResultPacket.readInt();
  1319. this.parameterBindings = new BindValue[this.parameterCount];
  1320. for (int i = 0; i < this.parameterCount; i++) {
  1321. this.parameterBindings[i] = new BindValue();
  1322. }
  1323. this.connection.incrementNumberOfPrepares();
  1324. if (this.profileSQL) {
  1325. this.eventSink.consumeEvent(new ProfilerEvent(
  1326. ProfilerEvent.TYPE_PREPARE,
  1327. "", this.currentCatalog, //$NON-NLS-1$
  1328. this.connectionId, this.statementId, -1,
  1329. System.currentTimeMillis(),
  1330. mysql.getCurrentTimeNanosOrMillis() - begin,
  1331. mysql.getQueryTimingUnits(), null,
  1332. new Throwable(), truncateQueryToLog(sql)));
  1333. }
  1334. if (this.parameterCount > 0) {
  1335. if (this.connection.versionMeetsMinimum(4, 1, 2)
  1336. && !mysql.isVersion(5, 0, 0)) {
  1337. this.parameterFields = new Field[this.parameterCount];
  1338. Buffer metaDataPacket = mysql.readPacket();
  1339. int i = 0;
  1340. while (!metaDataPacket.isLastDataPacket()
  1341. && (i < this.parameterCount)) {
  1342. this.parameterFields[i++] = mysql.unpackField(
  1343. metaDataPacket, false);
  1344. metaDataPacket = mysql.readPacket();
  1345. }
  1346. }
  1347. }
  1348. if (this.fieldCount > 0) {
  1349. this.resultFields = new Field[this.fieldCount];
  1350. Buffer fieldPacket = mysql.readPacket();
  1351. int i = 0;
  1352. // Read in the result set column information
  1353. while (!fieldPacket.isLastDataPacket()
  1354. && (i < this.fieldCount)) {
  1355. this.resultFields[i++] = mysql.unpackField(fieldPacket,
  1356. false);
  1357. fieldPacket = mysql.readPacket();
  1358. }
  1359. }
  1360. } catch (SQLException sqlEx) {
  1361. if (this.connection.getDumpQueriesOnException()) {
  1362. StringBuffer messageBuf = new StringBuffer(this.originalSql
  1363. .length() + 32);
  1364. messageBuf
  1365. .append("\n\nQuery being prepared when exception was thrown:\n\n");
  1366. messageBuf.append(this.originalSql);
  1367. sqlEx = ConnectionImpl.appendMessageToException(sqlEx,
  1368. messageBuf.toString(), getExceptionInterceptor());
  1369. }
  1370. throw sqlEx;
  1371. } finally {
  1372. // Leave the I/O channel in a known state...there might be
  1373. // packets out there
  1374. // that we're not interested in
  1375. this.connection.getIO().clearInputStream();
  1376. }
  1377. }
  1378. }
  1379. private String truncateQueryToLog(String sql) {
  1380. String query = null;
  1381. if (sql.length() > this.connection.getMaxQuerySizeToLog()) {
  1382. StringBuffer queryBuf = new StringBuffer(
  1383. this.connection.getMaxQuerySizeToLog() + 12);
  1384. queryBuf.append(sql.substring(0, this.connection.getMaxQuerySizeToLog()));
  1385. queryBuf.append(Messages.getString("MysqlIO.25"));
  1386. query = queryBuf.toString();
  1387. } else {
  1388. query = sql;
  1389. }
  1390. return query;
  1391. }
  1392. private void serverResetStatement() throws SQLException {
  1393. synchronized (this.connection.getMutex()) {
  1394. MysqlIO mysql = this.connection.getIO();
  1395. Buffer packet = mysql.getSharedSendPacket();
  1396. packet.clear();
  1397. packet.writeByte((byte) MysqlDefs.COM_RESET_STMT);
  1398. packet.writeLong(this.serverStatementId);
  1399. try {
  1400. mysql.sendCommand(MysqlDefs.COM_RESET_STMT, null, packet,
  1401. !this.connection.versionMeetsMinimum(4, 1, 2), null, 0);
  1402. } catch (SQLException sqlEx) {
  1403. throw sqlEx;
  1404. } catch (Exception ex) {
  1405. SQLException sqlEx = SQLError.createSQLException(ex.toString(),
  1406. SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
  1407. sqlEx.initCause(ex);
  1408. throw sqlEx;
  1409. } finally {
  1410. mysql.clearInputStream();
  1411. }
  1412. }
  1413. }
  1414. /**
  1415. * @see java.sql.PreparedStatement#setArray(int, java.sql.Array)
  1416. */
  1417. public void setArray(int i, Array x) throws SQLException {
  1418. throw SQLError.notImplemented();
  1419. }
  1420. /**
  1421. * @see java.sql.PreparedStatement#setAsciiStream(int, java.io.InputStream,
  1422. * int)
  1423. */
  1424. public void setAsciiStream(int parameterIndex, InputStream x, int length)
  1425. throws SQLException {
  1426. checkClosed();
  1427. if (x == null) {
  1428. setNull(parameterIndex, java.sql.Types.BIN

Large files files are truncated, but you can click here to view the full file