Save This Page
Home » MySQL-JDBC-5.1.11 » com.mysql.jdbc » [javadoc | source]
    1   /*
    2    Copyright  2002-2007 MySQL AB, 2008-2009 Sun Microsystems
    3   
    4    This program is free software; you can redistribute it and/or modify
    5    it under the terms of version 2 of the GNU General Public License as
    6    published by the Free Software Foundation.
    7   
    8    There are special exceptions to the terms and conditions of the GPL
    9    as it is applied to this software. View the full text of the
   10    exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
   11    software distribution.
   12   
   13    This program is distributed in the hope that it will be useful,
   14    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16    GNU General Public License for more details.
   17   
   18    You should have received a copy of the GNU General Public License
   19    along with this program; if not, write to the Free Software
   20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21   
   22   
   23   
   24    */
   25   package com.mysql.jdbc;
   26   
   27   import java.io.InputStream;
   28   import java.math.BigInteger;
   29   import java.sql.BatchUpdateException;
   30   import java.sql.ResultSet;
   31   import java.sql.SQLException;
   32   import java.sql.SQLWarning;
   33   import java.sql.Types;
   34   import java.util.ArrayList;
   35   import java.util.Calendar;
   36   import java.util.GregorianCalendar;
   37   import java.util.HashSet;
   38   import java.util.Iterator;
   39   import java.util.List;
   40   import java.util.Set;
   41   import java.util.TimerTask;
   42   
   43   import com.mysql.jdbc.exceptions.DeadlockTimeoutRollbackMarker;
   44   import com.mysql.jdbc.exceptions.MySQLStatementCancelledException;
   45   import com.mysql.jdbc.exceptions.MySQLTimeoutException;
   46   import com.mysql.jdbc.profiler.ProfilerEvent;
   47   import com.mysql.jdbc.profiler.ProfilerEventHandler;
   48   import com.mysql.jdbc.profiler.ProfilerEventHandlerFactory;
   49   
   50   /**
   51    * A Statement object is used for executing a static SQL statement and obtaining
   52    * the results produced by it.
   53    *
   54    * <p>
   55    * Only one ResultSet per Statement can be open at any point in time. Therefore,
   56    * if the reading of one ResultSet is interleaved with the reading of another,
   57    * each must have been generated by different Statements. All statement execute
   58    * methods implicitly close a statement's current ResultSet if an open one
   59    * exists.
   60    * </p>
   61    *
   62    * @author Mark Matthews
   63    * @version $Id: Statement.java 4624 2005-11-28 14:24:29 -0600 (Mon, 28 Nov
   64    *          2005) mmatthews $
   65    *
   66    * @see java.sql.Statement
   67    * @see ResultSetInternalMethods
   68    */
   69   public class StatementImpl implements Statement {
   70           protected static final String PING_MARKER = "/* ping */";
   71   	/**
   72   	 * Thread used to implement query timeouts...Eventually we could be more
   73   	 * efficient and have one thread with timers, but this is a straightforward
   74   	 * and simple way to implement a feature that isn't used all that often.
   75   	 */
   76   	class CancelTask extends TimerTask {
   77   
   78   		long connectionId = 0;
   79   		SQLException caughtWhileCancelling = null;
   80   		StatementImpl toCancel;
   81   		
   82   		CancelTask(StatementImpl cancellee) throws SQLException {
   83   			connectionId = connection.getIO().getThreadId();
   84   			toCancel = cancellee;
   85   		}
   86   
   87   		public void run() {
   88   
   89   			Thread cancelThread = new Thread() {
   90   
   91   				public void run() {
   92   					if (connection.getQueryTimeoutKillsConnection()) {
   93   						try {
   94   							toCancel.wasCancelled = true;
   95   							toCancel.wasCancelledByTimeout = true;
   96   							connection.realClose(false, false, true, 
   97   									new MySQLStatementCancelledException(Messages.getString("Statement.ConnectionKilledDueToTimeout")));
   98   						} catch (NullPointerException npe) {
   99   							// not worth guarding against
  100   						} catch (SQLException sqlEx) {
  101   							caughtWhileCancelling = sqlEx;
  102   						}
  103   					} else {
  104   						Connection cancelConn = null;
  105   						java.sql.Statement cancelStmt = null;
  106   	
  107   						try {
  108   							synchronized (cancelTimeoutMutex) {
  109   								cancelConn = connection.duplicate();
  110   								cancelStmt = cancelConn.createStatement();
  111   								cancelStmt.execute("KILL QUERY " + connectionId);
  112   								toCancel.wasCancelled = true;
  113   								toCancel.wasCancelledByTimeout = true;
  114   							}
  115   						} catch (SQLException sqlEx) {
  116   							caughtWhileCancelling = sqlEx;
  117   						} catch (NullPointerException npe) {
  118   							// Case when connection closed while starting to cancel
  119   							// We can't easily synchronize this, because then one thread
  120   							// can't cancel() a running query
  121   	
  122   							// ignore, we shouldn't re-throw this, because the connection's
  123   							// already closed, so the statement has been timed out.
  124   						} finally {
  125   							if (cancelStmt != null) {
  126   								try {
  127   									cancelStmt.close();
  128   								} catch (SQLException sqlEx) {
  129   									throw new RuntimeException(sqlEx.toString());
  130   								}
  131   							}
  132   	
  133   							if (cancelConn != null) {
  134   								try {
  135   									cancelConn.close();
  136   								} catch (SQLException sqlEx) {
  137   									throw new RuntimeException(sqlEx.toString());
  138   								}
  139   							}
  140   						}
  141   					}
  142   				}
  143   			};
  144   
  145   			cancelThread.start();
  146   		}
  147   	}
  148   
  149   	/** Mutex to prevent race between returning query results and noticing
  150       that we're timed-out or cancelled. */
  151   
  152   	protected Object cancelTimeoutMutex = new Object();
  153   
  154   	/** Used to generate IDs when profiling. */
  155   	protected static int statementCounter = 1;
  156   
  157   	public final static byte USES_VARIABLES_FALSE = 0;
  158   
  159   	public final static byte USES_VARIABLES_TRUE = 1;
  160   
  161   	public final static byte USES_VARIABLES_UNKNOWN = -1;
  162   
  163   	protected boolean wasCancelled = false;
  164   	protected boolean wasCancelledByTimeout = false;
  165   
  166   	/** Holds batched commands */
  167   	protected List batchedArgs;
  168   
  169   	/** The character converter to use (if available) */
  170   	protected SingleByteCharsetConverter charConverter = null;
  171   
  172   	/** The character encoding to use (if available) */
  173   	protected String charEncoding = null;
  174   
  175   	/** The connection that created us */
  176   	protected ConnectionImpl connection = null;
  177   
  178   	protected long connectionId = 0;
  179   
  180   	/** The catalog in use */
  181   	protected String currentCatalog = null;
  182   
  183   	/** Should we process escape codes? */
  184   	protected boolean doEscapeProcessing = true;
  185   
  186   	/** If we're profiling, where should events go to? */
  187   	protected ProfilerEventHandler eventSink = null;
  188   
  189   	/** The number of rows to fetch at a time (currently ignored) */
  190   	private int fetchSize = 0;
  191   
  192   	/** Has this statement been closed? */
  193   	protected boolean isClosed = false;
  194   
  195   	/** The auto_increment value for the last insert */
  196   	protected long lastInsertId = -1;
  197   
  198   	/** The max field size for this statement */
  199   	protected int maxFieldSize = MysqlIO.getMaxBuf();
  200   
  201   	/**
  202   	 * The maximum number of rows to return for this statement (-1 means _all_
  203   	 * rows)
  204   	 */
  205   	protected int maxRows = -1;
  206   
  207   	/** Has someone changed this for this statement? */
  208   	protected boolean maxRowsChanged = false;
  209   
  210   	/** Set of currently-open ResultSets */
  211   	protected Set openResults = new HashSet();
  212   
  213   	/** Are we in pedantic mode? */
  214   	protected boolean pedantic = false;
  215   
  216   	/**
  217   	 * Where this statement was created, only used if profileSql or
  218   	 * useUsageAdvisor set to true.
  219   	 */
  220   	protected Throwable pointOfOrigin;
  221   
  222   	/** Should we profile? */
  223   	protected boolean profileSQL = false;
  224   
  225   	/** The current results */
  226   	protected ResultSetInternalMethods results = null;
  227   
  228   	/** The concurrency for this result set (updatable or not) */
  229   	protected int resultSetConcurrency = 0;
  230   
  231   	/** The type of this result set (scroll sensitive or in-sensitive) */
  232   	protected int resultSetType = 0;
  233   
  234   	/** Used to identify this statement when profiling. */
  235   	protected int statementId;
  236   
  237   	/** The timeout for a query */
  238   	protected int timeoutInMillis = 0;
  239   
  240   	/** The update count for this statement */
  241   	protected long updateCount = -1;
  242   
  243   	/** Should we use the usage advisor? */
  244   	protected boolean useUsageAdvisor = false;
  245   
  246   	/** The warnings chain. */
  247   	protected SQLWarning warningChain = null;
  248   
  249   	/**
  250   	 * Should this statement hold results open over .close() irregardless of
  251   	 * connection's setting?
  252   	 */
  253   	protected boolean holdResultsOpenOverClose = false;
  254   
  255   	protected ArrayList batchedGeneratedKeys = null;
  256   
  257   	protected boolean retrieveGeneratedKeys = false;
  258   
  259   	protected boolean continueBatchOnError = false;
  260   
  261   	protected PingTarget pingTarget = null;
  262   	
  263   	protected boolean useLegacyDatetimeCode;
  264   	
  265   	private ExceptionInterceptor exceptionInterceptor;
  266   	
  267   	/** Whether or not the last query was of the form ON DUPLICATE KEY UPDATE */
  268   	protected boolean lastQueryIsOnDupKeyUpdate = false;
  269   	
  270   	/**
  271   	 * Constructor for a Statement.
  272   	 *
  273   	 * @param c
  274   	 *            the Connection instantation that creates us
  275   	 * @param catalog
  276   	 *            the database name in use when we were created
  277   	 *
  278   	 * @throws SQLException
  279   	 *             if an error occurs.
  280   	 */
  281   	public StatementImpl(ConnectionImpl c, String catalog) throws SQLException {
  282   		if ((c == null) || c.isClosed()) {
  283   			throw SQLError.createSQLException(
  284   					Messages.getString("Statement.0"), //$NON-NLS-1$
  285   					SQLError.SQL_STATE_CONNECTION_NOT_OPEN, null); //$NON-NLS-1$ //$NON-NLS-2$
  286   		}
  287   
  288   		this.connection = c;
  289   		this.connectionId = this.connection.getId();
  290   		this.exceptionInterceptor = c.getExceptionInterceptor();
  291   
  292   		this.currentCatalog = catalog;
  293   		this.pedantic = this.connection.getPedantic();
  294   		this.continueBatchOnError = this.connection.getContinueBatchOnError();
  295   		this.useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode();
  296   		
  297   		if (!this.connection.getDontTrackOpenResources()) {
  298   			this.connection.registerStatement(this);
  299   		}
  300   
  301   		//
  302   		// Adjust, if we know it
  303   		//
  304   
  305   		if (this.connection != null) {
  306   			this.maxFieldSize = this.connection.getMaxAllowedPacket();
  307   
  308   			int defaultFetchSize = this.connection.getDefaultFetchSize();
  309   
  310   			if (defaultFetchSize != 0) {
  311   				setFetchSize(defaultFetchSize);
  312   			}
  313   		}
  314   
  315   		if (this.connection.getUseUnicode()) {
  316   			this.charEncoding = this.connection.getEncoding();
  317   
  318   			this.charConverter = this.connection
  319   					.getCharsetConverter(this.charEncoding);
  320   		}
  321   
  322   		boolean profiling = this.connection.getProfileSql()
  323   				|| this.connection.getUseUsageAdvisor() || this.connection.getLogSlowQueries();
  324   
  325   		if (this.connection.getAutoGenerateTestcaseScript() || profiling) {
  326   			this.statementId = statementCounter++;
  327   		}
  328   
  329   		if (profiling) {
  330   			this.pointOfOrigin = new Throwable();
  331   			this.profileSQL = this.connection.getProfileSql();
  332   			this.useUsageAdvisor = this.connection.getUseUsageAdvisor();
  333   			this.eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
  334   		}
  335   
  336   		int maxRowsConn = this.connection.getMaxRows();
  337   
  338   		if (maxRowsConn != -1) {
  339   			setMaxRows(maxRowsConn);
  340   		}
  341   		
  342   		this.holdResultsOpenOverClose = this.connection.getHoldResultsOpenOverStatementClose();
  343   	}
  344   
  345   	/**
  346   	 * DOCUMENT ME!
  347   	 *
  348   	 * @param sql
  349   	 *            DOCUMENT ME!
  350   	 *
  351   	 * @throws SQLException
  352   	 *             DOCUMENT ME!
  353   	 */
  354   	public synchronized void addBatch(String sql) throws SQLException {
  355   		if (this.batchedArgs == null) {
  356   			this.batchedArgs = new ArrayList();
  357   		}
  358   
  359   		if (sql != null) {
  360   			this.batchedArgs.add(sql);
  361   		}
  362   	}
  363   
  364   	/**
  365   	 * Cancels this Statement object if both the DBMS and driver support
  366   	 * aborting an SQL statement. This method can be used by one thread to
  367   	 * cancel a statement that is being executed by another thread.
  368   	 */
  369   	public void cancel() throws SQLException {
  370   		if (!this.isClosed &&
  371   				this.connection != null &&
  372   				this.connection.versionMeetsMinimum(5, 0, 0)) {
  373   			Connection cancelConn = null;
  374   			java.sql.Statement cancelStmt = null;
  375   
  376   			try {
  377   				cancelConn = this.connection.duplicate();
  378   				cancelStmt = cancelConn.createStatement();
  379   				cancelStmt.execute("KILL QUERY "
  380   						+ this.connection.getIO().getThreadId());
  381   				this.wasCancelled = true;
  382   			} finally {
  383   				if (cancelStmt != null) {
  384   					cancelStmt.close();
  385   				}
  386   
  387   				if (cancelConn != null) {
  388   					cancelConn.close();
  389   				}
  390   			}
  391   
  392   		}
  393   	}
  394   
  395   	// --------------------------JDBC 2.0-----------------------------
  396   
  397   	/**
  398   	 * Checks if closed() has been called, and throws an exception if so
  399   	 *
  400   	 * @throws SQLException
  401   	 *             if this statement has been closed
  402   	 */
  403   	protected void checkClosed() throws SQLException {
  404   		if (this.isClosed) {
  405   			throw SQLError.createSQLException(Messages
  406   					.getString("Statement.49"), //$NON-NLS-1$
  407   					SQLError.SQL_STATE_CONNECTION_NOT_OPEN, getExceptionInterceptor()); //$NON-NLS-1$
  408   		}
  409   	}
  410   
  411   	/**
  412   	 * Checks if the given SQL query with the given first non-ws char is a DML
  413   	 * statement. Throws an exception if it is.
  414   	 *
  415   	 * @param sql
  416   	 *            the SQL to check
  417   	 * @param firstStatementChar
  418   	 *            the UC first non-ws char of the statement
  419   	 *
  420   	 * @throws SQLException
  421   	 *             if the statement contains DML
  422   	 */
  423   	protected void checkForDml(String sql, char firstStatementChar)
  424   			throws SQLException {
  425   		if ((firstStatementChar == 'I') || (firstStatementChar == 'U')
  426   				|| (firstStatementChar == 'D') || (firstStatementChar == 'A')
  427   				|| (firstStatementChar == 'C')) {
  428   			String noCommentSql = StringUtils.stripComments(sql,
  429   					"'\"", "'\"", true, false, true, true);
  430   
  431   			if (StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "INSERT") //$NON-NLS-1$
  432   					|| StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "UPDATE") //$NON-NLS-1$
  433   					|| StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "DELETE") //$NON-NLS-1$
  434   					|| StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "DROP") //$NON-NLS-1$
  435   					|| StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "CREATE") //$NON-NLS-1$
  436   					|| StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "ALTER")) { //$NON-NLS-1$
  437   				throw SQLError.createSQLException(Messages
  438   						.getString("Statement.57"), //$NON-NLS-1$
  439   						SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
  440   			}
  441   		}
  442   	}
  443   
  444   	/**
  445   	 * Method checkNullOrEmptyQuery.
  446   	 *
  447   	 * @param sql
  448   	 *            the SQL to check
  449   	 *
  450   	 * @throws SQLException
  451   	 *             if query is null or empty.
  452   	 */
  453   	protected void checkNullOrEmptyQuery(String sql) throws SQLException {
  454   		if (sql == null) {
  455   			throw SQLError.createSQLException(Messages
  456   					.getString("Statement.59"), //$NON-NLS-1$
  457   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
  458   		}
  459   
  460   		if (sql.length() == 0) {
  461   			throw SQLError.createSQLException(Messages
  462   					.getString("Statement.61"), //$NON-NLS-1$
  463   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
  464   		}
  465   	}
  466   
  467   	/**
  468   	 * JDBC 2.0 Make the set of commands in the current batch empty. This method
  469   	 * is optional.
  470   	 *
  471   	 * @exception SQLException
  472   	 *                if a database-access error occurs, or the driver does not
  473   	 *                support batch statements
  474   	 */
  475   	public synchronized void clearBatch() throws SQLException {
  476   		if (this.batchedArgs != null) {
  477   			this.batchedArgs.clear();
  478   		}
  479   	}
  480   
  481   	/**
  482   	 * After this call, getWarnings returns null until a new warning is reported
  483   	 * for this Statement.
  484   	 *
  485   	 * @exception SQLException
  486   	 *                if a database access error occurs (why?)
  487   	 */
  488   	public void clearWarnings() throws SQLException {
  489   		this.warningChain = null;
  490   	}
  491   
  492   	/**
  493   	 * In many cases, it is desirable to immediately release a Statement's
  494   	 * database and JDBC resources instead of waiting for this to happen when it
  495   	 * is automatically closed. The close method provides this immediate
  496   	 * release.
  497   	 *
  498   	 * <p>
  499   	 * <B>Note:</B> A Statement is automatically closed when it is garbage
  500   	 * collected. When a Statement is closed, its current ResultSet, if one
  501   	 * exists, is also closed.
  502   	 * </p>
  503   	 *
  504   	 * @exception SQLException
  505   	 *                if a database access error occurs
  506   	 */
  507   	public synchronized void close() throws SQLException {
  508   		realClose(true, true);
  509   	}
  510   
  511   	/**
  512   	 * Close any open result sets that have been 'held open'
  513   	 */
  514   	protected synchronized void closeAllOpenResults() {
  515   		if (this.openResults != null) {
  516   			for (Iterator iter = this.openResults.iterator(); iter.hasNext();) {
  517   				ResultSetInternalMethods element = (ResultSetInternalMethods) iter.next();
  518   
  519   				try {
  520   					element.realClose(false);
  521   				} catch (SQLException sqlEx) {
  522   					AssertionFailedException.shouldNotHappen(sqlEx);
  523   				}
  524   			}
  525   
  526   			this.openResults.clear();
  527   		}
  528   	}
  529   
  530   	public synchronized void removeOpenResultSet(ResultSet rs) {
  531   		if (this.openResults != null) {
  532   			this.openResults.remove(rs);
  533   		}
  534   	}
  535   	
  536   	public synchronized int getOpenResultSetCount() {
  537   		if (this.openResults != null) {
  538   			return this.openResults.size();
  539   		}
  540   		
  541   		return 0;
  542   	}
  543   	
  544   	/**
  545   	 * @param sql
  546   	 * @return
  547   	 */
  548   	private ResultSetInternalMethods createResultSetUsingServerFetch(String sql)
  549   			throws SQLException {
  550   		java.sql.PreparedStatement pStmt = this.connection.prepareStatement(
  551   				sql, this.resultSetType, this.resultSetConcurrency);
  552   
  553   		pStmt.setFetchSize(this.fetchSize);
  554   
  555   		if (this.maxRows > -1) {
  556   			pStmt.setMaxRows(this.maxRows);
  557   		}
  558   
  559   		pStmt.execute();
  560   
  561   		//
  562   		// Need to be able to get resultset irrespective if we issued DML or
  563   		// not to make this work.
  564   		//
  565   		ResultSetInternalMethods rs = ((com.mysql.jdbc.StatementImpl) pStmt)
  566   				.getResultSetInternal();
  567   
  568   		rs
  569   				.setStatementUsedForFetchingRows((com.mysql.jdbc.PreparedStatement) pStmt);
  570   
  571   		this.results = rs;
  572   
  573   		return rs;
  574   	}
  575   
  576   	/**
  577   	 * We only stream result sets when they are forward-only, read-only, and the
  578   	 * fetch size has been set to Integer.MIN_VALUE
  579   	 *
  580   	 * @return true if this result set should be streamed row at-a-time, rather
  581   	 *         than read all at once.
  582   	 */
  583   	protected boolean createStreamingResultSet() {
  584   		return ((this.resultSetType == java.sql.ResultSet.TYPE_FORWARD_ONLY)
  585   				&& (this.resultSetConcurrency == java.sql.ResultSet.CONCUR_READ_ONLY) && (this.fetchSize == Integer.MIN_VALUE));
  586   	}
  587   
  588   	private int originalResultSetType = 0;
  589   	private int originalFetchSize = 0;
  590   
  591   	/* (non-Javadoc)
  592   	 * @see com.mysql.jdbc.IStatement#enableStreamingResults()
  593   	 */
  594   	public void enableStreamingResults() throws SQLException {
  595   		this.originalResultSetType = this.resultSetType;
  596   		this.originalFetchSize = this.fetchSize;
  597   
  598   		setFetchSize(Integer.MIN_VALUE);
  599   		setResultSetType(ResultSet.TYPE_FORWARD_ONLY);
  600   	}
  601   
  602   	public void disableStreamingResults() throws SQLException {
  603   		if (this.fetchSize == Integer.MIN_VALUE &&
  604   				this.resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
  605   			setFetchSize(this.originalFetchSize);
  606   			setResultSetType(this.originalResultSetType);
  607   		}
  608   	}
  609   
  610   	/**
  611   	 * Execute a SQL statement that may return multiple results. We don't have
  612   	 * to worry about this since we do not support multiple ResultSets. You can
  613   	 * use getResultSet or getUpdateCount to retrieve the result.
  614   	 *
  615   	 * @param sql
  616   	 *            any SQL statement
  617   	 *
  618   	 * @return true if the next result is a ResulSet, false if it is an update
  619   	 *         count or there are no more results
  620   	 *
  621   	 * @exception SQLException
  622   	 *                if a database access error occurs
  623   	 */
  624   	public boolean execute(String sql) throws SQLException {
  625   		return execute(sql, false);
  626   	}
  627   	
  628   	private boolean execute(String sql, boolean returnGeneratedKeys) throws SQLException {
  629   		checkClosed();
  630   
  631   		ConnectionImpl locallyScopedConn = this.connection;
  632   
  633   		synchronized (locallyScopedConn.getMutex()) {
  634   			this.retrieveGeneratedKeys = returnGeneratedKeys;
  635   			lastQueryIsOnDupKeyUpdate = false;
  636   			if (returnGeneratedKeys)
  637   				lastQueryIsOnDupKeyUpdate = containsOnDuplicateKeyInString(sql);
  638   			
  639   			resetCancelledState();
  640   
  641   			checkNullOrEmptyQuery(sql);
  642   
  643   			checkClosed();
  644   
  645   			char firstNonWsChar = StringUtils.firstAlphaCharUc(sql, findStartOfStatement(sql));
  646   
  647   			boolean isSelect = true;
  648   
  649   			if (firstNonWsChar != 'S') {
  650   				isSelect = false;
  651   
  652   				if (locallyScopedConn.isReadOnly()) {
  653   					throw SQLError.createSQLException(Messages
  654   							.getString("Statement.27") //$NON-NLS-1$
  655   							+ Messages.getString("Statement.28"), //$NON-NLS-1$
  656   							SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
  657   				}
  658   			}
  659   
  660   			boolean doStreaming = createStreamingResultSet();
  661   
  662   			// Adjust net_write_timeout to a higher value if we're
  663   			// streaming result sets. More often than not, someone runs into
  664   			// an issue where they blow net_write_timeout when using this
  665   			// feature, and if they're willing to hold a result set open
  666   			// for 30 seconds or more, one more round-trip isn't going to hurt
  667   			//
  668   			// This is reset by RowDataDynamic.close().
  669   
  670   			if (doStreaming
  671   					&& this.connection.getNetTimeoutForStreamingResults() > 0) {
  672   				executeSimpleNonQuery(locallyScopedConn, "SET net_write_timeout="
  673   						+ this.connection.getNetTimeoutForStreamingResults());
  674   			}
  675   
  676   			if (this.doEscapeProcessing) {
  677   				Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
  678   						locallyScopedConn.serverSupportsConvertFn(), locallyScopedConn);
  679   
  680   				if (escapedSqlResult instanceof String) {
  681   					sql = (String) escapedSqlResult;
  682   				} else {
  683   					sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
  684   				}
  685   			}
  686   
  687   			if (this.results != null) {
  688   				if (!locallyScopedConn.getHoldResultsOpenOverStatementClose()) {
  689   					this.results.realClose(false);
  690   				}
  691   			}
  692   
  693   			if (sql.charAt(0) == '/') {
  694   				if (sql.startsWith(PING_MARKER)) {
  695   					doPingInstead();
  696   				
  697   					return true;
  698   				}
  699   			}
  700   
  701   			CachedResultSetMetaData cachedMetaData = null;
  702   
  703   			ResultSetInternalMethods rs = null;
  704   
  705   			// If there isn't a limit clause in the SQL
  706   			// then limit the number of rows to return in
  707   			// an efficient manner. Only do this if
  708   			// setMaxRows() hasn't been used on any Statements
  709   			// generated from the current Connection (saves
  710   			// a query, and network traffic).
  711   
  712   			this.batchedGeneratedKeys = null;
  713   
  714   			if (useServerFetch()) {
  715   				rs = createResultSetUsingServerFetch(sql);
  716   			} else {
  717   				CancelTask timeoutTask = null;
  718   
  719   				String oldCatalog = null;
  720   
  721   				try {
  722   					if (locallyScopedConn.getEnableQueryTimeouts() &&
  723   							this.timeoutInMillis != 0
  724   							&& locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
  725   						timeoutTask = new CancelTask(this);
  726   						locallyScopedConn.getCancelTimer().schedule(timeoutTask,
  727   								this.timeoutInMillis);
  728   					}
  729   
  730   
  731   
  732   					if (!locallyScopedConn.getCatalog().equals(
  733   							this.currentCatalog)) {
  734   						oldCatalog = locallyScopedConn.getCatalog();
  735   						locallyScopedConn.setCatalog(this.currentCatalog);
  736   					}
  737   
  738   					//
  739   					// Check if we have cached metadata for this query...
  740   					//
  741   
  742   					Field[] cachedFields = null;
  743   
  744   					if (locallyScopedConn.getCacheResultSetMetadata()) {
  745   						cachedMetaData = locallyScopedConn.getCachedMetaData(sql);
  746   
  747   						if (cachedMetaData != null) {
  748   							cachedFields = cachedMetaData.fields;
  749   						}
  750   					}
  751   
  752   					//
  753   					// Only apply max_rows to selects
  754   					//
  755   					if (locallyScopedConn.useMaxRows()) {
  756   						int rowLimit = -1;
  757   
  758   						if (isSelect) {
  759   							if (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1) { //$NON-NLS-1$
  760   								rowLimit = this.maxRows;
  761   							} else {
  762   								if (this.maxRows <= 0) {
  763   									executeSimpleNonQuery(locallyScopedConn,
  764   											"SET OPTION SQL_SELECT_LIMIT=DEFAULT");
  765   								} else {
  766   									executeSimpleNonQuery(locallyScopedConn,
  767   											"SET OPTION SQL_SELECT_LIMIT="
  768   													+ this.maxRows);
  769   								}
  770   							}
  771   						} else {
  772   							executeSimpleNonQuery(locallyScopedConn,
  773   									"SET OPTION SQL_SELECT_LIMIT=DEFAULT");
  774   						}
  775   
  776   						// Finally, execute the query
  777   						rs = locallyScopedConn.execSQL(this, sql, rowLimit, null,
  778   								this.resultSetType, this.resultSetConcurrency,
  779   								doStreaming,
  780   								this.currentCatalog, cachedFields);
  781   					} else {
  782   						rs = locallyScopedConn.execSQL(this, sql, -1, null,
  783   								this.resultSetType, this.resultSetConcurrency,
  784   								doStreaming,
  785   								this.currentCatalog, cachedFields);
  786   					}
  787   
  788   					if (timeoutTask != null) {
  789   						if (timeoutTask.caughtWhileCancelling != null) {
  790   							throw timeoutTask.caughtWhileCancelling;
  791   						}
  792   
  793   						timeoutTask.cancel();
  794   						timeoutTask = null;
  795   					}
  796   
  797   					synchronized (this.cancelTimeoutMutex) {
  798   						if (this.wasCancelled) {
  799   							SQLException cause = null;
  800   							
  801   							if (this.wasCancelledByTimeout) {
  802   								cause = new MySQLTimeoutException();
  803   							} else {
  804   								cause = new MySQLStatementCancelledException();
  805   							}
  806   							
  807   							resetCancelledState();
  808   							
  809   							throw cause;
  810   						}
  811   					}
  812   				} finally {
  813   					if (timeoutTask != null) {
  814   						timeoutTask.cancel();
  815   					}
  816   
  817   					if (oldCatalog != null) {
  818   						locallyScopedConn.setCatalog(oldCatalog);
  819   					}
  820   				}
  821   			}
  822   
  823   			if (rs != null) {
  824   				this.lastInsertId = rs.getUpdateID();
  825   
  826   				this.results = rs;
  827   
  828   				rs.setFirstCharOfQuery(firstNonWsChar);
  829   
  830   				if (rs.reallyResult()) {
  831   					if (cachedMetaData != null) {
  832   						locallyScopedConn.initializeResultsMetadataFromCache(sql, cachedMetaData,
  833   								this.results);
  834   					} else {
  835   						if (this.connection.getCacheResultSetMetadata()) {
  836   							locallyScopedConn.initializeResultsMetadataFromCache(sql,
  837   									null /* will be created */, this.results);
  838   						}
  839   					}
  840   				}
  841   			}
  842   
  843   			return ((rs != null) && rs.reallyResult());
  844   		}
  845   	}
  846   
  847   	protected synchronized void resetCancelledState() {
  848   		if (this.cancelTimeoutMutex == null) {
  849   			return;
  850   		}
  851   		
  852   		synchronized (this.cancelTimeoutMutex) {
  853   			this.wasCancelled = false;
  854   			this.wasCancelledByTimeout = false;
  855   		}
  856   	}
  857   
  858   	/**
  859   	 * @see StatementImpl#execute(String, int)
  860   	 */
  861   	public boolean execute(String sql, int returnGeneratedKeys)
  862   			throws SQLException {
  863   
  864   
  865   		if (returnGeneratedKeys == java.sql.Statement.RETURN_GENERATED_KEYS) {
  866   			checkClosed();
  867   
  868   			ConnectionImpl locallyScopedConn = this.connection;
  869   
  870   			synchronized (locallyScopedConn.getMutex()) {
  871   				// If this is a 'REPLACE' query, we need to be able to parse
  872   				// the 'info' message returned from the server to determine
  873   				// the actual number of keys generated.
  874   				boolean readInfoMsgState = this.connection
  875   						.isReadInfoMsgEnabled();
  876   				locallyScopedConn.setReadInfoMsgEnabled(true);
  877   
  878   				try {
  879   					return execute(sql, true);
  880   				} finally {
  881   					locallyScopedConn.setReadInfoMsgEnabled(readInfoMsgState);
  882   				}
  883   			}
  884   		}
  885   
  886   		return execute(sql);
  887   	}
  888   
  889   	/**
  890   	 * @see StatementImpl#execute(String, int[])
  891   	 */
  892   	public boolean execute(String sql, int[] generatedKeyIndices)
  893   			throws SQLException {
  894   		if ((generatedKeyIndices != null) && (generatedKeyIndices.length > 0)) {
  895   			checkClosed();
  896   
  897   			ConnectionImpl locallyScopedConn = this.connection;
  898   
  899   			synchronized (locallyScopedConn.getMutex()) {
  900   				this.retrieveGeneratedKeys = true;
  901   				
  902   				// If this is a 'REPLACE' query, we need to be able to parse
  903   				// the 'info' message returned from the server to determine
  904   				// the actual number of keys generated.
  905   				boolean readInfoMsgState = locallyScopedConn
  906   						.isReadInfoMsgEnabled();
  907   				locallyScopedConn.setReadInfoMsgEnabled(true);
  908   
  909   				try {
  910   					return execute(sql, true);
  911   				} finally {
  912   					locallyScopedConn.setReadInfoMsgEnabled(readInfoMsgState);
  913   				}
  914   			}
  915   		}
  916   
  917   		return execute(sql);
  918   	}
  919   
  920   	/**
  921   	 * @see StatementImpl#execute(String, String[])
  922   	 */
  923   	public boolean execute(String sql, String[] generatedKeyNames)
  924   			throws SQLException {
  925   		if ((generatedKeyNames != null) && (generatedKeyNames.length > 0)) {
  926   			checkClosed();
  927   
  928   			ConnectionImpl locallyScopedConn = this.connection;
  929   
  930   			synchronized (locallyScopedConn.getMutex()) {
  931   				this.retrieveGeneratedKeys = true;
  932   				// If this is a 'REPLACE' query, we need to be able to parse
  933   				// the 'info' message returned from the server to determine
  934   				// the actual number of keys generated.
  935   				boolean readInfoMsgState = this.connection
  936   						.isReadInfoMsgEnabled();
  937   				locallyScopedConn.setReadInfoMsgEnabled(true);
  938   
  939   				try {
  940   					return execute(sql, true);
  941   				} finally {
  942   					locallyScopedConn.setReadInfoMsgEnabled(readInfoMsgState);
  943   				}
  944   			}
  945   		}
  946   
  947   		return execute(sql);
  948   	}
  949   
  950   	/**
  951   	 * JDBC 2.0 Submit a batch of commands to the database for execution. This
  952   	 * method is optional.
  953   	 *
  954   	 * @return an array of update counts containing one element for each command
  955   	 *         in the batch. The array is ordered according to the order in
  956   	 *         which commands were inserted into the batch
  957   	 *
  958   	 * @exception SQLException
  959   	 *                if a database-access error occurs, or the driver does not
  960   	 *                support batch statements
  961   	 * @throws java.sql.BatchUpdateException
  962   	 *             DOCUMENT ME!
  963   	 */
  964   	public synchronized int[] executeBatch() throws SQLException {
  965   		checkClosed();
  966   
  967   		ConnectionImpl locallyScopedConn = this.connection;
  968   
  969   		if (locallyScopedConn.isReadOnly()) {
  970   			throw SQLError.createSQLException(Messages
  971   					.getString("Statement.34") //$NON-NLS-1$
  972   					+ Messages.getString("Statement.35"), //$NON-NLS-1$
  973   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
  974   		}
  975   
  976   		if (this.results != null) {
  977   			if (!locallyScopedConn.getHoldResultsOpenOverStatementClose()) {
  978   				this.results.realClose(false);
  979   			}
  980   		}
  981   
  982   		synchronized (locallyScopedConn.getMutex()) {
  983   			if (this.batchedArgs == null || this.batchedArgs.size() == 0) {
  984                   return new int[0];
  985               }
  986   			
  987   			// we timeout the entire batch, not individual statements
  988   			int individualStatementTimeout = this.timeoutInMillis;
  989   			this.timeoutInMillis = 0;
  990   			
  991   			CancelTask timeoutTask = null;
  992   			
  993   			try {
  994   				resetCancelledState();
  995   
  996   				this.retrieveGeneratedKeys = true; // The JDBC spec doesn't forbid this, but doesn't provide for it either...we do..
  997   
  998   				int[] updateCounts = null;
  999   
 1000   				
 1001   				if (this.batchedArgs != null) {
 1002   					int nbrCommands = this.batchedArgs.size();
 1003   
 1004   					this.batchedGeneratedKeys = new ArrayList(this.batchedArgs.size());
 1005   
 1006   					boolean multiQueriesEnabled = locallyScopedConn.getAllowMultiQueries();
 1007   
 1008   					if (locallyScopedConn.versionMeetsMinimum(4, 1, 1) &&
 1009   							(multiQueriesEnabled ||
 1010   							(locallyScopedConn.getRewriteBatchedStatements() &&
 1011   									nbrCommands > 4))) {
 1012   						return executeBatchUsingMultiQueries(multiQueriesEnabled, nbrCommands, individualStatementTimeout);
 1013   					}
 1014   
 1015   					if (locallyScopedConn.getEnableQueryTimeouts() &&
 1016   							individualStatementTimeout != 0
 1017   							&& locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
 1018   						timeoutTask = new CancelTask(this);
 1019   						locallyScopedConn.getCancelTimer().schedule(timeoutTask,
 1020   								individualStatementTimeout);
 1021   					}
 1022   					
 1023   					updateCounts = new int[nbrCommands];
 1024   
 1025   					for (int i = 0; i < nbrCommands; i++) {
 1026   						updateCounts[i] = -3;
 1027   					}
 1028   
 1029   					SQLException sqlEx = null;
 1030   
 1031   					int commandIndex = 0;
 1032   
 1033   					for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
 1034   						try {
 1035   							String sql = (String) this.batchedArgs.get(commandIndex);
 1036   							updateCounts[commandIndex] = executeUpdate(sql, true, true);
 1037   							// limit one generated key per OnDuplicateKey statement
 1038   							getBatchedGeneratedKeys(containsOnDuplicateKeyInString(sql) ? 1 : 0);
 1039   						} catch (SQLException ex) {
 1040   							updateCounts[commandIndex] = EXECUTE_FAILED;
 1041   
 1042   							if (this.continueBatchOnError && 
 1043   									!(ex instanceof MySQLTimeoutException) && 
 1044   									!(ex instanceof MySQLStatementCancelledException) &&
 1045                                       !hasDeadlockOrTimeoutRolledBackTx(ex)) {
 1046   								sqlEx = ex;
 1047   							} else {
 1048   								int[] newUpdateCounts = new int[commandIndex];
 1049   								
 1050   								if (hasDeadlockOrTimeoutRolledBackTx(ex)) {
 1051   									for (int i = 0; i < newUpdateCounts.length; i++) {
 1052   										newUpdateCounts[i] = Statement.EXECUTE_FAILED;
 1053   									}
 1054   								} else {
 1055   									System.arraycopy(updateCounts, 0,
 1056   										newUpdateCounts, 0, commandIndex);
 1057   								}
 1058   
 1059   								throw new java.sql.BatchUpdateException(ex
 1060   										.getMessage(), ex.getSQLState(), ex
 1061   										.getErrorCode(), newUpdateCounts);
 1062   							}
 1063   						}
 1064   					}
 1065   
 1066   					if (sqlEx != null) {
 1067   						throw new java.sql.BatchUpdateException(sqlEx
 1068   								.getMessage(), sqlEx.getSQLState(), sqlEx
 1069   								.getErrorCode(), updateCounts);
 1070   					}
 1071   				}
 1072   
 1073   				if (timeoutTask != null) {
 1074   					if (timeoutTask.caughtWhileCancelling != null) {
 1075   						throw timeoutTask.caughtWhileCancelling;
 1076   					}
 1077   
 1078   					timeoutTask.cancel();
 1079   					timeoutTask = null;
 1080   				}
 1081   				
 1082   				return (updateCounts != null) ? updateCounts : new int[0];
 1083   			} finally {
 1084   				
 1085   				if (timeoutTask != null) {
 1086   					timeoutTask.cancel();
 1087   				}
 1088   				
 1089   				resetCancelledState();
 1090   				
 1091   				this.timeoutInMillis = individualStatementTimeout;
 1092   
 1093   				clearBatch();
 1094   			}
 1095   		}
 1096   	}
 1097   
 1098   	protected final boolean hasDeadlockOrTimeoutRolledBackTx(SQLException ex) {
 1099   		int vendorCode = ex.getErrorCode();
 1100   		
 1101   		switch (vendorCode) {
 1102   		case MysqlErrorNumbers.ER_LOCK_DEADLOCK:
 1103   		case MysqlErrorNumbers.ER_LOCK_TABLE_FULL:
 1104   			return true;
 1105   		case MysqlErrorNumbers.ER_LOCK_WAIT_TIMEOUT:
 1106   			try {
 1107   				return !this.connection.versionMeetsMinimum(5, 0, 13);
 1108   			} catch (SQLException sqlEx) {
 1109   				// won't actually be thrown in this case
 1110   				return false;
 1111   			}
 1112   		default:
 1113   			return false;
 1114   		}
 1115   	}
 1116   
 1117   	/**
 1118   	 * Rewrites batch into a single query to send to the server. This method
 1119   	 * will constrain each batch to be shorter than max_allowed_packet on the
 1120   	 * server.
 1121   	 *
 1122   	 * @return update counts in the same manner as executeBatch()
 1123   	 * @throws SQLException
 1124   	 */
 1125   	private int[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled,
 1126   			int nbrCommands, int individualStatementTimeout) throws SQLException {
 1127   
 1128   		ConnectionImpl locallyScopedConn = this.connection;
 1129   
 1130   		if (!multiQueriesEnabled) {
 1131   			locallyScopedConn.getIO().enableMultiQueries();
 1132   		}
 1133   
 1134   		java.sql.Statement batchStmt = null;
 1135   
 1136   		CancelTask timeoutTask = null;
 1137   		
 1138   		try {
 1139   			int[] updateCounts = new int[nbrCommands];
 1140   
 1141   			for (int i = 0; i < nbrCommands; i++) {
 1142   				updateCounts[i] = -3;
 1143   			}
 1144   
 1145   			int commandIndex = 0;
 1146   
 1147   			StringBuffer queryBuf = new StringBuffer();
 1148   
 1149   			batchStmt = locallyScopedConn.createStatement();
 1150   
 1151   			if (locallyScopedConn.getEnableQueryTimeouts() &&
 1152   					individualStatementTimeout != 0
 1153   					&& locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
 1154   				timeoutTask = new CancelTask((StatementImpl)batchStmt);
 1155   				locallyScopedConn.getCancelTimer().schedule(timeoutTask,
 1156   						individualStatementTimeout);
 1157   			}
 1158   			
 1159   			int counter = 0;
 1160   
 1161   			int numberOfBytesPerChar = 1;
 1162   
 1163   			String connectionEncoding = locallyScopedConn.getEncoding();
 1164   
 1165   			if (StringUtils.startsWithIgnoreCase(connectionEncoding, "utf")) {
 1166   				numberOfBytesPerChar = 3;
 1167   			} else if (CharsetMapping.isMultibyteCharset(connectionEncoding)) {
 1168   				numberOfBytesPerChar = 2;
 1169   			}
 1170   
 1171   			int escapeAdjust = 1;
 1172   
 1173   			if (this.doEscapeProcessing) {
 1174   				escapeAdjust = 2; /* We assume packet _could_ grow by this amount, as we're not
 1175   				                     sure how big statement will end up after
 1176   				                     escape processing */
 1177   			}
 1178   
 1179   			SQLException sqlEx = null;
 1180   			
 1181   			int argumentSetsInBatchSoFar = 0;
 1182   			
 1183   			for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
 1184   				String nextQuery = (String) this.batchedArgs.get(commandIndex);
 1185   
 1186   				if (((((queryBuf.length() + nextQuery.length())
 1187   						* numberOfBytesPerChar) + 1 /* for semicolon */
 1188   						+ MysqlIO.HEADER_LENGTH) * escapeAdjust)  + 32 > this.connection
 1189   						.getMaxAllowedPacket()) {
 1190   					try {
 1191   						batchStmt.execute(queryBuf.toString(), Statement.RETURN_GENERATED_KEYS);
 1192   					} catch (SQLException ex) {
 1193   						sqlEx = handleExceptionForBatch(commandIndex,
 1194   								argumentSetsInBatchSoFar, updateCounts, ex);
 1195   					}
 1196   
 1197   					counter = processMultiCountsAndKeys((StatementImpl)batchStmt, counter, 
 1198   							updateCounts);
 1199   
 1200   					queryBuf = new StringBuffer();
 1201   					argumentSetsInBatchSoFar = 0;
 1202   				}
 1203   
 1204   				queryBuf.append(nextQuery);
 1205   				queryBuf.append(";");
 1206   				argumentSetsInBatchSoFar++;
 1207   			}
 1208   
 1209   			if (queryBuf.length() > 0) {
 1210   				try {
 1211   					batchStmt.execute(queryBuf.toString(), Statement.RETURN_GENERATED_KEYS);
 1212   				} catch (SQLException ex) {
 1213   					sqlEx = handleExceptionForBatch(commandIndex - 1,
 1214   							argumentSetsInBatchSoFar, updateCounts, ex);
 1215   				}
 1216   
 1217   				counter = processMultiCountsAndKeys((StatementImpl)batchStmt, counter, 
 1218   						updateCounts);
 1219   			}
 1220   
 1221   			if (timeoutTask != null) {
 1222   				if (timeoutTask.caughtWhileCancelling != null) {
 1223   					throw timeoutTask.caughtWhileCancelling;
 1224   				}
 1225   
 1226   				timeoutTask.cancel();
 1227   				timeoutTask = null;
 1228   			}
 1229   			
 1230   			if (sqlEx != null) {
 1231   				throw new java.sql.BatchUpdateException(sqlEx
 1232   						.getMessage(), sqlEx.getSQLState(), sqlEx
 1233   						.getErrorCode(), updateCounts);
 1234   			}
 1235   			
 1236   			return (updateCounts != null) ? updateCounts : new int[0];
 1237   		} finally {
 1238   			if (timeoutTask != null) {
 1239   				timeoutTask.cancel();
 1240   			}
 1241   			
 1242   			resetCancelledState();
 1243   			
 1244   			try {
 1245   				if (batchStmt != null) {
 1246   					batchStmt.close();
 1247   				}
 1248   			} finally {
 1249   				if (!multiQueriesEnabled) {
 1250   					locallyScopedConn.getIO().disableMultiQueries();
 1251   				}
 1252   			}
 1253   		}
 1254   	}
 1255   	
 1256   	protected int processMultiCountsAndKeys(
 1257   			StatementImpl batchedStatement,
 1258   			int updateCountCounter, int[] updateCounts) throws SQLException {
 1259   		updateCounts[updateCountCounter++] = batchedStatement.getUpdateCount();
 1260   		
 1261   		boolean doGenKeys = this.batchedGeneratedKeys != null;
 1262   
 1263   		byte[][] row = null;
 1264   		
 1265   		if (doGenKeys) {
 1266   			long generatedKey = batchedStatement.getLastInsertID();
 1267   		
 1268   			row = new byte[1][];
 1269   			row[0] = Long.toString(generatedKey).getBytes();
 1270   			this.batchedGeneratedKeys.add(new ByteArrayRow(row, getExceptionInterceptor()));
 1271   		}
 1272   
 1273   		while (batchedStatement.getMoreResults()
 1274   				|| batchedStatement.getUpdateCount() != -1) {
 1275   			updateCounts[updateCountCounter++] = batchedStatement.getUpdateCount();
 1276   			
 1277   			if (doGenKeys) {
 1278   				long generatedKey = batchedStatement.getLastInsertID();
 1279   				
 1280   				row = new byte[1][];
 1281   				row[0] = Long.toString(generatedKey).getBytes();
 1282   				this.batchedGeneratedKeys.add(new ByteArrayRow(row, getExceptionInterceptor()));
 1283   			}
 1284   		}
 1285   		
 1286   		return updateCountCounter;
 1287   	}
 1288   	
 1289   	protected SQLException handleExceptionForBatch(int endOfBatchIndex,
 1290   			int numValuesPerBatch, int[] updateCounts, SQLException ex)
 1291   			throws BatchUpdateException {
 1292   		SQLException sqlEx;
 1293   	
 1294   		for (int j = endOfBatchIndex; j > endOfBatchIndex - numValuesPerBatch; j--) {
 1295   			updateCounts[j] = EXECUTE_FAILED;
 1296   		}
 1297   
 1298   		if (this.continueBatchOnError && 
 1299   				!(ex instanceof MySQLTimeoutException) && 
 1300   				!(ex instanceof MySQLStatementCancelledException) &&
 1301   				!hasDeadlockOrTimeoutRolledBackTx(ex)) {
 1302   			sqlEx = ex;
 1303   		} else {
 1304   			int[] newUpdateCounts = new int[endOfBatchIndex];
 1305   			System.arraycopy(updateCounts, 0,
 1306   					newUpdateCounts, 0, endOfBatchIndex);
 1307   
 1308   			throw new java.sql.BatchUpdateException(ex
 1309   					.getMessage(), ex.getSQLState(), ex
 1310   					.getErrorCode(), newUpdateCounts);
 1311   		}
 1312   		
 1313   		return sqlEx;
 1314   	}
 1315   	
 1316   	/**
 1317   	 * Execute a SQL statement that retruns a single ResultSet
 1318   	 *
 1319   	 * @param sql
 1320   	 *            typically a static SQL SELECT statement
 1321   	 *
 1322   	 * @return a ResulSet that contains the data produced by the query
 1323   	 *
 1324   	 * @exception SQLException
 1325   	 *                if a database access error occurs
 1326   	 */
 1327   	public java.sql.ResultSet executeQuery(String sql)
 1328   			throws SQLException {
 1329   		checkClosed();
 1330   
 1331   		ConnectionImpl locallyScopedConn = this.connection;
 1332   
 1333   		synchronized (locallyScopedConn.getMutex()) {
 1334   			this.retrieveGeneratedKeys = false;
 1335   			
 1336   			resetCancelledState();
 1337   
 1338   			checkNullOrEmptyQuery(sql);
 1339   
 1340   			boolean doStreaming = createStreamingResultSet();
 1341   
 1342   			// Adjust net_write_timeout to a higher value if we're
 1343   			// streaming result sets. More often than not, someone runs into
 1344   			// an issue where they blow net_write_timeout when using this
 1345   			// feature, and if they're willing to hold a result set open
 1346   			// for 30 seconds or more, one more round-trip isn't going to hurt
 1347   			//
 1348   			// This is reset by RowDataDynamic.close().
 1349   
 1350   			if (doStreaming
 1351   					&& this.connection.getNetTimeoutForStreamingResults() > 0) {
 1352   				executeSimpleNonQuery(locallyScopedConn, "SET net_write_timeout="
 1353   						+ this.connection.getNetTimeoutForStreamingResults());
 1354   			}
 1355   
 1356   			if (this.doEscapeProcessing) {
 1357   				Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
 1358   						locallyScopedConn.serverSupportsConvertFn(), this.connection);
 1359   
 1360   				if (escapedSqlResult instanceof String) {
 1361   					sql = (String) escapedSqlResult;
 1362   				} else {
 1363   					sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
 1364   				}
 1365   			}
 1366   
 1367   			char firstStatementChar = StringUtils.firstNonWsCharUc(sql,
 1368   					findStartOfStatement(sql));
 1369   
 1370   			if (sql.charAt(0) == '/') {
 1371   				if (sql.startsWith(PING_MARKER)) {
 1372   					doPingInstead();
 1373   				
 1374   					return this.results;
 1375   				}
 1376   			}
 1377   			
 1378   			checkForDml(sql, firstStatementChar);
 1379   
 1380   			if (this.results != null) {
 1381   				if (!locallyScopedConn.getHoldResultsOpenOverStatementClose()) {
 1382   					this.results.realClose(false);
 1383   				}
 1384   			}
 1385   
 1386   			CachedResultSetMetaData cachedMetaData = null;
 1387   
 1388   			// If there isn't a limit clause in the SQL
 1389   			// then limit the number of rows to return in
 1390   			// an efficient manner. Only do this if
 1391   			// setMaxRows() hasn't been used on any Statements
 1392   			// generated from the current Connection (saves
 1393   			// a query, and network traffic).
 1394   
 1395   			if (useServerFetch()) {
 1396   				this.results = createResultSetUsingServerFetch(sql);
 1397   
 1398   				return this.results;
 1399   			}
 1400   
 1401   			CancelTask timeoutTask = null;
 1402   
 1403   			String oldCatalog = null;
 1404   
 1405   			try {
 1406   				if (locallyScopedConn.getEnableQueryTimeouts() &&
 1407   						this.timeoutInMillis != 0
 1408   						&& locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
 1409   					timeoutTask = new CancelTask(this);
 1410   					locallyScopedConn.getCancelTimer().schedule(timeoutTask,
 1411   							this.timeoutInMillis);
 1412   				}
 1413   
 1414   				if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) {
 1415   					oldCatalog = locallyScopedConn.getCatalog();
 1416   					locallyScopedConn.setCatalog(this.currentCatalog);
 1417   				}
 1418   
 1419   				//
 1420   				// Check if we have cached metadata for this query...
 1421   				//
 1422   
 1423   				Field[] cachedFields = null;
 1424   
 1425   				if (locallyScopedConn.getCacheResultSetMetadata()) {
 1426   					cachedMetaData = locallyScopedConn.getCachedMetaData(sql);
 1427   
 1428   					if (cachedMetaData != null) {
 1429   						cachedFields = cachedMetaData.fields;
 1430   					}
 1431   				}
 1432   
 1433   				if (locallyScopedConn.useMaxRows()) {
 1434   					// We need to execute this all together
 1435   					// So synchronize on the Connection's mutex (because
 1436   					// even queries going through there synchronize
 1437   					// on the connection
 1438   					if (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1) { //$NON-NLS-1$
 1439   						this.results = locallyScopedConn.execSQL(this, sql,
 1440   								this.maxRows, null, this.resultSetType,
 1441   								this.resultSetConcurrency,
 1442   								doStreaming,
 1443   								this.currentCatalog, cachedFields);
 1444   					} else {
 1445   						if (this.maxRows <= 0) {
 1446   							executeSimpleNonQuery(locallyScopedConn,
 1447   									"SET OPTION SQL_SELECT_LIMIT=DEFAULT");
 1448   						} else {
 1449   							executeSimpleNonQuery(locallyScopedConn,
 1450   											"SET OPTION SQL_SELECT_LIMIT=" + this.maxRows);
 1451   						}
 1452   
 1453   						this.results = locallyScopedConn.execSQL(this, sql, -1,
 1454   								null, this.resultSetType,
 1455   								this.resultSetConcurrency,
 1456   								doStreaming,
 1457   								this.currentCatalog, cachedFields);
 1458   
 1459   						if (oldCatalog != null) {
 1460   							locallyScopedConn.setCatalog(oldCatalog);
 1461   						}
 1462   					}
 1463   				} else {
 1464   					this.results = locallyScopedConn.execSQL(this, sql, -1, null,
 1465   							this.resultSetType, this.resultSetConcurrency,
 1466   							doStreaming,
 1467   							this.currentCatalog, cachedFields);
 1468   				}
 1469   
 1470   				if (timeoutTask != null) {
 1471   					if (timeoutTask.caughtWhileCancelling != null) {
 1472   						throw timeoutTask.caughtWhileCancelling;
 1473   					}
 1474   
 1475   					timeoutTask.cancel();
 1476   					timeoutTask = null;
 1477   				}
 1478   
 1479   				synchronized (this.cancelTimeoutMutex) {
 1480   					if (this.wasCancelled) {
 1481   						SQLException cause = null;
 1482   						
 1483   						if (this.wasCancelledByTimeout) {
 1484   							cause = new MySQLTimeoutException();
 1485   						} else {
 1486   							cause = new MySQLStatementCancelledException();
 1487   						}
 1488   						
 1489   						resetCancelledState();
 1490   						
 1491   						throw cause;
 1492   					}
 1493   				}
 1494   			} finally {
 1495   				if (timeoutTask != null) {
 1496   					timeoutTask.cancel();
 1497   				}
 1498   
 1499   				if (oldCatalog != null) {
 1500   					locallyScopedConn.setCatalog(oldCatalog);
 1501   				}
 1502   			}
 1503   
 1504   			this.lastInsertId = this.results.getUpdateID();
 1505   
 1506   			if (cachedMetaData != null) {
 1507   				locallyScopedConn.initializeResultsMetadataFromCache(sql, cachedMetaData,
 1508   						this.results);
 1509   			} else {
 1510   				if (this.connection.getCacheResultSetMetadata()) {
 1511   					locallyScopedConn.initializeResultsMetadataFromCache(sql,
 1512   							null /* will be created */, this.results);
 1513   				}
 1514   			}
 1515   
 1516   			return this.results;
 1517   		}
 1518   	}
 1519   
 1520   	protected void doPingInstead() throws SQLException {
 1521   		if (this.pingTarget != null) {
 1522   			this.pingTarget.doPing();
 1523   		} else {
 1524   			this.connection.ping();
 1525   		}
 1526   
 1527   		ResultSetInternalMethods fakeSelectOneResultSet = generatePingResultSet();
 1528   		this.results = fakeSelectOneResultSet;
 1529   	}
 1530   
 1531   	protected ResultSetInternalMethods generatePingResultSet() throws SQLException {
 1532   		Field[] fields = { new Field(null, "1", Types.BIGINT, 1) };
 1533   		ArrayList rows = new ArrayList();
 1534   		byte[] colVal = new byte[] { (byte) '1' };
 1535   
 1536   		rows.add(new ByteArrayRow(new byte[][] { colVal }, getExceptionInterceptor()));
 1537   
 1538   		return (ResultSetInternalMethods) DatabaseMetaData.buildResultSet(fields, rows,
 1539   				this.connection);
 1540   	}
 1541   	
 1542   	protected void executeSimpleNonQuery(ConnectionImpl c, String nonQuery)
 1543   			throws SQLException {
 1544   		c.execSQL(this, nonQuery,
 1545   				-1, null, ResultSet.TYPE_FORWARD_ONLY,
 1546   				ResultSet.CONCUR_READ_ONLY, false, this.currentCatalog,
 1547   				null, false).close();
 1548   	}
 1549   
 1550   	/**
 1551   	 * Execute a SQL INSERT, UPDATE or DELETE statement. In addition SQL
 1552   	 * statements that return nothing such as SQL DDL statements can be executed
 1553   	 * Any IDs generated for AUTO_INCREMENT fields can be retrieved by casting
 1554   	 * this Statement to org.gjt.mm.mysql.Statement and calling the
 1555   	 * getLastInsertID() method.
 1556   	 *
 1557   	 * @param sql
 1558   	 *            a SQL statement
 1559   	 *
 1560   	 * @return either a row count, or 0 for SQL commands
 1561   	 *
 1562   	 * @exception SQLException
 1563   	 *                if a database access error occurs
 1564   	 */
 1565   	public int executeUpdate(String sql) throws SQLException {
 1566   		return executeUpdate(sql, false, false);
 1567   	}
 1568   
 1569   	protected int executeUpdate(String sql, boolean isBatch, boolean returnGeneratedKeys)
 1570   		throws SQLException {
 1571   		checkClosed();
 1572   
 1573   		ConnectionImpl locallyScopedConn = this.connection;
 1574   
 1575   		char firstStatementChar = StringUtils.firstAlphaCharUc(sql,
 1576   				findStartOfStatement(sql));
 1577   
 1578   		ResultSetInternalMethods rs = null;
 1579   
 1580   		synchronized (locallyScopedConn.getMutex()) {
 1581   			this.retrieveGeneratedKeys = returnGeneratedKeys;
 1582   			
 1583   			resetCancelledState();
 1584   
 1585   			checkNullOrEmptyQuery(sql);
 1586   
 1587   			if (this.doEscapeProcessing) {
 1588   				Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
 1589   						this.connection.serverSupportsConvertFn(), this.connection);
 1590   
 1591   				if (escapedSqlResult instanceof String) {
 1592   					sql = (String) escapedSqlResult;
 1593   				} else {
 1594   					sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
 1595   				}
 1596   			}
 1597   
 1598   			if (locallyScopedConn.isReadOnly()) {
 1599   				throw SQLError.createSQLException(Messages
 1600   						.getString("Statement.42") //$NON-NLS-1$
 1601   						+ Messages.getString("Statement.43"), //$NON-NLS-1$
 1602   						SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
 1603   			}
 1604   
 1605   			if (StringUtils.startsWithIgnoreCaseAndWs(sql, "select")) { //$NON-NLS-1$
 1606   				throw SQLError.createSQLException(Messages
 1607   						.getString("Statement.46"), //$NON-NLS-1$
 1608   				"01S03", getExceptionInterceptor()); //$NON-NLS-1$
 1609   			}
 1610   
 1611   			if (this.results != null) {
 1612   				if (!locallyScopedConn.getHoldResultsOpenOverStatementClose()) {
 1613   					this.results.realClose(false);
 1614   				}
 1615   			}
 1616   
 1617   			// The checking and changing of catalogs
 1618   			// must happen in sequence, so synchronize
 1619   			// on the same mutex that _conn is using
 1620   
 1621   			CancelTask timeoutTask = null;
 1622   
 1623   			String oldCatalog = null;
 1624   
 1625   			try {
 1626   				if (locallyScopedConn.getEnableQueryTimeouts() &&
 1627   						this.timeoutInMillis != 0
 1628   						&& locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
 1629   					timeoutTask = new CancelTask(this);
 1630   					locallyScopedConn.getCancelTimer().schedule(timeoutTask,
 1631   							this.timeoutInMillis);
 1632   				}
 1633   
 1634   				if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) {
 1635   					oldCatalog = locallyScopedConn.getCatalog();
 1636   					locallyScopedConn.setCatalog(this.currentCatalog);
 1637   				}
 1638   
 1639   				//
 1640   				// Only apply max_rows to selects
 1641   				//
 1642   				if (locallyScopedConn.useMaxRows()) {
 1643   					executeSimpleNonQuery(locallyScopedConn,
 1644   							"SET OPTION SQL_SELECT_LIMIT=DEFAULT");
 1645   				}
 1646   
 1647   				rs = locallyScopedConn.execSQL(this, sql, -1, null,
 1648   						java.sql.ResultSet.TYPE_FORWARD_ONLY,
 1649   						java.sql.ResultSet.CONCUR_READ_ONLY, false,
 1650   						this.currentCatalog,
 1651   						null /* force read of field info on DML */,
 1652   						isBatch);
 1653   
 1654   				if (timeoutTask != null) {
 1655   					if (timeoutTask.caughtWhileCancelling != null) {
 1656   						throw timeoutTask.caughtWhileCancelling;
 1657   					}
 1658   
 1659   					timeoutTask.cancel();
 1660   					timeoutTask = null;
 1661   				}
 1662   
 1663   				synchronized (this.cancelTimeoutMutex) {
 1664   					if (this.wasCancelled) {
 1665   						SQLException cause = null;
 1666   						
 1667   						if (this.wasCancelledByTimeout) {
 1668   							cause = new MySQLTimeoutException();
 1669   						} else {
 1670   							cause = new MySQLStatementCancelledException();
 1671   						}
 1672   						
 1673   						resetCancelledState();
 1674   						
 1675   						throw cause;
 1676   					}
 1677   				}
 1678   			} finally {
 1679   				if (timeoutTask != null) {
 1680   					timeoutTask.cancel();
 1681   				}
 1682   
 1683   				if (oldCatalog != null) {
 1684   					locallyScopedConn.setCatalog(oldCatalog);
 1685   				}
 1686   			}
 1687   		}
 1688   
 1689   		this.results = rs;
 1690   
 1691   		rs.setFirstCharOfQuery(firstStatementChar);
 1692   
 1693   		this.updateCount = rs.getUpdateCount();
 1694   
 1695   		int truncatedUpdateCount = 0;
 1696   
 1697   		if (this.updateCount > Integer.MAX_VALUE) {
 1698   			truncatedUpdateCount = Integer.MAX_VALUE;
 1699   		} else {
 1700   			truncatedUpdateCount = (int) this.updateCount;
 1701   		}
 1702   
 1703   		this.lastInsertId = rs.getUpdateID();
 1704   
 1705   		return truncatedUpdateCount;
 1706   	}
 1707   
 1708   
 1709   	/**
 1710   	 * @see StatementImpl#executeUpdate(String, int)
 1711   	 */
 1712   	public int executeUpdate(String sql, int returnGeneratedKeys)
 1713   			throws SQLException {
 1714   		if (returnGeneratedKeys == java.sql.Statement.RETURN_GENERATED_KEYS) {
 1715   			checkClosed();
 1716   
 1717   			ConnectionImpl locallyScopedConn = this.connection;
 1718   
 1719   			synchronized (locallyScopedConn.getMutex()) {
 1720   				// If this is a 'REPLACE' query, we need to be able to parse
 1721   				// the 'info' message returned from the server to determine
 1722   				// the actual number of keys generated.
 1723   				boolean readInfoMsgState = locallyScopedConn
 1724   						.isReadInfoMsgEnabled();
 1725   				locallyScopedConn.setReadInfoMsgEnabled(true);
 1726   
 1727   				try {
 1728   					return executeUpdate(sql, false, true);
 1729   				} finally {
 1730   					locallyScopedConn.setReadInfoMsgEnabled(readInfoMsgState);
 1731   				}
 1732   			}
 1733   		}
 1734   
 1735   		return executeUpdate(sql);
 1736   	}
 1737   
 1738   	/**
 1739   	 * @see StatementImpl#executeUpdate(String, int[])
 1740   	 */
 1741   	public int executeUpdate(String sql, int[] generatedKeyIndices)
 1742   			throws SQLException {
 1743   		if ((generatedKeyIndices != null) && (generatedKeyIndices.length > 0)) {
 1744   			checkClosed();
 1745   
 1746   			ConnectionImpl locallyScopedConn = this.connection;
 1747   
 1748   			synchronized (locallyScopedConn.getMutex()) {
 1749   				// If this is a 'REPLACE' query, we need to be able to parse
 1750   				// the 'info' message returned from the server to determine
 1751   				// the actual number of keys generated.
 1752   				boolean readInfoMsgState = locallyScopedConn
 1753   						.isReadInfoMsgEnabled();
 1754   				locallyScopedConn.setReadInfoMsgEnabled(true);
 1755   
 1756   				try {
 1757   					return executeUpdate(sql, false, true);
 1758   				} finally {
 1759   					locallyScopedConn.setReadInfoMsgEnabled(readInfoMsgState);
 1760   				}
 1761   			}
 1762   		}
 1763   
 1764   		return executeUpdate(sql);
 1765   	}
 1766   
 1767   	/**
 1768   	 * @see StatementImpl#executeUpdate(String, String[])
 1769   	 */
 1770   	public int executeUpdate(String sql, String[] generatedKeyNames)
 1771   			throws SQLException {
 1772   		if ((generatedKeyNames != null) && (generatedKeyNames.length > 0)) {
 1773   			checkClosed();
 1774   
 1775   			ConnectionImpl locallyScopedConn = this.connection;
 1776   
 1777   			synchronized (locallyScopedConn.getMutex()) {
 1778   				// If this is a 'REPLACE' query, we need to be able to parse
 1779   				// the 'info' message returned from the server to determine
 1780   				// the actual number of keys generated.
 1781   				boolean readInfoMsgState = this.connection
 1782   						.isReadInfoMsgEnabled();
 1783   				locallyScopedConn.setReadInfoMsgEnabled(true);
 1784   
 1785   				try {
 1786   					return executeUpdate(sql, false, true);
 1787   				} finally {
 1788   					locallyScopedConn.setReadInfoMsgEnabled(readInfoMsgState);
 1789   				}
 1790   			}
 1791   		}
 1792   
 1793   		return executeUpdate(sql);
 1794   	}
 1795   
 1796   	/**
 1797   	 * Optimization to only use one calendar per-session, or calculate it for
 1798   	 * each call, depending on user configuration
 1799   	 */
 1800   	protected Calendar getCalendarInstanceForSessionOrNew() {
 1801   		if (this.connection != null) {
 1802   			return this.connection.getCalendarInstanceForSessionOrNew();
 1803   		} else {
 1804   			// punt, no connection around
 1805   			return new GregorianCalendar();
 1806   		}
 1807   	}
 1808   
 1809   	/**
 1810   	 * JDBC 2.0 Return the Connection that produced the Statement.
 1811   	 *
 1812   	 * @return the Connection that produced the Statement
 1813   	 *
 1814   	 * @throws SQLException
 1815   	 *             if an error occurs
 1816   	 */
 1817   	public java.sql.Connection getConnection() throws SQLException {
 1818   		return this.connection;
 1819   	}
 1820   
 1821   	/**
 1822   	 * JDBC 2.0 Determine the fetch direction.
 1823   	 *
 1824   	 * @return the default fetch direction
 1825   	 *
 1826   	 * @exception SQLException
 1827   	 *                if a database-access error occurs
 1828   	 */
 1829   	public int getFetchDirection() throws SQLException {
 1830   		return java.sql.ResultSet.FETCH_FORWARD;
 1831   	}
 1832   
 1833   	/**
 1834   	 * JDBC 2.0 Determine the default fetch size.
 1835   	 *
 1836   	 * @return the number of rows to fetch at a time
 1837   	 *
 1838   	 * @throws SQLException
 1839   	 *             if an error occurs
 1840   	 */
 1841   	public int getFetchSize() throws SQLException {
 1842   		return this.fetchSize;
 1843   	}
 1844   
 1845   	/**
 1846   	 * DOCUMENT ME!
 1847   	 *
 1848   	 * @return DOCUMENT ME!
 1849   	 *
 1850   	 * @throws SQLException
 1851   	 *             DOCUMENT ME!
 1852   	 */
 1853   	public synchronized java.sql.ResultSet getGeneratedKeys()
 1854   			throws SQLException {
 1855   		if (!this.retrieveGeneratedKeys) {
 1856   			throw SQLError.createSQLException(Messages.getString("Statement.GeneratedKeysNotRequested"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
 1857   		}
 1858   		
 1859   		if (this.batchedGeneratedKeys == null) {
 1860   			if (lastQueryIsOnDupKeyUpdate)
 1861   				return getGeneratedKeysInternal(1);
 1862   			else
 1863   				return getGeneratedKeysInternal();
 1864   		}
 1865   
 1866   		Field[] fields = new Field[1];
 1867   		fields[0] = new Field("", "GENERATED_KEY", Types.BIGINT, 17); //$NON-NLS-1$ //$NON-NLS-2$
 1868   		fields[0].setConnection(this.connection);
 1869   
 1870   		return com.mysql.jdbc.ResultSetImpl.getInstance(this.currentCatalog, fields,
 1871   				new RowDataStatic(this.batchedGeneratedKeys), this.connection,
 1872   				this, false);
 1873   	}
 1874   
 1875   	/*
 1876   	 * Needed because there's no concept of super.super to get to this
 1877   	 * implementation from ServerPreparedStatement when dealing with batched
 1878   	 * updates.
 1879   	 */
 1880   	protected java.sql.ResultSet getGeneratedKeysInternal()
 1881   			throws SQLException {
 1882   		int numKeys = getUpdateCount();
 1883   		return getGeneratedKeysInternal(numKeys);
 1884   	}
 1885   
 1886   	protected synchronized java.sql.ResultSet getGeneratedKeysInternal(int numKeys)
 1887   			throws SQLException {
 1888   		Field[] fields = new Field[1];
 1889   		fields[0] = new Field("", "GENERATED_KEY", Types.BIGINT, 17); //$NON-NLS-1$ //$NON-NLS-2$
 1890   		fields[0].setConnection(this.connection);
 1891   		fields[0].setUseOldNameMetadata(true);
 1892   
 1893   		ArrayList rowSet = new ArrayList();
 1894   
 1895   		long beginAt = getLastInsertID();
 1896   		
 1897   		if (beginAt < 0) { // looking at an UNSIGNED BIGINT that has overflowed
 1898   			fields[0].setUnsigned();
 1899   		}
 1900   
 1901   		if (this.results != null) {
 1902   			String serverInfo = this.results.getServerInfo();
 1903   
 1904   			//
 1905   			// Only parse server info messages for 'REPLACE'
 1906   			// queries
 1907   			//
 1908   			if ((numKeys > 0) && (this.results.getFirstCharOfQuery() == 'R')
 1909   					&& (serverInfo != null) && (serverInfo.length() > 0)) {
 1910   				numKeys = getRecordCountFromInfo(serverInfo);
 1911   			}
 1912   
 1913   			if ((beginAt != 0 /* BIGINT UNSIGNED can wrap the protocol representation */) && (numKeys > 0)) {
 1914   				for (int i = 0; i < numKeys; i++) {
 1915   					byte[][] row = new byte[1][];
 1916   					if (beginAt > 0) {
 1917   						row[0] = Long.toString(beginAt).getBytes();
 1918   					} else {
 1919   						byte[] asBytes = new byte[8];
 1920   						asBytes[7] = (byte) (beginAt & 0xff);
 1921   						asBytes[6] = (byte) (beginAt >>> 8);
 1922   						asBytes[5] = (byte) (beginAt >>> 16);
 1923   						asBytes[4] = (byte) (beginAt >>> 24);
 1924   						asBytes[3] = (byte) (beginAt >>> 32);
 1925   						asBytes[2] = (byte) (beginAt >>> 40);
 1926   						asBytes[1] = (byte) (beginAt >>> 48);
 1927   						asBytes[0] = (byte) (beginAt >>> 56);
 1928   						
 1929   						BigInteger val = new BigInteger(1, asBytes);
 1930   
 1931   						row[0] = val.toString().getBytes();
 1932   					}
 1933   					rowSet.add(new ByteArrayRow(row, getExceptionInterceptor()));
 1934   					beginAt  += this.connection.getAutoIncrementIncrement();
 1935   				}
 1936   			}
 1937   		}
 1938   
 1939   		com.mysql.jdbc.ResultSetImpl gkRs = com.mysql.jdbc.ResultSetImpl.getInstance(this.currentCatalog, fields,
 1940   				new RowDataStatic(rowSet), this.connection, this, false);
 1941   		
 1942   		this.openResults.add(gkRs);
 1943   		
 1944   		return gkRs;
 1945   	}
 1946   
 1947   	/**
 1948   	 * Returns the id used when profiling
 1949   	 *
 1950   	 * @return the id used when profiling.
 1951   	 */
 1952   	protected int getId() {
 1953   		return this.statementId;
 1954   	}
 1955   
 1956   	/**
 1957   	 * getLastInsertID returns the value of the auto_incremented key after an
 1958   	 * executeQuery() or excute() call.
 1959   	 *
 1960   	 * <p>
 1961   	 * This gets around the un-threadsafe behavior of "select LAST_INSERT_ID()"
 1962   	 * which is tied to the Connection that created this Statement, and
 1963   	 * therefore could have had many INSERTS performed before one gets a chance
 1964   	 * to call "select LAST_INSERT_ID()".
 1965   	 * </p>
 1966   	 *
 1967   	 * @return the last update ID.
 1968   	 */
 1969   	public long getLastInsertID() {
 1970   		return this.lastInsertId;
 1971   	}
 1972   
 1973   	/**
 1974   	 * getLongUpdateCount returns the current result as an update count, if the
 1975   	 * result is a ResultSet or there are no more results, -1 is returned. It
 1976   	 * should only be called once per result.
 1977   	 *
 1978   	 * <p>
 1979   	 * This method returns longs as MySQL server versions newer than 3.22.4
 1980   	 * return 64-bit values for update counts
 1981   	 * </p>
 1982   	 *
 1983   	 * @return the current update count.
 1984   	 */
 1985   	public long getLongUpdateCount() {
 1986   		if (this.results == null) {
 1987   			return -1;
 1988   		}
 1989   
 1990   		if (this.results.reallyResult()) {
 1991   			return -1;
 1992   		}
 1993   
 1994   		return this.updateCount;
 1995   	}
 1996   
 1997   	/**
 1998   	 * The maxFieldSize limit (in bytes) is the maximum amount of data returned
 1999   	 * for any column value; it only applies to BINARY, VARBINARY,
 2000   	 * LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR columns. If the limit is
 2001   	 * exceeded, the excess data is silently discarded.
 2002   	 *
 2003   	 * @return the current max column size limit; zero means unlimited
 2004   	 *
 2005   	 * @exception SQLException
 2006   	 *                if a database access error occurs
 2007   	 */
 2008   	public int getMaxFieldSize() throws SQLException {
 2009   		return this.maxFieldSize;
 2010   	}
 2011   
 2012   	/**
 2013   	 * The maxRows limit is set to limit the number of rows that any ResultSet
 2014   	 * can contain. If the limit is exceeded, the excess rows are silently
 2015   	 * dropped.
 2016   	 *
 2017   	 * @return the current maximum row limit; zero means unlimited
 2018   	 *
 2019   	 * @exception SQLException
 2020   	 *                if a database access error occurs
 2021   	 */
 2022   	public int getMaxRows() throws SQLException {
 2023   		if (this.maxRows <= 0) {
 2024   			return 0;
 2025   		}
 2026   
 2027   		return this.maxRows;
 2028   	}
 2029   
 2030   	/**
 2031   	 * getMoreResults moves to a Statement's next result. If it returns true,
 2032   	 * this result is a ResulSet.
 2033   	 *
 2034   	 * @return true if the next ResultSet is valid
 2035   	 *
 2036   	 * @exception SQLException
 2037   	 *                if a database access error occurs
 2038   	 */
 2039   	public boolean getMoreResults() throws SQLException {
 2040   		return getMoreResults(CLOSE_CURRENT_RESULT);
 2041   	}
 2042   
 2043   	/**
 2044   	 * @see StatementImpl#getMoreResults(int)
 2045   	 */
 2046   	public synchronized boolean getMoreResults(int current) throws SQLException {
 2047   
 2048   		if (this.results == null) {
 2049   			return false;
 2050   		}
 2051   
 2052   		boolean streamingMode = createStreamingResultSet();
 2053   		
 2054   		if (streamingMode) {
 2055   			if (this.results.reallyResult()) {
 2056   				while (this.results.next()); // need to drain remaining rows to get to server status 
 2057   										 // which tells us whether more results actually exist or not
 2058   			}
 2059   		}
 2060   		
 2061   		ResultSetInternalMethods nextResultSet = this.results.getNextResultSet();
 2062   
 2063   		switch (current) {
 2064   		case java.sql.Statement.CLOSE_CURRENT_RESULT:
 2065   
 2066   			if (this.results != null) {
 2067   				if (!streamingMode) { 
 2068   					this.results.close();
 2069   				}
 2070   				
 2071   				this.results.clearNextResult();
 2072   			}
 2073   
 2074   			break;
 2075   
 2076   		case java.sql.Statement.CLOSE_ALL_RESULTS:
 2077   
 2078   			if (this.results != null) {
 2079   				if (!streamingMode) { 
 2080   					this.results.close();
 2081   				}
 2082   				
 2083   				this.results.clearNextResult();
 2084   			}
 2085   
 2086   			closeAllOpenResults();
 2087   
 2088   			break;
 2089   
 2090   		case java.sql.Statement.KEEP_CURRENT_RESULT:
 2091   			if (!this.connection.getDontTrackOpenResources()) {
 2092   				this.openResults.add(this.results);
 2093   			}
 2094   
 2095   			this.results.clearNextResult(); // nobody besides us should
 2096   			// ever need this value...
 2097   			break;
 2098   
 2099   		default:
 2100   			throw SQLError.createSQLException(Messages
 2101   					.getString("Statement.19"), //$NON-NLS-1$
 2102   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
 2103   		}
 2104   
 2105   		this.results = nextResultSet;
 2106   
 2107   		if (this.results == null) {
 2108   			this.updateCount = -1;
 2109   			this.lastInsertId = -1;
 2110   		} else if (this.results.reallyResult()) {
 2111   			this.updateCount = -1;
 2112   			this.lastInsertId = -1;
 2113   		} else {
 2114   			this.updateCount = this.results.getUpdateCount();
 2115   			this.lastInsertId = this.results.getUpdateID();
 2116   		}
 2117   
 2118   		return ((this.results != null) && this.results.reallyResult()) ? true
 2119   				: false;
 2120   	}
 2121   
 2122   	/**
 2123   	 * The queryTimeout limit is the number of seconds the driver will wait for
 2124   	 * a Statement to execute. If the limit is exceeded, a SQLException is
 2125   	 * thrown.
 2126   	 *
 2127   	 * @return the current query timeout limit in seconds; 0 = unlimited
 2128   	 *
 2129   	 * @exception SQLException
 2130   	 *                if a database access error occurs
 2131   	 */
 2132   	public int getQueryTimeout() throws SQLException {
 2133   		return this.timeoutInMillis / 1000;
 2134   	}
 2135   
 2136   	/**
 2137   	 * Parses actual record count from 'info' message
 2138   	 *
 2139   	 * @param serverInfo
 2140   	 *            DOCUMENT ME!
 2141   	 *
 2142   	 * @return DOCUMENT ME!
 2143   	 */
 2144   	private int getRecordCountFromInfo(String serverInfo) {
 2145   		StringBuffer recordsBuf = new StringBuffer();
 2146   		int recordsCount = 0;
 2147   		int duplicatesCount = 0;
 2148   
 2149   		char c = (char) 0;
 2150   
 2151   		int length = serverInfo.length();
 2152   		int i = 0;
 2153   
 2154   		for (; i < length; i++) {
 2155   			c = serverInfo.charAt(i);
 2156   
 2157   			if (Character.isDigit(c)) {
 2158   				break;
 2159   			}
 2160   		}
 2161   
 2162   		recordsBuf.append(c);
 2163   		i++;
 2164   
 2165   		for (; i < length; i++) {
 2166   			c = serverInfo.charAt(i);
 2167   
 2168   			if (!Character.isDigit(c)) {
 2169   				break;
 2170   			}
 2171   
 2172   			recordsBuf.append(c);
 2173   		}
 2174   
 2175   		recordsCount = Integer.parseInt(recordsBuf.toString());
 2176   
 2177   		StringBuffer duplicatesBuf = new StringBuffer();
 2178   
 2179   		for (; i < length; i++) {
 2180   			c = serverInfo.charAt(i);
 2181   
 2182   			if (Character.isDigit(c)) {
 2183   				break;
 2184   			}
 2185   		}
 2186   
 2187   		duplicatesBuf.append(c);
 2188   		i++;
 2189   
 2190   		for (; i < length; i++) {
 2191   			c = serverInfo.charAt(i);
 2192   
 2193   			if (!Character.isDigit(c)) {
 2194   				break;
 2195   			}
 2196   
 2197   			duplicatesBuf.append(c);
 2198   		}
 2199   
 2200   		duplicatesCount = Integer.parseInt(duplicatesBuf.toString());
 2201   
 2202   		return recordsCount - duplicatesCount;
 2203   	}
 2204   
 2205   	/**
 2206   	 * getResultSet returns the current result as a ResultSet. It should only be
 2207   	 * called once per result.
 2208   	 *
 2209   	 * @return the current result set; null if there are no more
 2210   	 *
 2211   	 * @exception SQLException
 2212   	 *                if a database access error occurs (why?)
 2213   	 */
 2214   	public java.sql.ResultSet getResultSet() throws SQLException {
 2215   		return ((this.results != null) && this.results.reallyResult()) ? (java.sql.ResultSet) this.results
 2216   				: null;
 2217   	}
 2218   
 2219   	/**
 2220   	 * JDBC 2.0 Determine the result set concurrency.
 2221   	 *
 2222   	 * @return CONCUR_UPDATABLE or CONCUR_READONLY
 2223   	 *
 2224   	 * @throws SQLException
 2225   	 *             if an error occurs
 2226   	 */
 2227   	public int getResultSetConcurrency() throws SQLException {
 2228   		return this.resultSetConcurrency;
 2229   	}
 2230   
 2231   	/**
 2232   	 * @see StatementImpl#getResultSetHoldability()
 2233   	 */
 2234   	public int getResultSetHoldability() throws SQLException {
 2235   		return java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
 2236   	}
 2237   
 2238   	protected ResultSetInternalMethods getResultSetInternal() {
 2239   		return this.results;
 2240   	}
 2241   
 2242   	/**
 2243   	 * JDBC 2.0 Determine the result set type.
 2244   	 *
 2245   	 * @return the ResultSet type (SCROLL_SENSITIVE or SCROLL_INSENSITIVE)
 2246   	 *
 2247   	 * @throws SQLException
 2248   	 *             if an error occurs.
 2249   	 */
 2250   	public int getResultSetType() throws SQLException {
 2251   		return this.resultSetType;
 2252   	}
 2253   
 2254   	/**
 2255   	 * getUpdateCount returns the current result as an update count, if the
 2256   	 * result is a ResultSet or there are no more results, -1 is returned. It
 2257   	 * should only be called once per result.
 2258   	 *
 2259   	 * @return the current result as an update count.
 2260   	 *
 2261   	 * @exception SQLException
 2262   	 *                if a database access error occurs
 2263   	 */
 2264   	public int getUpdateCount() throws SQLException {
 2265   		if (this.results == null) {
 2266   			return -1;
 2267   		}
 2268   
 2269   		if (this.results.reallyResult()) {
 2270   			return -1;
 2271   		}
 2272   
 2273   		int truncatedUpdateCount = 0;
 2274   
 2275   		if (this.results.getUpdateCount() > Integer.MAX_VALUE) {
 2276   			truncatedUpdateCount = Integer.MAX_VALUE;
 2277   		} else {
 2278   			truncatedUpdateCount = (int) this.results.getUpdateCount();
 2279   		}
 2280   
 2281   		return truncatedUpdateCount;
 2282   	}
 2283   
 2284   	/**
 2285   	 * The first warning reported by calls on this Statement is returned. A
 2286   	 * Statement's execute methods clear its java.sql.SQLWarning chain.
 2287   	 * Subsequent Statement warnings will be chained to this
 2288   	 * java.sql.SQLWarning.
 2289   	 *
 2290   	 * <p>
 2291   	 * The Warning chain is automatically cleared each time a statement is
 2292   	 * (re)executed.
 2293   	 * </p>
 2294   	 *
 2295   	 * <p>
 2296   	 * <B>Note:</B> If you are processing a ResultSet then any warnings
 2297   	 * associated with ResultSet reads will be chained on the ResultSet object.
 2298   	 * </p>
 2299   	 *
 2300   	 * @return the first java.sql.SQLWarning or null
 2301   	 *
 2302   	 * @exception SQLException
 2303   	 *                if a database access error occurs
 2304   	 */
 2305   	public java.sql.SQLWarning getWarnings() throws SQLException {
 2306   		checkClosed();
 2307   
 2308   		if (this.connection != null && !this.connection.isClosed()
 2309   				&& this.connection.versionMeetsMinimum(4, 1, 0)) {
 2310   			SQLWarning pendingWarningsFromServer = SQLError
 2311   					.convertShowWarningsToSQLWarnings(this.connection);
 2312   
 2313   			if (this.warningChain != null) {
 2314   				this.warningChain.setNextWarning(pendingWarningsFromServer);
 2315   			} else {
 2316   				this.warningChain = pendingWarningsFromServer;
 2317   			}
 2318   
 2319   			return this.warningChain;
 2320   		}
 2321   
 2322   		return this.warningChain;
 2323   	}
 2324   
 2325   	/**
 2326   	 * Closes this statement, and frees resources.
 2327   	 *
 2328   	 * @param calledExplicitly
 2329   	 *            was this called from close()?
 2330   	 *
 2331   	 * @throws SQLException
 2332   	 *             if an error occurs
 2333   	 */
 2334   	protected synchronized void realClose(boolean calledExplicitly, boolean closeOpenResults)
 2335   			throws SQLException {
 2336   		if (this.isClosed) {
 2337   			return;
 2338   		}
 2339   
 2340   		if (this.useUsageAdvisor) {
 2341   			if (!calledExplicitly) {
 2342   				String message = Messages.getString("Statement.63") //$NON-NLS-1$
 2343   						+ Messages.getString("Statement.64"); //$NON-NLS-1$
 2344   
 2345   				this.eventSink.consumeEvent(new ProfilerEvent(
 2346   						ProfilerEvent.TYPE_WARN,
 2347   						"", //$NON-NLS-1$
 2348   						this.currentCatalog, this.connectionId, this.getId(),
 2349   						-1, System.currentTimeMillis(), 0,
 2350   						Constants.MILLIS_I18N, null, this.pointOfOrigin,
 2351   						message));
 2352   			}
 2353   		}
 2354   
 2355   		if (closeOpenResults) {
 2356   			closeOpenResults = !this.holdResultsOpenOverClose;
 2357   		}
 2358   		
 2359   		if (closeOpenResults) {
 2360   			if (this.results != null) {
 2361   				
 2362   				try {
 2363   					this.results.close();
 2364   				} catch (Exception ex) {
 2365   					;
 2366   				}
 2367   			}
 2368   			
 2369   			closeAllOpenResults();
 2370   		}
 2371   
 2372   		if (this.connection != null) {
 2373   			if (this.maxRowsChanged) {
 2374   				this.connection.unsetMaxRows(this);
 2375   			}
 2376   
 2377   			if (!this.connection.getDontTrackOpenResources()) {
 2378   				this.connection.unregisterStatement(this);
 2379   			}
 2380   		}
 2381   
 2382   		this.isClosed = true;
 2383   
 2384   		this.results = null;
 2385   		this.connection = null;
 2386   		this.warningChain = null;
 2387   		this.openResults = null;
 2388   		this.batchedGeneratedKeys = null;
 2389   		this.localInfileInputStream = null;
 2390   		this.pingTarget = null;
 2391   	}
 2392   
 2393   	/**
 2394   	 * setCursorName defines the SQL cursor name that will be used by subsequent
 2395   	 * execute methods. This name can then be used in SQL positioned
 2396   	 * update/delete statements to identify the current row in the ResultSet
 2397   	 * generated by this statement. If a database doesn't support positioned
 2398   	 * update/delete, this method is a no-op.
 2399   	 *
 2400   	 * <p>
 2401   	 * <b>Note:</b> This MySQL driver does not support cursors.
 2402   	 * </p>
 2403   	 *
 2404   	 * @param name
 2405   	 *            the new cursor name
 2406   	 *
 2407   	 * @exception SQLException
 2408   	 *                if a database access error occurs
 2409   	 */
 2410   	public void setCursorName(String name) throws SQLException {
 2411   		// No-op
 2412   	}
 2413   
 2414   	/**
 2415   	 * If escape scanning is on (the default), the driver will do escape
 2416   	 * substitution before sending the SQL to the database.
 2417   	 *
 2418   	 * @param enable
 2419   	 *            true to enable; false to disable
 2420   	 *
 2421   	 * @exception SQLException
 2422   	 *                if a database access error occurs
 2423   	 */
 2424   	public void setEscapeProcessing(boolean enable)
 2425   			throws SQLException {
 2426   		this.doEscapeProcessing = enable;
 2427   	}
 2428   
 2429   	/**
 2430   	 * JDBC 2.0 Give a hint as to the direction in which the rows in a result
 2431   	 * set will be processed. The hint applies only to result sets created using
 2432   	 * this Statement object. The default value is ResultSet.FETCH_FORWARD.
 2433   	 *
 2434   	 * @param direction
 2435   	 *            the initial direction for processing rows
 2436   	 *
 2437   	 * @exception SQLException
 2438   	 *                if a database-access error occurs or direction is not one
 2439   	 *                of ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, or
 2440   	 *                ResultSet.FETCH_UNKNOWN
 2441   	 */
 2442   	public void setFetchDirection(int direction) throws SQLException {
 2443   		switch (direction) {
 2444   		case java.sql.ResultSet.FETCH_FORWARD:
 2445   		case java.sql.ResultSet.FETCH_REVERSE:
 2446   		case java.sql.ResultSet.FETCH_UNKNOWN:
 2447   			break;
 2448   
 2449   		default:
 2450   			throw SQLError.createSQLException(
 2451   					Messages.getString("Statement.5"), //$NON-NLS-1$
 2452   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
 2453   		}
 2454   	}
 2455   
 2456   	/**
 2457   	 * JDBC 2.0 Give the JDBC driver a hint as to the number of rows that should
 2458   	 * be fetched from the database when more rows are needed. The number of
 2459   	 * rows specified only affects result sets created using this statement. If
 2460   	 * the value specified is zero, then the hint is ignored. The default value
 2461   	 * is zero.
 2462   	 *
 2463   	 * @param rows
 2464   	 *            the number of rows to fetch
 2465   	 *
 2466   	 * @exception SQLException
 2467   	 *                if a database-access error occurs, or the condition 0
 2468   	 *                &lt;= rows &lt;= this.getMaxRows() is not satisfied.
 2469   	 */
 2470   	public void setFetchSize(int rows) throws SQLException {
 2471   		if (((rows < 0) && (rows != Integer.MIN_VALUE))
 2472   				|| ((this.maxRows != 0) && (this.maxRows != -1) && (rows > this
 2473   						.getMaxRows()))) {
 2474   			throw SQLError.createSQLException(
 2475   					Messages.getString("Statement.7"), //$NON-NLS-1$
 2476   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
 2477   		}
 2478   
 2479   		this.fetchSize = rows;
 2480   	}
 2481   
 2482   	protected void setHoldResultsOpenOverClose(boolean holdResultsOpenOverClose) {
 2483   		this.holdResultsOpenOverClose = holdResultsOpenOverClose;
 2484   	}
 2485   
 2486   	/**
 2487   	 * Sets the maxFieldSize
 2488   	 *
 2489   	 * @param max
 2490   	 *            the new max column size limit; zero means unlimited
 2491   	 *
 2492   	 * @exception SQLException
 2493   	 *                if size exceeds buffer size
 2494   	 */
 2495   	public void setMaxFieldSize(int max) throws SQLException {
 2496   		if (max < 0) {
 2497   			throw SQLError.createSQLException(Messages
 2498   					.getString("Statement.11"), //$NON-NLS-1$
 2499   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
 2500   		}
 2501   
 2502   		int maxBuf = (this.connection != null) ? this.connection
 2503   				.getMaxAllowedPacket() : MysqlIO.getMaxBuf();
 2504   
 2505   		if (max > maxBuf) {
 2506   			throw SQLError.createSQLException(Messages.getString(
 2507   					"Statement.13", //$NON-NLS-1$
 2508   					new Object[] { Constants.longValueOf(maxBuf) }), //$NON-NLS-1$
 2509   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
 2510   		}
 2511   
 2512   		this.maxFieldSize = max;
 2513   	}
 2514   
 2515   	/**
 2516   	 * Set the maximum number of rows
 2517   	 *
 2518   	 * @param max
 2519   	 *            the new max rows limit; zero means unlimited
 2520   	 *
 2521   	 * @exception SQLException
 2522   	 *                if a database access error occurs
 2523   	 *
 2524   	 * @see getMaxRows
 2525   	 */
 2526   	public void setMaxRows(int max) throws SQLException {
 2527   		if ((max > MysqlDefs.MAX_ROWS) || (max < 0)) {
 2528   			throw SQLError
 2529   					.createSQLException(
 2530   							Messages.getString("Statement.15") + max //$NON-NLS-1$
 2531   									+ " > " //$NON-NLS-1$ //$NON-NLS-2$
 2532   									+ MysqlDefs.MAX_ROWS + ".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
 2533   		}
 2534   
 2535   		if (max == 0) {
 2536   			max = -1;
 2537   		}
 2538   
 2539   		this.maxRows = max;
 2540   		this.maxRowsChanged = true;
 2541   
 2542   		if (this.maxRows == -1) {
 2543   			this.connection.unsetMaxRows(this);
 2544   			this.maxRowsChanged = false;
 2545   		} else {
 2546   			// Most people don't use setMaxRows()
 2547   			// so don't penalize them
 2548   			// with the extra query it takes
 2549   			// to do it efficiently unless we need
 2550   			// to.
 2551   			this.connection.maxRowsChanged(this);
 2552   		}
 2553   	}
 2554   
 2555   	/**
 2556   	 * Sets the queryTimeout limit
 2557   	 *
 2558   	 * @param seconds -
 2559   	 *            the new query timeout limit in seconds
 2560   	 *
 2561   	 * @exception SQLException
 2562   	 *                if a database access error occurs
 2563   	 */
 2564   	public void setQueryTimeout(int seconds) throws SQLException {
 2565   		if (seconds < 0) {
 2566   			throw SQLError.createSQLException(Messages
 2567   					.getString("Statement.21"), //$NON-NLS-1$
 2568   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
 2569   		}
 2570   
 2571   		this.timeoutInMillis = seconds * 1000;
 2572   	}
 2573   
 2574   	/**
 2575   	 * Sets the concurrency for result sets generated by this statement
 2576   	 *
 2577   	 * @param concurrencyFlag
 2578   	 *            DOCUMENT ME!
 2579   	 */
 2580   	void setResultSetConcurrency(int concurrencyFlag) {
 2581   		this.resultSetConcurrency = concurrencyFlag;
 2582   	}
 2583   
 2584   	/**
 2585   	 * Sets the result set type for result sets generated by this statement
 2586   	 *
 2587   	 * @param typeFlag
 2588   	 *            DOCUMENT ME!
 2589   	 */
 2590   	void setResultSetType(int typeFlag) {
 2591   		this.resultSetType = typeFlag;
 2592   	}
 2593   
 2594   	protected void getBatchedGeneratedKeys(java.sql.Statement batchedStatement) throws SQLException {
 2595   		if (this.retrieveGeneratedKeys) {
 2596   			java.sql.ResultSet rs = null;
 2597   
 2598   			try {
 2599   				rs = batchedStatement.getGeneratedKeys();
 2600   
 2601   				while (rs.next()) {
 2602   					this.batchedGeneratedKeys
 2603   							.add(new ByteArrayRow(new byte[][] { rs.getBytes(1) }, getExceptionInterceptor()));
 2604   				}
 2605   			} finally {
 2606   				if (rs != null) {
 2607   					rs.close();
 2608   				}
 2609   			}
 2610   		}
 2611   	}
 2612   	
 2613   	protected void getBatchedGeneratedKeys(int maxKeys) throws SQLException {
 2614   		if (this.retrieveGeneratedKeys) {
 2615   			java.sql.ResultSet rs = null;
 2616   
 2617   			try {
 2618   				if (maxKeys == 0)
 2619   					rs = getGeneratedKeysInternal();
 2620   				else
 2621   					rs = getGeneratedKeysInternal(maxKeys);
 2622   
 2623   				while (rs.next()) {
 2624   					this.batchedGeneratedKeys
 2625   							.add(new ByteArrayRow(new byte[][] { rs.getBytes(1) }, getExceptionInterceptor()));
 2626   				}
 2627   			} finally {
 2628   				if (rs != null) {
 2629   					rs.close();
 2630   				}
 2631   			}
 2632   		}
 2633   	}
 2634   
 2635   	/**
 2636   	 * @return
 2637   	 */
 2638   	private boolean useServerFetch() throws SQLException {
 2639   
 2640   		return this.connection.isCursorFetchEnabled() && this.fetchSize > 0
 2641   				&& this.resultSetConcurrency == ResultSet.CONCUR_READ_ONLY
 2642   				&& this.resultSetType == ResultSet.TYPE_FORWARD_ONLY;
 2643   	}
 2644   
 2645   	public synchronized boolean isClosed() throws SQLException {
 2646   		return this.isClosed;
 2647   	}
 2648   
 2649   	private boolean isPoolable = true;
 2650   
 2651   	public boolean isPoolable() throws SQLException {
 2652   		return this.isPoolable;
 2653   	}
 2654   
 2655   	public void setPoolable(boolean poolable) throws SQLException {
 2656   		this.isPoolable = poolable;
 2657   	}
 2658   
 2659   	/**
 2660        * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
 2661        * for an object that does. Returns false otherwise. If this implements the interface then return true,
 2662        * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
 2663        * object. If this does not implement the interface and is not a wrapper, return false.
 2664        * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
 2665        * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
 2666        * returns true then calling <code>unwrap</code> with the same argument should succeed.
 2667        *
 2668        * @param interfaces a Class defining an interface.
 2669        * @return true if this implements the interface or directly or indirectly wraps an object that does.
 2670        * @throws java.sql.SQLException  if an error occurs while determining whether this is a wrapper
 2671        * for an object with the given interface.
 2672        * @since 1.6
 2673        */
 2674   	public boolean isWrapperFor(Class iface) throws SQLException {
 2675   		checkClosed();
 2676   
 2677   		// This works for classes that aren't actually wrapping
 2678   		// anything
 2679   		return iface.isInstance(this);
 2680   	}
 2681   
 2682       /**
 2683        * Returns an object that implements the given interface to allow access to non-standard methods,
 2684        * or standard methods not exposed by the proxy.
 2685        * The result may be either the object found to implement the interface or a proxy for that object.
 2686        * If the receiver implements the interface then that is the object. If the receiver is a wrapper
 2687        * and the wrapped object implements the interface then that is the object. Otherwise the object is
 2688        *  the result of calling <code>unwrap</code> recursively on the wrapped object. If the receiver is not a
 2689        * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
 2690        *
 2691        * @param iface A Class defining an interface that the result must implement.
 2692        * @return an object that implements the interface. May be a proxy for the actual implementing object.
 2693        * @throws java.sql.SQLException If no object found that implements the interface
 2694        * @since 1.6
 2695        */
 2696   	public Object unwrap(Class iface) throws java.sql.SQLException {
 2697       	try {
 2698       		// This works for classes that aren't actually wrapping
 2699       		// anything
 2700               return Util.cast(iface, this);
 2701           } catch (ClassCastException cce) {
 2702               throw SQLError.createSQLException("Unable to unwrap to " + iface.toString(),
 2703               		SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
 2704           }
 2705       }
 2706   
 2707   	protected int findStartOfStatement(String sql) {
 2708   		int statementStartPos = 0;
 2709   
 2710   		if (StringUtils.startsWithIgnoreCaseAndWs(sql, "/*")) {
 2711   			statementStartPos = sql.indexOf("*/");
 2712   
 2713   			if (statementStartPos == -1) {
 2714   				statementStartPos = 0;
 2715   			} else {
 2716   				statementStartPos += 2;
 2717   			}
 2718   		} else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "--")
 2719   			|| StringUtils.startsWithIgnoreCaseAndWs(sql, "#")) {
 2720   			statementStartPos = sql.indexOf('\n');
 2721   
 2722   			if (statementStartPos == -1) {
 2723   				statementStartPos = sql.indexOf('\r');
 2724   
 2725   				if (statementStartPos == -1) {
 2726   					statementStartPos = 0;
 2727   				}
 2728   			}
 2729   		}
 2730   
 2731   		return statementStartPos;
 2732   	}
 2733   
 2734   	private InputStream localInfileInputStream;
 2735   
 2736       public synchronized InputStream getLocalInfileInputStream() {
 2737           return this.localInfileInputStream;
 2738       }
 2739   
 2740       public synchronized void setLocalInfileInputStream(InputStream stream) {
 2741           this.localInfileInputStream = stream;
 2742       }
 2743       
 2744       public synchronized void setPingTarget(PingTarget pingTarget) {
 2745   		this.pingTarget = pingTarget;
 2746   	}
 2747       
 2748       public ExceptionInterceptor getExceptionInterceptor() {
 2749       	return this.exceptionInterceptor;
 2750       }
 2751   	
 2752   	protected boolean containsOnDuplicateKeyInString(String sql) {
 2753   		return getOnDuplicateKeyLocation(sql) != -1;
 2754   	}
 2755   	
 2756   	protected int getOnDuplicateKeyLocation(String sql) {
 2757   		return StringUtils.indexOfIgnoreCaseRespectMarker(0, 
 2758   				sql, " ON DUPLICATE KEY UPDATE ", "\"'`", "\"'`", !this.connection.isNoBackslashEscapesSet());
 2759   	}
 2760   }

Save This Page
Home » MySQL-JDBC-5.1.11 » com.mysql.jdbc » [javadoc | source]