📄 serverpreparedstatement.java
字号:
* Used by Connection when auto-reconnecting to retrieve 'lost' prepared * statements. * * @throws SQLException * if an error occurs. */ protected void rePrepare() throws SQLException { this.invalidationException = null; try { serverPrepare(this.originalSql); } catch (SQLException sqlEx) { // don't wrap SQLExceptions this.invalidationException = sqlEx; } catch (Exception ex) { this.invalidationException = new SQLException(ex.toString(), SQLError.SQL_STATE_GENERAL_ERROR); } if (this.invalidationException != null) { this.invalid = true; this.parameterBindings = null; this.parameterFields = null; this.resultFields = null; if (this.results != null) { try { this.results.close(); } catch (Exception ex) { ; } } if (this.connection != null) { if (this.maxRowsChanged) { this.connection.unsetMaxRows(this); } if (!this.connection.getDontTrackOpenResources()) { this.connection.unregisterStatement(this); } } } } /** * Tells the server to execute this prepared statement with the current * parameter bindings. * * <pre> * * * - Server gets the command 'COM_EXECUTE' to execute the * previously prepared query. If there is any param markers; * then client will send the data in the following format: * * [COM_EXECUTE:1] * [STMT_ID:4] * [NULL_BITS:(param_count+7)/8)] * [TYPES_SUPPLIED_BY_CLIENT(0/1):1] * [[length]data] * [[length]data] .. [[length]data]. * * (Note: Except for string/binary types; all other types will not be * supplied with length field) * * * </pre> * * @param maxRowsToRetrieve * DOCUMENT ME! * @param createStreamingResultSet * DOCUMENT ME! * * @return DOCUMENT ME! * * @throws SQLException */ private com.mysql.jdbc.ResultSet serverExecute(int maxRowsToRetrieve, boolean createStreamingResultSet) throws SQLException { synchronized (this.connection.getMutex()) { if (this.detectedLongParameterSwitch) { // Check when values were bound boolean firstFound = false; long boundTimeToCheck = 0; for (int i = 0; i < this.parameterCount - 1; i++) { if (this.parameterBindings[i].isLongData) { if (firstFound && boundTimeToCheck != this.parameterBindings[i].boundBeforeExecutionNum) { throw new SQLException(Messages .getString("ServerPreparedStatement.11") //$NON-NLS-1$ + Messages.getString("ServerPreparedStatement.12"), //$NON-NLS-1$ SQLError.SQL_STATE_DRIVER_NOT_CAPABLE); } else { firstFound = true; boundTimeToCheck = this.parameterBindings[i].boundBeforeExecutionNum; } } } // Okay, we've got all "newly"-bound streams, so reset // server-side state to clear out previous bindings serverResetStatement(); } // Check bindings for (int i = 0; i < this.parameterCount; i++) { if (!this.parameterBindings[i].isSet) { throw new SQLException(Messages .getString("ServerPreparedStatement.13") + (i + 1) //$NON-NLS-1$ + Messages.getString("ServerPreparedStatement.14"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ } } // // Send all long data // for (int i = 0; i < this.parameterCount; i++) { if (this.parameterBindings[i].isLongData) { serverLongData(i, this.parameterBindings[i]); } } if (this.connection.getAutoGenerateTestcaseScript()) { dumpExecuteForTestcase(); } // // store the parameter values // MysqlIO mysql = this.connection.getIO(); Buffer packet = mysql.getSharedSendPacket(); packet.clear(); packet.writeByte((byte) MysqlDefs.COM_EXECUTE); packet.writeLong(this.serverStatementId); if (this.connection.versionMeetsMinimum(4, 1, 2)) { packet.writeByte((byte) 0); // placeholder for flags packet.writeLong(1); // placeholder for parameter iterations } /* Reserve place for null-marker bytes */ int nullCount = (this.parameterCount + 7) / 8; // if (mysql.versionMeetsMinimum(4, 1, 2)) { // nullCount = (this.parameterCount + 9) / 8; // } int nullBitsPosition = packet.getPosition(); for (int i = 0; i < nullCount; i++) { packet.writeByte((byte) 0); } byte[] nullBitsBuffer = new byte[nullCount]; /* In case if buffers (type) altered, indicate to server */ packet.writeByte(this.sendTypesToServer ? (byte) 1 : (byte) 0); if (this.sendTypesToServer) { /* * Store types of parameters in first in first package that is * sent to the server. */ for (int i = 0; i < this.parameterCount; i++) { packet.writeInt(this.parameterBindings[i].bufferType); } } // // store the parameter values // for (int i = 0; i < this.parameterCount; i++) { if (!this.parameterBindings[i].isLongData) { if (!this.parameterBindings[i].isNull) { storeBinding(packet, this.parameterBindings[i], mysql); } else { nullBitsBuffer[i / 8] |= (1 << (i & 7)); } } } // // Go back and write the NULL flags // to the beginning of the packet // int endPosition = packet.getPosition(); packet.setPosition(nullBitsPosition); packet.writeBytesNoNull(nullBitsBuffer); packet.setPosition(endPosition); long begin = 0; if (this.connection.getProfileSql() || this.connection.getLogSlowQueries() || this.connection.getGatherPerformanceMetrics()) { begin = System.currentTimeMillis(); } Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE, null, packet, false, null); this.connection.incrementNumberOfPreparedExecutes(); if (this.connection.getProfileSql()) { this.eventSink = ProfileEventSink.getInstance(this.connection); this.eventSink.consumeEvent(new ProfilerEvent( ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$ this.connection.getId(), this.statementId, -1, System .currentTimeMillis(), (int) (System .currentTimeMillis() - begin), null, new Throwable(), null)); } com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this, maxRowsToRetrieve, this.resultSetType, this.resultSetConcurrency, createStreamingResultSet, this.currentCatalog, resultPacket, true, this.fieldCount, true); if (!createStreamingResultSet && this.serverNeedsResetBeforeEachExecution) { serverResetStatement(); // clear any long data... } this.sendTypesToServer = false; this.results = rs; if (this.connection.getLogSlowQueries() || this.connection.getGatherPerformanceMetrics()) { long elapsedTime = System.currentTimeMillis() - begin; if (this.connection.getLogSlowQueries() && (elapsedTime > this.connection .getSlowQueryThresholdMillis())) { StringBuffer mesgBuf = new StringBuffer( 48 + this.originalSql.length()); mesgBuf.append(Messages .getString("ServerPreparedStatement.15")); //$NON-NLS-1$ mesgBuf.append(this.connection .getSlowQueryThresholdMillis()); mesgBuf.append(Messages .getString("ServerPreparedStatement.16")); //$NON-NLS-1$ mesgBuf.append(this.originalSql); this.connection.getLog().logWarn(mesgBuf.toString()); if (this.connection.getExplainSlowQueries()) { String queryAsString = asSql(true); mysql.explainSlowQuery(queryAsString.getBytes(), queryAsString); } } if (this.connection.getGatherPerformanceMetrics()) { this.connection.registerQueryExecutionTime(elapsedTime); } } return rs; } } /** * Sends stream-type data parameters to the server. * * <pre> * * Long data handling: * * - Server gets the long data in pieces with command type 'COM_LONG_DATA'. * - The packet recieved will have the format as: * [COM_LONG_DATA: 1][STMT_ID:4][parameter_number:2][type:2][data] * - Checks if the type is specified by client, and if yes reads the type, * and stores the data in that format. * - It's up to the client to check for read data ended. The server doesn't * care; and also server doesn't notify to the client that it got the * data or not; if there is any error; then during execute; the error * will be returned * * </pre> * * @param parameterIndex * DOCUMENT ME! * @param longData * DOCUMENT ME! * * @throws SQLException * if an error occurs. */ private void serverLongData(int parameterIndex, BindValue longData) throws SQLException { synchronized (this.connection.getMutex()) { MysqlIO mysql = this.connection.getIO(); Buffer packet = mysql.getSharedSendPacket(); Object value = longData.value; if (value instanceof byte[]) { packet.clear(); packet.writeByte((byte) MysqlDefs.COM_LONG_DATA); packet.writeLong(this.serverStatementId); packet.writeInt((parameterIndex)); packet.writeBytesNoNull((byte[]) longData.value); mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true, null); } else if (value instanceof InputStream) { storeStream(mysql, parameterIndex, packet, (InputStream) value); } else if (value instanceof java.sql.Blob) { storeStream(mysql, parameterIndex, packet, ((java.sql.Blob) value).getBinaryStream()); } else if (value instanceof Reader) { storeReader(mysql, parameterIndex, packet, (Reader) value); } else { throw new SQLException(Messages .getString("ServerPreparedStatement.18") //$NON-NLS-1$ + value.getClass().getName() + "'", //$NON-NLS-1$ SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } } } private void serverPrepare(String sql) throws SQLException { synchronized (this.connection.getMutex()) { MysqlIO mysql = this.connection.getIO(); if (this.connection.getAutoGenerateTestcaseScript()) { dumpPrepareForTestcase(); } try { long begin = 0; if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) { //$NON-NLS-1$ this.isLoadDataQuery = true; } else { this.isLoadDataQuery = false; } if (this.connection.getProfileSql()) { begin = System.currentTimeMillis(); } String characterEncoding = null; String connectionEncoding = this.connection.getEncoding(); if (!this.isLoadDataQuery && this.connection.getUseUnicode() && (connectionEncoding != null)) { characterEncoding = connectionEncoding; } Buffer prepareResultPacket = mysql.sendCommand( MysqlDefs.COM_PREPARE, sql, null, false, characterEncoding); if (this.connection.versionMeetsMinimum(4, 1, 1)) { // 4.1.1 and newer use the first byte // as an 'ok' or 'error' flag, so move // the buffer pointer past it to // start reading the statement id. prepareResultPacket.setPosition(1); } else { // 4.1.0 doesn't use the first byte as an // 'ok' or 'error' flag prepareResultPacket.setPosition(0); } this.serverStatementId = prepareResultPacket.readLong(); this.fieldCount = prepareResultPacket.readInt(); this.parameterCount = prepareResultPacket.readInt(); this.parameterBindings = new BindValue[this.parameterCount]; for (int i = 0; i < this.parameterCount; i++) { this.parameterBindings[i] = new BindValue(); } this.connection.incrementNumberOfPrepares(); if (this.connection.getProfileSql()) { this.eventSink = ProfileEventSink .getInstance(this.connection); this.eventSink.consumeEvent(new ProfilerEvent( ProfilerEvent.TYPE_PREPARE, "", this.currentCatalog, //$NON-NLS-1$ this.connection.getId(), this.statementId, -1, System.currentTimeMillis(), (int) (System .currentTimeMillis() - begin), null, new Throwable(), sql)); } if (this.parameterCount > 0) { if (this.connection.versionMeetsMinimum(4, 1, 2) && !mysql.isVersion(5, 0, 0)) { this.parameterFields = new Field[this.parameterCount]; Buffer metaDataPacket = mysql.readPacket(); int i = 0; while (!metaDataPacket.isLastDataPacket() && (i < this.parameterCount)) { this.parameterFields[i++] = mysql.unpackField( metaDataPacket, false); metaDataPacket = mysql.readPacket(); } } } if (this.fieldCount > 0) { this.resultFields = new Field[this.fieldCount]; Buffer fieldPacket = mysql.readPacket(); int i = 0; // Read in the result set column information while (!fieldPacket.isLastDataPacket() && (i < this.fieldCount)) { this.resultFields[i++] = mysql.unpackField(fieldPacket, false); fieldPacket = mysql.readPacket(); } } } catch (SQLException sqlEx) { if (this.connection.getDumpQueriesOnException()) { StringBuffer messageBuf = new StringBuffer(this.originalSql .length() + 32); messageBuf .append("\n\nQuery being prepared when exception was thrown:\n\n"); messageBuf.append(this.originalSql); sqlEx = Connection.appendMessageToException(sqlEx, messageBuf.toString()); } throw sqlEx; } finally { // Leave the I/O channel in a known state...there might be // packets out there // that we're not interested in this.connection.getIO().clearInputStream(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -