📄 serverpreparedstatement.java
字号:
packet.writeByte((byte) MysqlDefs.COM_CLOSE_STATEMENT); packet.writeLong(this.serverStatementId); mysql.sendCommand(MysqlDefs.COM_CLOSE_STATEMENT, null, packet, true, null); } catch (SQLException sqlEx) { exceptionDuringClose = sqlEx; } } super.realClose(calledExplicitly, closeOpenResults); clearParametersInternal(false); this.parameterBindings = null; this.parameterFields = null; this.resultFields = null; if (exceptionDuringClose != null) { throw exceptionDuringClose; } } } } /** * 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 = SQLError.createSQLException(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, boolean unpackFields, Field[] metadataFromCache) 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 SQLError.createSQLException(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 SQLError.createSQLException(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); boolean usingCursor = false; if (this.connection.versionMeetsMinimum(4, 1, 2)) { // we only create cursor-backed result sets if // a) The query is a SELECT // b) The server supports it // c) We know it is forward-only (note this doesn't // preclude updatable result sets) // d) The user has set a fetch size if (this.resultFields != null && this.connection.isCursorFetchEnabled() && getResultSetType() == ResultSet.TYPE_FORWARD_ONLY && getResultSetConcurrency() == ResultSet.CONCUR_READ_ONLY && getFetchSize() > 0) { packet.writeByte(MysqlDefs.OPEN_CURSOR_FLAG); usingCursor = true; } else { 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; boolean logSlowQueries = this.connection.getLogSlowQueries(); boolean gatherPerformanceMetrics = this.connection .getGatherPerformanceMetrics(); if (this.profileSQL || logSlowQueries || gatherPerformanceMetrics) { begin = mysql.getCurrentTimeNanosOrMillis(); } synchronized (this.cancelTimeoutMutex) { this.wasCancelled = false; } CancelTask timeoutTask = null; try { if (this.connection.getEnableQueryTimeouts() && this.timeoutInMillis != 0 && this.connection.versionMeetsMinimum(5, 0, 0)) { timeoutTask = new CancelTask(); this.connection.getCancelTimer().schedule(timeoutTask, this.timeoutInMillis); } Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE, null, packet, false, null); long queryEndTime = 0L; if (logSlowQueries || gatherPerformanceMetrics || this.profileSQL) { queryEndTime = mysql.getCurrentTimeNanosOrMillis(); } if (timeoutTask != null) { timeoutTask.cancel(); if (timeoutTask.caughtWhileCancelling != null) { throw timeoutTask.caughtWhileCancelling; } timeoutTask = null; } synchronized (this.cancelTimeoutMutex) { if (this.wasCancelled) { this.wasCancelled = false; throw new MySQLTimeoutException(); } } boolean queryWasSlow = false; if (logSlowQueries || gatherPerformanceMetrics) { long elapsedTime = queryEndTime - begin; if (logSlowQueries && (elapsedTime >= mysql.getSlowQueryThreshold())) { queryWasSlow = true; StringBuffer mesgBuf = new StringBuffer( 48 + this.originalSql.length()); mesgBuf.append(Messages .getString("ServerPreparedStatement.15")); //$NON-NLS-1$ mesgBuf.append(mysql.getSlowQueryThreshold()); mesgBuf.append(Messages .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$ mesgBuf.append(elapsedTime); mesgBuf.append(Messages .getString("ServerPreparedStatement.16")); //$NON-NLS-1$ mesgBuf.append("as prepared: "); mesgBuf.append(this.originalSql); mesgBuf.append("\n\n with parameters bound:\n\n"); mesgBuf.append(asSql(true)); this.eventSink .consumeEvent(new ProfilerEvent( ProfilerEvent.TYPE_SLOW_QUERY, "", this.currentCatalog, this.connection.getId(), //$NON-NLS-1$ getId(), 0, System.currentTimeMillis(), elapsedTime, mysql .getQueryTimingUnits(), null, new Throwable(), mesgBuf.toString())); } if (gatherPerformanceMetrics) { this.connection.registerQueryExecutionTime(elapsedTime); } } this.connection.incrementNumberOfPreparedExecutes(); if (this.profileSQL) { this.eventSink = ProfileEventSink .getInstance(this.connection); this.eventSink.consumeEvent(new ProfilerEvent( ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$ this.connectionId, this.statementId, -1, System .currentTimeMillis(), (int) (mysql .getCurrentTimeNanosOrMillis() - begin), mysql.getQueryTimingUnits(), null, new Throwable(), truncateQueryToLog(asSql(true)))); } com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this, maxRowsToRetrieve, this.resultSetType, this.resultSetConcurrency, createStreamingResultSet, this.currentCatalog, resultPacket, true, this.fieldCount, unpackFields, metadataFromCache); if (this.profileSQL) { long fetchEndTime = mysql.getCurrentTimeNanosOrMillis(); this.eventSink.consumeEvent(new ProfilerEvent( ProfilerEvent.TYPE_FETCH, "", this.currentCatalog, this.connection.getId(), //$NON-NLS-1$ getId(), rs.resultId, System.currentTimeMillis(), (fetchEndTime - queryEndTime), mysql .getQueryTimingUnits(), null, new Throwable(), null)); } if (queryWasSlow && this.connection.getExplainSlowQueries()) { String queryAsString = asSql(true); mysql.explainSlowQuery(queryAsString.getBytes(), queryAsString); } if (!createStreamingResultSet && this.serverNeedsResetBeforeEachExecution) { serverResetStatement(); // clear any long data... } this.sendTypesToServer = false; this.results = rs; if (mysql.hadWarnings()) { mysql.scanForAndThrowDataTruncation(); } return rs; } finally { if (timeoutTask != null) { timeoutTask.cancel(); } } } } /** * 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 SQLError.createSQLException(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()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -