📄 jtdspreparedstatement.java
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase// Copyright (C) 2004 The jTDS Project//// This library is free software; you can redistribute it and/or// modify it under the terms of the GNU Lesser General Public// License as published by the Free Software Foundation; either// version 2.1 of the License, or (at your option) any later version.//// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public// License along with this library; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//package net.sourceforge.jtds.jdbc;import java.io.InputStream;import java.io.Reader;import java.math.BigDecimal;import java.net.URL;import java.sql.Array;import java.sql.Blob;import java.sql.Clob;import java.sql.Date;import java.sql.ParameterMetaData;import java.sql.PreparedStatement;import java.sql.Ref;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import java.sql.Time;import java.sql.Timestamp;import java.util.Calendar;import java.util.Collection;import java.util.ArrayList;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.lang.reflect.Constructor;import java.text.NumberFormat;/** * jTDS implementation of the java.sql.PreparedStatement interface. * <p> * Implementation notes: * <ol> * <li>Generally a simple subclass of Statement mainly adding support for the * setting of parameters. * <li>The stream logic is taken over from the work Brian did to add Blob support * to the original jTDS. * <li>Use of Statement specific method calls eg executeQuery(sql) is blocked by * this version of the driver. This is unlike the original jTDS but inline * with all the other JDBC drivers that I have been able to test. * </ol> * * @author Mike Hutchinson * @author Brian Heineman * @version $Id: JtdsPreparedStatement.java,v 1.51 2005/06/16 09:32:27 alin_sinpalean Exp $ */public class JtdsPreparedStatement extends JtdsStatement implements PreparedStatement { /** The SQL statement being prepared. */ protected final String sql; /** The first SQL keyword in the SQL string.*/ protected String sqlWord; /** The procedure name for CallableStatements. */ protected String procName; /** The parameter list for the call. */ protected ParamInfo[] parameters; /** True to return generated keys. */ private boolean returnKeys; /** The cached parameter meta data. */ protected ParamInfo[] paramMetaData; /** Used to format numeric values when scale is specified. */ private static NumberFormat f = NumberFormat.getInstance(); /** Collection of handles used by this statement */ Collection handles; /** * Construct a new preparedStatement object. * * @param connection The parent connection. * @param sql The SQL statement to prepare. * @param resultSetType The result set type eg SCROLLABLE etc. * @param concurrency The result set concurrency eg READONLY. * @param returnKeys True if generated keys should be returned. * @throws SQLException */ JtdsPreparedStatement(ConnectionJDBC2 connection, String sql, int resultSetType, int concurrency, boolean returnKeys) throws SQLException { super(connection, resultSetType, concurrency); // Parse the SQL looking for escapes and parameters if (this instanceof JtdsCallableStatement) { sql = normalizeCall(sql); } ArrayList params = new ArrayList(); String[] parsedSql = SQLParser.parse(sql, params, connection, false); if (parsedSql[0].length() == 0) { throw new SQLException(Messages.get("error.prepare.nosql"), "07000"); } if (parsedSql[1].length() > 1) { if (this instanceof JtdsCallableStatement) { // Procedure call this.procName = parsedSql[1]; } } sqlWord = parsedSql[2]; if (returnKeys && sqlWord.equals("insert")) { if (connection.getServerType() == Driver.SQLSERVER && connection.getDatabaseMajorVersion() >= 8) { this.sql = parsedSql[0] + " SELECT SCOPE_IDENTITY() AS ID"; } else { this.sql = parsedSql[0] + " SELECT @@IDENTITY AS ID"; } this.returnKeys = true; } else { this.sql = parsedSql[0]; this.returnKeys = false; } parameters = (ParamInfo[]) params.toArray(new ParamInfo[params.size()]); } /** * This method converts native call syntax into (hopefully) valid JDBC escape syntax. * NB. This method is required for backwards compatibility with previous versions of jTDS. * Strictly speaking only the JDBC syntax needs to be recognised, * constructions such as "?=#testproc ?,?" are neither valid native syntax nor valid escapes. * All the substrings and trims below are not as bad as they look. The objects created all refer back * to the original sql string it is just the start and length positions which change. * @param sql The SQL statement to process. * @return The SQL possibly in original form. */ protected static String normalizeCall(String sql) { String original = sql; sql = sql.trim(); if (sql.length() > 0 && sql.charAt(0) == '{') { return original; // Assume already escaped } if (sql.length() > 4 && sql.substring(0, 5).equalsIgnoreCase("exec ")) { sql = sql.substring(4).trim(); } else if (sql.length() > 7 && sql.substring(0, 8).equalsIgnoreCase("execute ")){ sql = sql.substring(7).trim(); } if (sql.length() > 1 && sql.charAt(0) == '?') { sql = sql.substring(1).trim(); if (sql.length() < 1 || sql.charAt(0) != '=') { return original; // Give up error will be reported elsewhere } sql = sql.substring(1).trim(); // OK now reconstruct as JDBC escaped call return "{?=call " + sql + '}'; } return "{call " + sql + '}'; } /** * Check that this statement is still open. * * @throws SQLException if statement closed. */ protected void checkOpen() throws SQLException { if (closed) { throw new SQLException( Messages.get("error.generic.closed", "PreparedStatement"), "HY010"); } } /** * Report that user tried to call a method not supported on this type of statement. * * @param method The method name to report in the error message. * @throws SQLException */ protected void notSupported(String method) throws SQLException { throw new SQLException( Messages.get("error.generic.notsup", method), "HYC00"); } /** * Executes a <code>ParamInfo</code> array (list of parameters). * * @param value list of parameters to execute * @param last <code>true</code> if this is the last parameter list in the * batch */ protected void executeBatchOther(Object value, boolean last) throws SQLException { if (value instanceof ParamInfo[]) { // procName will contain the procedure name for CallableStatements // and null for PreparedStatements tds.executeSQL(sql, procName, (ParamInfo[])value, false, 0, -1, -1, last); } else { super.executeBatchOther(value, last); } }/* protected int executeBatchOther(Object value) throws SQLException { if (value instanceof ParamInfo[]) { ParamInfo[] saveParameters = parameters; try { parameters = (ParamInfo[]) value; return executeUpdate(); } finally { parameters = saveParameters; } } super.executeBatchOther(value); return Integer.MIN_VALUE; }*/ /** * Check the supplied index and return the selected parameter. * * @param parameterIndex the parameter index 1 to n. * @return the parameter as a <code>ParamInfo</code> object. * @throws SQLException if the statement is closed; * if <code>parameterIndex</code> is less than 0; * if <code>parameterIndex</code> is greater than the * number of parameters; * if <code>checkIfSet</code> was <code>true</code> * and the parameter was not set */ protected ParamInfo getParameter(int parameterIndex) throws SQLException { checkOpen(); if (parameterIndex < 1 || parameterIndex > parameters.length) { throw new SQLException(Messages.get("error.prepare.paramindex", Integer.toString(parameterIndex)), "07009"); } ParamInfo pi = parameters[parameterIndex - 1]; return pi; } /** * Generic setObject method. * * @param parameterIndex Parameter index 1 to n. * @param x The value to set. * @param targetSqlType The java.sql.Types constant describing the data. * @param scale The decimal scale -1 if not set. */ public void setObjectBase(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException { checkOpen(); int length = 0; if (targetSqlType == java.sql.Types.CLOB) { targetSqlType = java.sql.Types.LONGVARCHAR; } else if (targetSqlType == java.sql.Types.BLOB) { targetSqlType = java.sql.Types.LONGVARBINARY; } if (x != null) { x = Support.convert(this, x, targetSqlType, connection.getCharset()); if (scale >= 0) { if (x instanceof BigDecimal) { x = ((BigDecimal) x).setScale(scale, BigDecimal.ROUND_HALF_UP); } else if (x instanceof Number) { synchronized (f) { f.setGroupingUsed(false); f.setMaximumFractionDigits(scale); x = Support.convert(this, f.format(x), targetSqlType, connection.getCharset()); } } } if (x instanceof Blob) { Blob blob = (Blob) x; length = (int) blob.length(); x = blob.getBinaryStream(); } else if (x instanceof Clob) { Clob clob = (Clob) x; length = (int) clob.length(); x = clob.getCharacterStream(); } } setParameter(parameterIndex, x, targetSqlType, scale, length); } /** * Update the ParamInfo object for the specified parameter. * * @param parameterIndex Parameter index 1 to n. * @param x The value to set. * @param targetSqlType The java.sql.Types constant describing the data. * @param scale The decimal scale -1 if not set. * @param length The length of the data item. */ protected void setParameter(int parameterIndex, Object x, int targetSqlType, int scale, int length) throws SQLException { ParamInfo pi = getParameter(parameterIndex); if (Support.getJdbcTypeName(targetSqlType).equals("ERROR")) { throw new SQLException(Messages.get("error.generic.badtype", Integer.toString(targetSqlType)), "HY092"); } pi.scale = (scale < 0) ? 0 : scale; // Update parameter descriptor if (targetSqlType == java.sql.Types.DECIMAL || targetSqlType == java.sql.Types.NUMERIC) { pi.precision = connection.getMaxPrecision(); if (x instanceof BigDecimal) { x = Support.normalizeBigDecimal((BigDecimal) x, pi.precision); pi.scale = ((BigDecimal) x).scale(); } } if (x instanceof String) { pi.length = ((String) x).length(); } else if (x instanceof byte[]) { pi.length = ((byte[]) x).length; } else { pi.length = length; } if (x instanceof Date) { x = new DateTime((Date) x); } else if (x instanceof Time) { x = new DateTime((Time) x); } else if (x instanceof Timestamp) { x = new DateTime((Timestamp) x); } pi.value = x; pi.jdbcType = targetSqlType; pi.isSet = true; pi.isUnicode = connection.isUseUnicode(); } /** * Update the cached column meta data information. * * @param value The Column meta data array. */ void setColMetaData(ColInfo[] value) { this.colMetaData = value; } /** * Update the cached parameter meta data information. * * @param value The Column meta data array. */ void setParamMetaData(ParamInfo[] value) { for (int i = 0; i < value.length && i < parameters.length; i++) { if (!parameters[i].isSet) { // Only update parameter descriptors if the user // has not yet set them. parameters[i].jdbcType = value[i].jdbcType; parameters[i].isOutput = value[i].isOutput; parameters[i].precision = value[i].precision; parameters[i].scale = value[i].scale; parameters[i].sqlType = value[i].sqlType; } } }// -------------------- java.sql.PreparedStatement methods follow ----------------- public int executeUpdate() throws SQLException { checkOpen(); initialize(); if (procName == null && !(this instanceof JtdsCallableStatement)) { // Sync on the connection to make sure rollback() isn't called // between the moment when the statement is prepared and the moment // when it's executed. synchronized (connection) { String spName = connection.prepareSQL(this, sql, parameters, returnKeys, false); executeSQL(sql, spName, parameters, returnKeys, true, false); } } else { executeSQL(sql, procName, parameters, returnKeys, true, false); } int res = getUpdateCount(); return res == -1 ? 0 : res; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -