List:Commits« Previous MessageNext Message »
From:mmatthews Date:November 1 2007 3:34am
Subject:Connector/J commit: r6655 - branches/branch_5_1/src/com/mysql/jdbc
View as plain text  
Modified:
   branches/branch_5_1/src/com/mysql/jdbc/ServerPreparedStatement.java
Log:
Pulled up batch rewriting from 5.0.

Modified: branches/branch_5_1/src/com/mysql/jdbc/ServerPreparedStatement.java
===================================================================
--- branches/branch_5_1/src/com/mysql/jdbc/ServerPreparedStatement.java	2007-10-29 18:15:35 UTC (rev 6654)
+++ branches/branch_5_1/src/com/mysql/jdbc/ServerPreparedStatement.java	2007-11-01 03:34:31 UTC (rev 6655)
@@ -24,6 +24,7 @@
  */
 package com.mysql.jdbc;
 
+import com.mysql.jdbc.StatementImpl.CancelTask;
 import com.mysql.jdbc.exceptions.MySQLStatementCancelledException;
 import com.mysql.jdbc.exceptions.MySQLTimeoutException;
 import com.mysql.jdbc.profiler.ProfilerEventHandlerFactory;
@@ -208,6 +209,51 @@
 				}
 			}
 		}
+		
+		long getBoundLength() {
+			if (isNull) {
+				return 0;
+			}
+			
+			if (isLongData) {
+				return bindLength;
+			}
+
+			switch (bufferType) {
+
+			case MysqlDefs.FIELD_TYPE_TINY:
+				return 1;
+			case MysqlDefs.FIELD_TYPE_SHORT:
+				return 2;
+			case MysqlDefs.FIELD_TYPE_LONG:
+				return 4;
+			case MysqlDefs.FIELD_TYPE_LONGLONG:
+				return 8;
+			case MysqlDefs.FIELD_TYPE_FLOAT:
+				return 4;
+			case MysqlDefs.FIELD_TYPE_DOUBLE:
+				return 8;
+			case MysqlDefs.FIELD_TYPE_TIME:
+				return 9;
+			case MysqlDefs.FIELD_TYPE_DATE:
+				return 7;
+			case MysqlDefs.FIELD_TYPE_DATETIME:
+			case MysqlDefs.FIELD_TYPE_TIMESTAMP:
+				return 11;
+			case MysqlDefs.FIELD_TYPE_VAR_STRING:
+			case MysqlDefs.FIELD_TYPE_STRING:
+			case MysqlDefs.FIELD_TYPE_VARCHAR:
+			case MysqlDefs.FIELD_TYPE_DECIMAL:
+			case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
+				if (value instanceof byte[]) {
+					return ((byte[]) value).length;
+				} else {
+					return ((String) value).length();
+				}
+			default: 
+				return 0;
+			}
+		}
 	}
 
 	/* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
@@ -616,10 +662,7 @@
 		this.connection.dumpTestcaseQuery(buf.toString());
 	}
 
-	/**
-	 * @see java.sql.Statement#executeBatch()
-	 */
-	public synchronized int[] executeBatch() throws SQLException {
+	protected int[] executeBatchSerially(int batchTimeout) throws SQLException {
 		if (this.connection.isReadOnly()) {
 			throw SQLError.createSQLException(Messages
 					.getString("ServerPreparedStatement.2") //$NON-NLS-1$
@@ -657,77 +700,97 @@
 
 					BindValue[] previousBindValuesForBatch = null;
 
-					for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
-						Object arg = this.batchedArgs.get(commandIndex);
-
-						if (arg instanceof String) {
-							updateCounts[commandIndex] = executeUpdate((String) arg);
-						} else {
-							this.parameterBindings = ((BatchedBindValues) arg).batchedParameterValues;
-
-							try {
-								// We need to check types each time, as
-								// the user might have bound different
-								// types in each addBatch()
-
-								if (previousBindValuesForBatch != null) {
-									for (int j = 0; j < this.parameterBindings.length; j++) {
-										if (this.parameterBindings[j].bufferType != previousBindValuesForBatch[j].bufferType) {
-											this.sendTypesToServer = true;
-
-											break;
+					CancelTask timeoutTask = null;
+					
+					try {
+						if (this.connection.getEnableQueryTimeouts() &&
+								batchTimeout != 0
+								&& this.connection.versionMeetsMinimum(5, 0, 0)) {
+							timeoutTask = new CancelTask(this);
+							ConnectionImpl.getCancelTimer().schedule(timeoutTask,
+									batchTimeout);
+						}
+						
+						for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
+							Object arg = this.batchedArgs.get(commandIndex);
+	
+							if (arg instanceof String) {
+								updateCounts[commandIndex] = executeUpdate((String) arg);
+							} else {
+								this.parameterBindings = ((BatchedBindValues) arg).batchedParameterValues;
+	
+								try {
+									// We need to check types each time, as
+									// the user might have bound different
+									// types in each addBatch()
+	
+									if (previousBindValuesForBatch != null) {
+										for (int j = 0; j < this.parameterBindings.length; j++) {
+											if (this.parameterBindings[j].bufferType != previousBindValuesForBatch[j].bufferType) {
+												this.sendTypesToServer = true;
+	
+												break;
+											}
 										}
 									}
-								}
-
-								try {
-									updateCounts[commandIndex] = executeUpdate(false, true);
-								} finally {
-									previousBindValuesForBatch = this.parameterBindings;
-								}
-
-								if (this.retrieveGeneratedKeys) {
-									java.sql.ResultSet rs = null;
-
+	
 									try {
-										// we don't want to use our version,
-										// because we've altered the behavior of
-										// ours to support batch updates
-										// (catch-22)
-										// Ideally, what we need here is
-										// super.super.getGeneratedKeys()
-										// but that construct doesn't exist in
-										// Java, so that's why there's
-										// this kludge.
-										rs = getGeneratedKeysInternal();
-
-										while (rs.next()) {
-											this.batchedGeneratedKeys
-													.add(new ByteArrayRow(new byte[][] { rs
-															.getBytes(1) }));
-										}
+										updateCounts[commandIndex] = executeUpdate(false, true);
 									} finally {
-										if (rs != null) {
-											rs.close();
+										previousBindValuesForBatch = this.parameterBindings;
+									}
+	
+									if (this.retrieveGeneratedKeys) {
+										java.sql.ResultSet rs = null;
+	
+										try {
+											// we don't want to use our version,
+											// because we've altered the behavior of
+											// ours to support batch updates
+											// (catch-22)
+											// Ideally, what we need here is
+											// super.super.getGeneratedKeys()
+											// but that construct doesn't exist in
+											// Java, so that's why there's
+											// this kludge.
+											rs = getGeneratedKeysInternal();
+	
+											while (rs.next()) {
+												this.batchedGeneratedKeys
+														.add(new ByteArrayRow(new byte[][] { rs
+																.getBytes(1) }));
+											}
+										} finally {
+											if (rs != null) {
+												rs.close();
+											}
 										}
 									}
+								} catch (SQLException ex) {
+									updateCounts[commandIndex] = EXECUTE_FAILED;
+									
+									if (this.continueBatchOnError && 
+											!(ex instanceof MySQLTimeoutException) && 
+											!(ex instanceof MySQLStatementCancelledException)) {
+										sqlEx = ex;
+									} else {
+										int[] newUpdateCounts = new int[commandIndex];
+										System.arraycopy(updateCounts, 0,
+												newUpdateCounts, 0, commandIndex);
+			
+										throw new java.sql.BatchUpdateException(ex
+												.getMessage(), ex.getSQLState(), ex
+												.getErrorCode(), newUpdateCounts);
+									}
 								}
-							} catch (SQLException ex) {
-								updateCounts[commandIndex] = EXECUTE_FAILED;
-
-								if (this.continueBatchOnError) {
-									sqlEx = ex;
-								} else {
-									int[] newUpdateCounts = new int[commandIndex];
-									System.arraycopy(updateCounts, 0,
-											newUpdateCounts, 0, commandIndex);
-
-									throw new java.sql.BatchUpdateException(ex
-											.getMessage(), ex.getSQLState(), ex
-											.getErrorCode(), newUpdateCounts);
-								}
 							}
 						}
+					} finally {
+						if (timeoutTask != null) {
+							timeoutTask.cancel();
+						}
+						
+						resetCancelledState();
 					}
 
 					if (sqlEx != null) {
@@ -2576,5 +2639,184 @@
 		return serverStatementId;
 	}
 
+	public synchronized boolean canRewriteAsMultivalueInsertStatement() {
+		if (!super.canRewriteAsMultivalueInsertStatement()) {
+			return false;
+		}
+	
+		BindValue[] currentBindValues = null;
+		BindValue[] previousBindValues = null;
+	
+		int nbrCommands = this.batchedArgs.size();
+	
+		// Can't have type changes between sets of bindings for this to work...
+	
+		for (int commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
+			Object arg = this.batchedArgs.get(commandIndex);
+	
+			if (!(arg instanceof String)) {
+	
+				currentBindValues = ((BatchedBindValues) arg).batchedParameterValues;
+	
+				// We need to check types each time, as
+				// the user might have bound different
+				// types in each addBatch()
+	
+				if (previousBindValues != null) {
+					for (int j = 0; j < this.parameterBindings.length; j++) {
+						if (currentBindValues[j].bufferType != previousBindValues[j].bufferType) {
+							return false;
+						}
+					}
+				}
+			}
+		}
+		
+		return true;
+	}
 
+	/** 
+	 *  Computes the maximum parameter set size, and entire batch size given 
+	 *  the number of arguments in the batch.
+	 */
+	protected long[] computeMaxParameterSetSizeAndBatchSize(int numBatchedArgs) {
+		long sizeOfEntireBatch = 1 + /* com_execute */ + 4 /* stmt id */ + 1 /* flags */ + 4 /* batch count padding */; 
+		long maxSizeOfParameterSet = 0;
+		
+		for (int i = 0; i < numBatchedArgs; i++) {
+			BindValue[] paramArg = ((BatchedBindValues) this.batchedArgs.get(i)).batchedParameterValues;
+	
+			long sizeOfParameterSet = 0;
+			
+			sizeOfParameterSet += (this.parameterCount + 7) / 8; // for isNull
+			
+			sizeOfParameterSet += this.parameterCount * 2; // have to send types
+			
+			for (int j = 0; j < this.parameterBindings.length; j++) {
+				if (!paramArg[j].isNull) {
+	
+					long size = paramArg[j].getBoundLength();
+					
+					if (paramArg[j].isLongData) {
+						if (size != -1) {
+							sizeOfParameterSet += size;
+						}
+					} else {
+						sizeOfParameterSet += size;
+					}
+				}
+			}
+			
+			sizeOfEntireBatch += sizeOfParameterSet;
+			
+			if (sizeOfParameterSet > maxSizeOfParameterSet) {
+				maxSizeOfParameterSet = sizeOfParameterSet;
+			}
+		}	
+		
+		return new long[] {maxSizeOfParameterSet, sizeOfEntireBatch};
+	}
+
+	protected int setOneBatchedParameterSet(
+			java.sql.PreparedStatement batchedStatement, int batchedParamIndex,
+			Object paramSet) throws SQLException {
+		BindValue[] paramArg = ((BatchedBindValues) paramSet).batchedParameterValues;
+	
+		for (int j = 0; j < paramArg.length; j++) {
+			if (paramArg[j].isNull) {
+				batchedStatement.setNull(batchedParamIndex++, Types.NULL);
+			} else {
+				if (paramArg[j].isLongData) {
+					Object value = paramArg[j].value;
+	
+					if (value instanceof InputStream) {
+						batchedStatement.setBinaryStream(batchedParamIndex++,
+								(InputStream) value,
+								(int) paramArg[j].bindLength);
+					} else {
+						batchedStatement.setCharacterStream(
+								batchedParamIndex++, (Reader) value,
+								(int) paramArg[j].bindLength);
+					}
+				} else {
+	
+					switch (paramArg[j].bufferType) {
+	
+					case MysqlDefs.FIELD_TYPE_TINY:
+						batchedStatement.setByte(batchedParamIndex++,
+								paramArg[j].byteBinding);
+						break;
+					case MysqlDefs.FIELD_TYPE_SHORT:
+						batchedStatement.setShort(batchedParamIndex++,
+								paramArg[j].shortBinding);
+						break;
+					case MysqlDefs.FIELD_TYPE_LONG:
+						batchedStatement.setInt(batchedParamIndex++,
+								paramArg[j].intBinding);
+						break;
+					case MysqlDefs.FIELD_TYPE_LONGLONG:
+						batchedStatement.setLong(batchedParamIndex++,
+								paramArg[j].longBinding);
+						break;
+					case MysqlDefs.FIELD_TYPE_FLOAT:
+						batchedStatement.setFloat(batchedParamIndex++,
+								paramArg[j].floatBinding);
+						break;
+					case MysqlDefs.FIELD_TYPE_DOUBLE:
+						batchedStatement.setDouble(batchedParamIndex++,
+								paramArg[j].doubleBinding);
+						break;
+					case MysqlDefs.FIELD_TYPE_TIME:
+						batchedStatement.setTime(batchedParamIndex++,
+								(Time) paramArg[j].value);
+						break;
+					case MysqlDefs.FIELD_TYPE_DATE:
+						batchedStatement.setDate(batchedParamIndex++,
+								(Date) paramArg[j].value);
+						break;
+					case MysqlDefs.FIELD_TYPE_DATETIME:
+					case MysqlDefs.FIELD_TYPE_TIMESTAMP:
+						batchedStatement.setTimestamp(batchedParamIndex++,
+								(Timestamp) paramArg[j].value);
+						break;
+					case MysqlDefs.FIELD_TYPE_VAR_STRING:
+					case MysqlDefs.FIELD_TYPE_STRING:
+					case MysqlDefs.FIELD_TYPE_VARCHAR:
+					case MysqlDefs.FIELD_TYPE_DECIMAL:
+					case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
+						Object value = paramArg[j].value;
+	
+						if (value instanceof byte[]) {
+							batchedStatement.setBytes(batchedParamIndex,
+									(byte[]) value);
+						} else {
+							batchedStatement.setString(batchedParamIndex,
+									(String) value);
+						}
+	
+						BindValue asBound = ((ServerPreparedStatement) batchedStatement)
+								.getBinding(
+										batchedParamIndex + 1 /*
+																 * uses 1-based
+																 * offset
+																 */,
+										false);
+						asBound.bufferType = paramArg[j].bufferType;
+	
+						batchedParamIndex++;
+	
+						break;
+					default:
+						throw new IllegalArgumentException(
+								"Unknown type when re-binding parameter into batched statement for parameter index "
+										+ batchedParamIndex);
+					}
+				}
+			}
+		}
+	
+		return batchedParamIndex;
+	}
+
+
 }

Thread
Connector/J commit: r6655 - branches/branch_5_1/src/com/mysql/jdbcmmatthews1 Nov