Package com.mysql.jdbc

Source Code of com.mysql.jdbc.CallableStatement$CallableStatementParamInfoJDBC3

/*
  Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.

  The MySQL Connector/J is licensed under the terms of the GPLv2
  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
  this software, see the FLOSS License Exception
  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.

  This program is free software; you can redistribute it and/or modify it under the terms
  of the GNU General Public License as published by the Free Software Foundation; version 2
  of the License.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along with this
  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
  Floor, Boston, MA 02110-1301  USA
*/
package com.mysql.jdbc;

import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
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.Ref;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* Representation of stored procedures for JDBC
*
* @author Mark Matthews
* @version $Id: CallableStatement.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
*          Exp $
*/
public class CallableStatement extends PreparedStatement implements
    java.sql.CallableStatement {
  protected final static Constructor<?> JDBC_4_CSTMT_2_ARGS_CTOR;
 
  protected final static Constructor<?> JDBC_4_CSTMT_4_ARGS_CTOR;
 
  static {
    if (Util.isJdbc4()) {
      try {
        JDBC_4_CSTMT_2_ARGS_CTOR = Class.forName(
            "com.mysql.jdbc.JDBC4CallableStatement")
            .getConstructor(
                new Class[] { MySQLConnection.class,
                    CallableStatementParamInfo.class });
        JDBC_4_CSTMT_4_ARGS_CTOR = Class.forName(
            "com.mysql.jdbc.JDBC4CallableStatement")
            .getConstructor(
                new Class[] { MySQLConnection.class,
                    String.class, String.class,
                    Boolean.TYPE });
      } catch (SecurityException e) {
        throw new RuntimeException(e);
      } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
      } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
      }
    } else {
      JDBC_4_CSTMT_4_ARGS_CTOR = null;
      JDBC_4_CSTMT_2_ARGS_CTOR = null;
    }
  }
 
  protected static class CallableStatementParam {
    int desiredJdbcType;

    int index;

    int inOutModifier;

    boolean isIn;

    boolean isOut;

    int jdbcType;

    short nullability;

    String paramName;

    int precision;

    int scale;

    String typeName;

    CallableStatementParam(String name, int idx, boolean in, boolean out,
        int jdbcType, String typeName, int precision, int scale,
        short nullability, int inOutModifier) {
      this.paramName = name;
      this.isIn = in;
      this.isOut = out;
      this.index = idx;

      this.jdbcType = jdbcType;
      this.typeName = typeName;
      this.precision = precision;
      this.scale = scale;
      this.nullability = nullability;
      this.inOutModifier = inOutModifier;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#clone()
     */
    protected Object clone() throws CloneNotSupportedException {
      return super.clone();
    }
  }

  protected class CallableStatementParamInfo {
    String catalogInUse;

    boolean isFunctionCall;

    String nativeSql;

    int numParameters;

    List<CallableStatementParam> parameterList;

    Map<String, CallableStatementParam> parameterMap;

   
    /**
     * synchronized externally in checkReadOnlyProcedure()
     */
    boolean isReadOnlySafeProcedure = false;
   
    /**
     * synchronized externally in checkReadOnlyProcedure()
     */
    boolean isReadOnlySafeChecked = false;

    /**
     * Constructor that converts a full list of parameter metadata into one
     * that only represents the placeholders present in the {CALL ()}.
     *
     * @param fullParamInfo the metadata for all parameters for this stored
     * procedure or function.
     */
    CallableStatementParamInfo(CallableStatementParamInfo fullParamInfo) {
      this.nativeSql = originalSql;
      this.catalogInUse = currentCatalog;
      isFunctionCall = fullParamInfo.isFunctionCall;
      @SuppressWarnings("synthetic-access")
      int[] localParameterMap = placeholderToParameterIndexMap;
      int parameterMapLength = localParameterMap.length;
     
      this.isReadOnlySafeProcedure = fullParamInfo.isReadOnlySafeProcedure;
      this.isReadOnlySafeChecked = fullParamInfo.isReadOnlySafeChecked;
      parameterList = new ArrayList<CallableStatementParam>(fullParamInfo.numParameters);
      parameterMap = new HashMap<String, CallableStatementParam>(fullParamInfo.numParameters);
     
      if (isFunctionCall) {
        // Take the return value
        parameterList.add(fullParamInfo.parameterList.get(0));
      }
     
      int offset = isFunctionCall ? 1 : 0;
     
      for (int i = 0; i < parameterMapLength; i++) {
        if (localParameterMap[i] != 0) {
          CallableStatementParam param = fullParamInfo.parameterList.get(localParameterMap[i] + offset);
         
          parameterList.add(param);
          parameterMap.put(param.paramName, param);
        }
      }
     
      this.numParameters = parameterList.size();
    }
   
    @SuppressWarnings("synthetic-access")
    CallableStatementParamInfo(java.sql.ResultSet paramTypesRs)
        throws SQLException {
      boolean hadRows = paramTypesRs.last();

      this.nativeSql = originalSql;
      this.catalogInUse = currentCatalog;
      isFunctionCall = callingStoredFunction;

      if (hadRows) {
        this.numParameters = paramTypesRs.getRow();

        this.parameterList = new ArrayList<CallableStatementParam>(this.numParameters);
        this.parameterMap = new HashMap<String, CallableStatementParam>(this.numParameters);

        paramTypesRs.beforeFirst();

        addParametersFromDBMD(paramTypesRs);
      } else {
        this.numParameters = 0;
      }
     
      if (isFunctionCall) {
        this.numParameters += 1;
    }
    }

    private void addParametersFromDBMD(java.sql.ResultSet paramTypesRs)
        throws SQLException {
      int i = 0;

      while (paramTypesRs.next()) {
        String paramName = paramTypesRs.getString(4);
        int inOutModifier = paramTypesRs.getInt(5);

        boolean isOutParameter = false;
        boolean isInParameter = false;

        if (i == 0 && isFunctionCall) {
          isOutParameter = true;
          isInParameter = false;
        } else if (inOutModifier == DatabaseMetaData.procedureColumnInOut) {
          isOutParameter = true;
          isInParameter = true;
        } else if (inOutModifier == DatabaseMetaData.procedureColumnIn) {
          isOutParameter = false;
          isInParameter = true;
        } else if (inOutModifier == DatabaseMetaData.procedureColumnOut) {
          isOutParameter = true;
          isInParameter = false;
        }

        int jdbcType = paramTypesRs.getInt(6);
        String typeName = paramTypesRs.getString(7);
        int precision = paramTypesRs.getInt(8);
        int scale = paramTypesRs.getInt(10);
        short nullability = paramTypesRs.getShort(12);

        CallableStatementParam paramInfoToAdd = new CallableStatementParam(
            paramName, i++, isInParameter, isOutParameter,
            jdbcType, typeName, precision, scale, nullability,
            inOutModifier);

        this.parameterList.add(paramInfoToAdd);
        this.parameterMap.put(paramName, paramInfoToAdd);
      }
    }

    protected void checkBounds(int paramIndex) throws SQLException {
      int localParamIndex = paramIndex - 1;

      if ((paramIndex < 0) || (localParamIndex >= this.numParameters)) {
        throw SQLError.createSQLException(
            Messages.getString("CallableStatement.11") + paramIndex //$NON-NLS-1$
                + Messages.getString("CallableStatement.12") + numParameters //$NON-NLS-1$
                + Messages.getString("CallableStatement.13"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
      }
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#clone()
     */
    protected Object clone() throws CloneNotSupportedException {
      return super.clone();
    }

    CallableStatementParam getParameter(int index) {
      return this.parameterList.get(index);
    }

    CallableStatementParam getParameter(String name) {
      return this.parameterMap.get(name);
    }

    public String getParameterClassName(int arg0) throws SQLException {
      String mysqlTypeName = getParameterTypeName(arg0);
     
      boolean isBinaryOrBlob = StringUtils.indexOfIgnoreCase(mysqlTypeName, "BLOB") != -1 ||
        StringUtils.indexOfIgnoreCase(mysqlTypeName, "BINARY") != -1;
     
      boolean isUnsigned = StringUtils.indexOfIgnoreCase(mysqlTypeName, "UNSIGNED") != -1;
     
      int mysqlTypeIfKnown = 0;
     
      if (StringUtils.startsWithIgnoreCase(mysqlTypeName, "MEDIUMINT")) {
        mysqlTypeIfKnown = MysqlDefs.FIELD_TYPE_INT24;
      }
     
      return ResultSetMetaData.getClassNameForJavaType(getParameterType(arg0),
          isUnsigned, mysqlTypeIfKnown, isBinaryOrBlob, false);
    }

    public int getParameterCount() throws SQLException {
      if (this.parameterList == null) {
        return 0;
      }
     
      return this.parameterList.size();
    }

    public int getParameterMode(int arg0) throws SQLException {
      checkBounds(arg0);

      return getParameter(arg0 - 1).inOutModifier;
    }

    public int getParameterType(int arg0) throws SQLException {
      checkBounds(arg0);

      return getParameter(arg0 - 1).jdbcType;
    }

    public String getParameterTypeName(int arg0) throws SQLException {
      checkBounds(arg0);

      return getParameter(arg0 - 1).typeName;
    }

    public int getPrecision(int arg0) throws SQLException {
      checkBounds(arg0);

      return getParameter(arg0 - 1).precision;
    }

    public int getScale(int arg0) throws SQLException {
      checkBounds(arg0);

      return getParameter(arg0 - 1).scale;
    }

    public int isNullable(int arg0) throws SQLException {
      checkBounds(arg0);

      return getParameter(arg0 - 1).nullability;
    }

    public boolean isSigned(int arg0) throws SQLException {
      checkBounds(arg0);

      return false;
    }

    Iterator<CallableStatementParam> iterator() {
      return this.parameterList.iterator();
    }

    int numberOfParameters() {
      return this.numParameters;
    }
  }

  /**
   * Can't implement this directly, as then you can't use callable statements
   * on JDK-1.3.1, which unfortunately isn't EOL'd yet, and still present
   * quite a bit out there in the wild (Websphere, FreeBSD, anyone?)
   */

  protected class CallableStatementParamInfoJDBC3 extends CallableStatementParamInfo
      implements ParameterMetaData {

    CallableStatementParamInfoJDBC3(java.sql.ResultSet paramTypesRs)
        throws SQLException {
      super(paramTypesRs);
    }

    public CallableStatementParamInfoJDBC3(CallableStatementParamInfo paramInfo) {
      super(paramInfo);
    }
   
    /**
       * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
       * for an object that does. Returns false otherwise. If this implements the interface then return true,
       * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
       * object. If this does not implement the interface and is not a wrapper, return false.
       * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
       * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
       * returns true then calling <code>unwrap</code> with the same argument should succeed.
       *
       * @param interfaces a Class defining an interface.
       * @return true if this implements the interface or directly or indirectly wraps an object that does.
       * @throws java.sql.SQLException  if an error occurs while determining whether this is a wrapper
       * for an object with the given interface.
       * @since 1.6
       */
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
      checkClosed();
     
      // This works for classes that aren't actually wrapping
      // anything
      return iface.isInstance(this);
    }

      /**
       * Returns an object that implements the given interface to allow access to non-standard methods,
       * or standard methods not exposed by the proxy.
       * The result may be either the object found to implement the interface or a proxy for that object.
       * If the receiver implements the interface then that is the object. If the receiver is a wrapper
       * and the wrapped object implements the interface then that is the object. Otherwise the object is
       *  the result of calling <code>unwrap</code> recursively on the wrapped object. If the receiver is not a
       * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
       *
       * @param iface A Class defining an interface that the result must implement.
       * @return an object that implements the interface. May be a proxy for the actual implementing object.
       * @throws java.sql.SQLException If no object found that implements the interface
       * @since 1.6
       */
    public Object unwrap(Class<?> iface) throws java.sql.SQLException {
        try {
          // This works for classes that aren't actually wrapping
          // anything
          return Util.cast(iface, this);
          } catch (ClassCastException cce) {
              throw SQLError.createSQLException("Unable to unwrap to " + iface.toString(),
                  SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
          }
      }
  }

  private final static int NOT_OUTPUT_PARAMETER_INDICATOR = Integer.MIN_VALUE;

  private final static String PARAMETER_NAMESPACE_PREFIX = "@com_mysql_jdbc_outparam_"; //$NON-NLS-1$

  private static String mangleParameterName(String origParameterName) {
    //Fixed for 5.5+ in callers
    if (origParameterName == null) {
      return null;
    }

    int offset = 0;

    if (origParameterName.length() > 0
        && origParameterName.charAt(0) == '@') {
      offset = 1;
    }

    StringBuffer paramNameBuf = new StringBuffer(PARAMETER_NAMESPACE_PREFIX
        .length()
        + origParameterName.length());
    paramNameBuf.append(PARAMETER_NAMESPACE_PREFIX);
    paramNameBuf.append(origParameterName.substring(offset));

    return paramNameBuf.toString();
  }

  private boolean callingStoredFunction = false;

  private ResultSetInternalMethods functionReturnValueResults;

  private boolean hasOutputParams = false;

  // private List parameterList;
  // private Map parameterMap;
  private ResultSetInternalMethods outputParameterResults;

  protected boolean outputParamWasNull = false;

  private int[] parameterIndexToRsIndex;

  protected CallableStatementParamInfo paramInfo;

  private CallableStatementParam returnValueParam;
 
  /**
   * Creates a new CallableStatement
   *
   * @param conn
   *            the connection creating this statement
   * @param paramInfo
   *            the SQL to prepare
   *
   * @throws SQLException
   *             if an error occurs
   */
  public CallableStatement(MySQLConnection conn,
      CallableStatementParamInfo paramInfo) throws SQLException {
    super(conn, paramInfo.nativeSql, paramInfo.catalogInUse);

    this.paramInfo = paramInfo;
    this.callingStoredFunction = this.paramInfo.isFunctionCall;
   
    if (this.callingStoredFunction) {
      this.parameterCount += 1;
    }
   
    this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
  }

  /**
   * Creates a callable statement instance -- We need to provide factory-style methods
   * so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
   * the class verifier complains when it tries to load JDBC4-only interface
   * classes that are present in JDBC4 method signatures.
   */

  protected static CallableStatement getInstance(MySQLConnection conn, String sql,
      String catalog, boolean isFunctionCall) throws SQLException {
    if (!Util.isJdbc4()) {
      return new CallableStatement(conn, sql, catalog, isFunctionCall);
    }

    return (CallableStatement) Util.handleNewInstance(
        JDBC_4_CSTMT_4_ARGS_CTOR, new Object[] { conn, sql, catalog,
            Boolean.valueOf(isFunctionCall) }, conn.getExceptionInterceptor());
  }
 
  /**
   * Creates a callable statement instance -- We need to provide factory-style methods
   * so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
   * the class verifier complains when it tries to load JDBC4-only interface
   * classes that are present in JDBC4 method signatures.
   */

  protected static CallableStatement getInstance(MySQLConnection conn,
      CallableStatementParamInfo paramInfo) throws SQLException {
    if (!Util.isJdbc4()) {
      return new CallableStatement(conn, paramInfo);
    }

    return (CallableStatement) Util.handleNewInstance(
        JDBC_4_CSTMT_2_ARGS_CTOR, new Object[] { conn, paramInfo }, conn.getExceptionInterceptor());

  }
 
  private int[] placeholderToParameterIndexMap;
 
  private void generateParameterMap() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (this.paramInfo == null) {
        return;
      }
     
      // if the user specified some parameters as literals, we need to
      // provide a map from the specified placeholders to the actual
      // parameter numbers
     
      int parameterCountFromMetaData = this.paramInfo.getParameterCount();
     
      // Ignore the first ? if this is a stored function, it doesn't count
     
      if (this.callingStoredFunction) {
        parameterCountFromMetaData--;
      }
     
      if (this.paramInfo != null &&
          this.parameterCount != parameterCountFromMetaData) {
        this.placeholderToParameterIndexMap = new int[this.parameterCount];
       
        int startPos = this.callingStoredFunction ? StringUtils.indexOfIgnoreCase(this.originalSql,
        "SELECT") : StringUtils.indexOfIgnoreCase(this.originalSql, "CALL");
       
        if (startPos != -1) {
          int parenOpenPos = this.originalSql.indexOf('(', startPos + 4);
         
          if (parenOpenPos != -1) {
            int parenClosePos = StringUtils.indexOfIgnoreCaseRespectQuotes(parenOpenPos,
                this.originalSql, ")", '\'', true);
           
            if (parenClosePos != -1) {
              List<?> parsedParameters = StringUtils.split(this.originalSql.substring(parenOpenPos + 1, parenClosePos), ",", "'\"", "'\"", true);
             
              int numParsedParameters = parsedParameters.size();
             
              // sanity check
             
              if (numParsedParameters != this.parameterCount) {
                // bail?
              }
             
              int placeholderCount = 0;
             
              for (int i = 0; i < numParsedParameters; i++) {
                if (((String)parsedParameters.get(i)).equals("?")) {
                  this.placeholderToParameterIndexMap[placeholderCount++] = i;
                }
              }
            }
          }
        }
      }
    }
  }
 
  /**
   * Creates a new CallableStatement
   *
   * @param conn
   *            the connection creating this statement
   * @param sql
   *            the SQL to prepare
   * @param catalog
   *            the current catalog
   *
   * @throws SQLException
   *             if an error occurs
   */
  public CallableStatement(MySQLConnection conn, String sql, String catalog,
      boolean isFunctionCall) throws SQLException {
    super(conn, sql, catalog);

    this.callingStoredFunction = isFunctionCall;

    if (!this.callingStoredFunction) {
      if (!StringUtils.startsWithIgnoreCaseAndWs(sql, "CALL")) {
        // not really a stored procedure call
        fakeParameterTypes(false);
      } else {
        determineParameterTypes();
      }
     
      generateParameterMap();
    } else {
      determineParameterTypes();
      generateParameterMap();
     
      this.parameterCount += 1;
    }
   
    this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
  }

  /*
   * (non-Javadoc)
   *
   * @see java.sql.PreparedStatement#addBatch()
   */
  public void addBatch() throws SQLException {
    setOutParams();

    super.addBatch();
  }

  private CallableStatementParam checkIsOutputParam(int paramIndex)
      throws SQLException {

    synchronized (checkClosed().getConnectionMutex()) {
      if (this.callingStoredFunction) {
        if (paramIndex == 1) {
 
          if (this.returnValueParam == null) {
            this.returnValueParam = new CallableStatementParam("", 0,
                false, true, Types.VARCHAR, "VARCHAR", 0, 0,
                DatabaseMetaData.attributeNullableUnknown,
                DatabaseMetaData.procedureColumnReturn);
          }
 
          return this.returnValueParam;
        }
 
        // Move to position in output result set
        paramIndex--;
      }
 
      checkParameterIndexBounds(paramIndex);
 
      int localParamIndex = paramIndex - 1;
 
      if (this.placeholderToParameterIndexMap != null) {
        localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
      }
     
      CallableStatementParam paramDescriptor = this.paramInfo
          .getParameter(localParamIndex);
 
      // We don't have reliable metadata in this case, trust
      // the caller
     
      if (this.connection.getNoAccessToProcedureBodies()) {
        paramDescriptor.isOut = true;
        paramDescriptor.isIn = true;
        paramDescriptor.inOutModifier = DatabaseMetaData.procedureColumnInOut;
      } else if (!paramDescriptor.isOut) {
        throw SQLError.createSQLException(
            Messages.getString("CallableStatement.9") + paramIndex //$NON-NLS-1$
                + Messages.getString("CallableStatement.10"), //$NON-NLS-1$
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
 
      this.hasOutputParams = true;
 
      return paramDescriptor;
    }
  }

  /**
   * DOCUMENT ME!
   *
   * @param paramIndex
   *
   * @throws SQLException
   */
  private void checkParameterIndexBounds(int paramIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      this.paramInfo.checkBounds(paramIndex);
    }
  }

  /**
   * Checks whether or not this statement is supposed to be providing
   * streamable result sets...If output parameters are registered, the driver
   * can not stream the results.
   *
   * @throws SQLException
   *             DOCUMENT ME!
   */
  private void checkStreamability() throws SQLException {
    if (this.hasOutputParams && createStreamingResultSet()) {
      throw SQLError.createSQLException(Messages.getString("CallableStatement.14"), //$NON-NLS-1$
          SQLError.SQL_STATE_DRIVER_NOT_CAPABLE, getExceptionInterceptor());
    }
  }

  public void clearParameters() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      super.clearParameters();
 
      try {
        if (this.outputParameterResults != null) {
          this.outputParameterResults.close();
        }
      } finally {
        this.outputParameterResults = null;
      }
    }
  }

  /**
   * Used to fake up some metadata when we don't have access to
   * SHOW CREATE PROCEDURE or mysql.proc.
   *
   * @throws SQLException if we can't build the metadata.
   */
  private void fakeParameterTypes(boolean isReallyProcedure) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      Field[] fields = new Field[13];
 
      fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
      fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
      fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
      fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 0);
      fields[4] = new Field("", "COLUMN_TYPE", Types.CHAR, 0);
      fields[5] = new Field("", "DATA_TYPE", Types.SMALLINT, 0);
      fields[6] = new Field("", "TYPE_NAME", Types.CHAR, 0);
      fields[7] = new Field("", "PRECISION", Types.INTEGER, 0);
      fields[8] = new Field("", "LENGTH", Types.INTEGER, 0);
      fields[9] = new Field("", "SCALE", Types.SMALLINT, 0);
      fields[10] = new Field("", "RADIX", Types.SMALLINT, 0);
      fields[11] = new Field("", "NULLABLE", Types.SMALLINT, 0);
      fields[12] = new Field("", "REMARKS", Types.CHAR, 0);
 
      String procName = isReallyProcedure ? extractProcedureName() : null;
 
      byte[] procNameAsBytes = null;
 
      try {
        procNameAsBytes = procName == null ? null : StringUtils.getBytes(procName, "UTF-8");
      } catch (UnsupportedEncodingException ueEx) {
        procNameAsBytes = StringUtils.s2b(procName, this.connection);
      }
 
      ArrayList<ResultSetRow> resultRows = new ArrayList<ResultSetRow>();
 
      for (int i = 0; i < this.parameterCount; i++) {
        byte[][] row = new byte[13][];
        row[0] = null; // PROCEDURE_CAT
        row[1] = null; // PROCEDURE_SCHEM
        row[2] = procNameAsBytes; // PROCEDURE/NAME
        row[3] = StringUtils.s2b(String.valueOf(i), this.connection); // COLUMN_NAME
 
        row[4] = StringUtils.s2b(String
            .valueOf(DatabaseMetaData.procedureColumnIn),
            this.connection);
 
        row[5] = StringUtils.s2b(String.valueOf(Types.VARCHAR),
            this.connection); // DATA_TYPE
        row[6] = StringUtils.s2b("VARCHAR", this.connection); // TYPE_NAME
        row[7] = StringUtils.s2b(Integer.toString(65535), this.connection); // PRECISION
        row[8] = StringUtils.s2b(Integer.toString(65535), this.connection); // LENGTH
        row[9] = StringUtils.s2b(Integer.toString(0), this.connection); // SCALE
        row[10] = StringUtils.s2b(Integer.toString(10), this.connection); // RADIX
 
        row[11] = StringUtils.s2b(Integer
            .toString(DatabaseMetaData.procedureNullableUnknown),
            this.connection); // nullable
 
        row[12] = null;
 
        resultRows.add(new ByteArrayRow(row, getExceptionInterceptor()));
      }
 
      java.sql.ResultSet paramTypesRs = DatabaseMetaData.buildResultSet(
          fields, resultRows, this.connection);
 
      convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);
    }
  }
 
  private void determineParameterTypes() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      java.sql.ResultSet paramTypesRs = null;
 
      try {
        //Bug#57022, we need to check for db.SPname notation first
        //  and pass on only SPname
        String procName = extractProcedureName();
        String quotedId = "";
        try {
          quotedId = this.connection.supportsQuotedIdentifiers() ?
              this.connection.getMetaData().getIdentifierQuoteString()  : "";
        } catch (SQLException sqlEx) {
          // Forced by API, never thrown from getIdentifierQuoteString() in
          // this implementation.
          AssertionFailedException.shouldNotHappen(sqlEx);
        }
       
        List<?> parseList = StringUtils.splitDBdotName(procName, "",
            quotedId , this.connection.isNoBackslashEscapesSet());
        String tmpCatalog = "";
        //There *should* be 2 rows, if any.
        if (parseList.size() == 2) {
          tmpCatalog = (String) parseList.get(0);
          procName = (String) parseList.get(1);     
        } else {
          //keep values as they are
        }
       
        java.sql.DatabaseMetaData dbmd = this.connection.getMetaData();
 
        boolean useCatalog = false;
 
        if (tmpCatalog.length() <= 0) {
          useCatalog = true;
        }
       
        paramTypesRs = dbmd.getProcedureColumns(this.connection
            .versionMeetsMinimum(5, 0, 2)
            && useCatalog ? this.currentCatalog : tmpCatalog/*null*/, null, procName,
            "%"); //$NON-NLS-1$
       
        boolean hasResults = false;
        try {
          if (paramTypesRs.next()) {
            paramTypesRs.previous();
            hasResults = true;
          }
        } catch (Exception e) {
          // paramTypesRs is empty, proceed with fake params. swallow, was expected
        }
        if (hasResults){
          convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);
        } else {
          fakeParameterTypes(true);
        }
      } finally {
        SQLException sqlExRethrow = null;
 
        if (paramTypesRs != null) {
          try {
            paramTypesRs.close();
          } catch (SQLException sqlEx) {
            sqlExRethrow = sqlEx;
          }
 
          paramTypesRs = null;
        }
 
        if (sqlExRethrow != null) {
          throw sqlExRethrow;
        }
      }
    }
  }

  private void convertGetProcedureColumnsToInternalDescriptors(java.sql.ResultSet paramTypesRs) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (!this.connection.isRunningOnJDK13()) {
        this.paramInfo = new CallableStatementParamInfoJDBC3(
            paramTypesRs);
      } else {
        this.paramInfo = new CallableStatementParamInfo(paramTypesRs);
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see java.sql.PreparedStatement#execute()
   */
  public boolean execute() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      boolean returnVal = false;

      checkStreamability();

      setInOutParamsOnServer();
      setOutParams();

      returnVal = super.execute();

      if (this.callingStoredFunction) {
        this.functionReturnValueResults = this.results;
        this.functionReturnValueResults.next();
        this.results = null;
      }

      retrieveOutParams();
   

      if (!this.callingStoredFunction) {
        return returnVal;
      }
 
      // Functions can't return results
      return false;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see java.sql.PreparedStatement#executeQuery()
   */
  public java.sql.ResultSet executeQuery() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {

      checkStreamability();
 
      java.sql.ResultSet execResults = null;

      setInOutParamsOnServer();
      setOutParams();

      execResults = super.executeQuery();

      retrieveOutParams();
     
      return execResults;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see java.sql.PreparedStatement#executeUpdate()
   */
  public int executeUpdate() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      int returnVal = -1;
 
     
      checkStreamability();
 
      if (this.callingStoredFunction) {
        execute();
 
        return -1;
      }

      setInOutParamsOnServer();
      setOutParams();

      returnVal = super.executeUpdate();

      retrieveOutParams();

      return returnVal;
    }
  }

  private String extractProcedureName() throws SQLException {
    String sanitizedSql = StringUtils.stripComments(this.originalSql,
        "`\"'", "`\"'", true, false, true, true);
   
    // TODO: Do this with less memory allocation
    int endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql,
        "CALL "); //$NON-NLS-1$
    int offset = 5;

    if (endCallIndex == -1) {
      endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql,
          "SELECT ");
      offset = 7;
    }

    if (endCallIndex != -1) {
      StringBuffer nameBuf = new StringBuffer();

      String trimmedStatement = sanitizedSql.substring(
          endCallIndex + offset).trim();

      int statementLength = trimmedStatement.length();

      for (int i = 0; i < statementLength; i++) {
        char c = trimmedStatement.charAt(i);

        if (Character.isWhitespace(c) || (c == '(') || (c == '?')) {
          break;
        }
        nameBuf.append(c);

      }

      return nameBuf.toString();
    }
   
    throw SQLError.createSQLException(Messages.getString("CallableStatement.1"), //$NON-NLS-1$
        SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
  }

  /**
   * Adds 'at' symbol to beginning of parameter names if needed.
   *
   * @param paramNameIn
   *            the parameter name to 'fix'
   *
   * @return the parameter name with an 'a' prepended, if needed
   *
   * @throws SQLException
   *             if the parameter name is null or empty.
   */
  protected String fixParameterName(String paramNameIn) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      //Fixed for 5.5+
      if (((paramNameIn == null) || (paramNameIn.length() == 0)) && (!hasParametersView())) {
        throw SQLError.createSQLException(
            ((Messages.getString("CallableStatement.0") + paramNameIn) == null) //$NON-NLS-1$
                ? Messages.getString("CallableStatement.15") : Messages.getString("CallableStatement.16"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
                    getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
      }
 
      if ((paramNameIn == null) && (hasParametersView())) {
        paramNameIn = "nullpn";
      };
 
      if (this.connection.getNoAccessToProcedureBodies()) {
        throw SQLError.createSQLException("No access to parameters by name when connection has been configured not to access procedure bodies",
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
     
      return mangleParameterName(paramNameIn);
    }
  }

  /**
   * @see java.sql.CallableStatement#getArray(int)
   */
  public Array getArray(int i) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(i);
 
      Array retValue = rs.getArray(mapOutputParameterIndexToRsIndex(i));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getArray(java.lang.String)
   */
  public Array getArray(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Array retValue = rs.getArray(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBigDecimal(int)
   */
  public BigDecimal getBigDecimal(int parameterIndex)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      BigDecimal retValue = rs
          .getBigDecimal(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * DOCUMENT ME!
   *
   * @param parameterIndex
   *            DOCUMENT ME!
   * @param scale
   *            DOCUMENT ME!
   *
   * @return DOCUMENT ME!
   *
   * @throws SQLException
   *             DOCUMENT ME!
   *
   * @see java.sql.CallableStatement#getBigDecimal(int, int)
   * @deprecated
   */
  public BigDecimal getBigDecimal(int parameterIndex, int scale)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      BigDecimal retValue = rs.getBigDecimal(
          mapOutputParameterIndexToRsIndex(parameterIndex), scale);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBigDecimal(java.lang.String)
   */
  public BigDecimal getBigDecimal(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      BigDecimal retValue = rs.getBigDecimal(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBlob(int)
   */
  public Blob getBlob(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Blob retValue = rs
          .getBlob(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBlob(java.lang.String)
   */
  public Blob getBlob(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Blob retValue = rs.getBlob(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBoolean(int)
   */
  public boolean getBoolean(int parameterIndex)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      boolean retValue = rs
          .getBoolean(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBoolean(java.lang.String)
   */
  public boolean getBoolean(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      boolean retValue = rs.getBoolean(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getByte(int)
   */
  public byte getByte(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      byte retValue = rs
          .getByte(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getByte(java.lang.String)
   */
  public byte getByte(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      byte retValue = rs.getByte(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBytes(int)
   */
  public byte[] getBytes(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      byte[] retValue = rs
          .getBytes(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getBytes(java.lang.String)
   */
  public byte[] getBytes(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      byte[] retValue = rs.getBytes(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getClob(int)
   */
  public Clob getClob(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Clob retValue = rs
          .getClob(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getClob(java.lang.String)
   */
  public Clob getClob(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Clob retValue = rs.getClob(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getDate(int)
   */
  public Date getDate(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Date retValue = rs
          .getDate(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getDate(int, java.util.Calendar)
   */
  public Date getDate(int parameterIndex, Calendar cal)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Date retValue = rs.getDate(
          mapOutputParameterIndexToRsIndex(parameterIndex), cal);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getDate(java.lang.String)
   */
  public Date getDate(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Date retValue = rs.getDate(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getDate(java.lang.String,
   *      java.util.Calendar)
   */
  public Date getDate(String parameterName, Calendar cal)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Date retValue = rs.getDate(fixParameterName(parameterName), cal);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getDouble(int)
   */
  public double getDouble(int parameterIndex)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      double retValue = rs
          .getDouble(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getDouble(java.lang.String)
   */
  public double getDouble(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      double retValue = rs.getDouble(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getFloat(int)
   */
  public float getFloat(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      float retValue = rs
          .getFloat(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getFloat(java.lang.String)
   */
  public float getFloat(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      float retValue = rs.getFloat(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getInt(int)
   */
  public int getInt(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      int retValue = rs
          .getInt(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getInt(java.lang.String)
   */
  public int getInt(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      int retValue = rs.getInt(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getLong(int)
   */
  public long getLong(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      long retValue = rs
          .getLong(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getLong(java.lang.String)
   */
  public long getLong(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      long retValue = rs.getLong(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  protected int getNamedParamIndex(String paramName, boolean forOut)
  throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (this.connection.getNoAccessToProcedureBodies()) {
        throw SQLError.createSQLException("No access to parameters by name when connection has been configured not to access procedure bodies",
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
     
      //Fixed for 5.5+ in callers
      if ((paramName == null) || (paramName.length() == 0)) {
        throw SQLError.createSQLException(Messages.getString("CallableStatement.2"), //$NON-NLS-1$
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
 
      if (this.paramInfo == null) {
        throw SQLError.createSQLException(
            Messages.getString("CallableStatement.3") + paramName + Messages.getString("CallableStatement.4"), //$NON-NLS-1$ //$NON-NLS-2$
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
 
      CallableStatementParam namedParamInfo = this.paramInfo
        .getParameter(paramName);
 
      if (forOut && !namedParamInfo.isOut) {
        throw SQLError.createSQLException(
            Messages.getString("CallableStatement.5") + paramName //$NON-NLS-1$
            + Messages.getString("CallableStatement.6"), //$NON-NLS-1$
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
 
 
      if (this.placeholderToParameterIndexMap == null) {
        return namedParamInfo.index + 1; // JDBC indices are 1-based
      }
 
      for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
        if (this.placeholderToParameterIndexMap[i] == namedParamInfo.index) {
          return i + 1;
        }
      }
 
      throw SQLError.createSQLException("Can't find local placeholder mapping for parameter named \"" +
          paramName + "\".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
    }
  }

  /**
   * @see java.sql.CallableStatement#getObject(int)
   */
  public Object getObject(int parameterIndex)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      CallableStatementParam paramDescriptor = checkIsOutputParam(parameterIndex);
 
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Object retVal = rs.getObjectStoredProc(
          mapOutputParameterIndexToRsIndex(parameterIndex),
          paramDescriptor.desiredJdbcType);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retVal;
    }
  }

  /**
   * @see java.sql.CallableStatement#getObject(int, java.util.Map)
   */
  public Object getObject(int parameterIndex, Map<String, Class<?>> map)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Object retVal = rs.getObject(
          mapOutputParameterIndexToRsIndex(parameterIndex), map);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retVal;
    }
  }

  /**
   * @see java.sql.CallableStatement#getObject(java.lang.String)
   */
  public Object getObject(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Object retValue = rs.getObject(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getObject(java.lang.String,
   *      java.util.Map)
   */
  public Object getObject(String parameterName, Map<String, Class<?>> map)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Object retValue = rs.getObject(fixParameterName(parameterName), map);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }
 
  // JDBC-4.1
  public <T> T getObject(int parameterIndex, Class<T> type) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      // remove cast once 1.5, 1.6 EOL'd
      T retVal = ((ResultSetImpl)rs).getObject(
          mapOutputParameterIndexToRsIndex(parameterIndex), type);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retVal;
    }
  }
 
  public <T> T getObject(String parameterName, Class<T> type) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      T retValue = ((ResultSetImpl)rs).getObject(fixParameterName(parameterName), type);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * Returns the ResultSet that holds the output parameters, or throws an
   * appropriate exception if none exist, or they weren't returned.
   *
   * @return the ResultSet that holds the output parameters
   *
   * @throws SQLException
   *             if no output parameters were defined, or if no output
   *             parameters were returned.
   */
  protected ResultSetInternalMethods getOutputParameters(int paramIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      this.outputParamWasNull = false;
 
      if (paramIndex == 1 && this.callingStoredFunction
          && this.returnValueParam != null) {
        return this.functionReturnValueResults;
      }
 
      if (this.outputParameterResults == null) {
        if (this.paramInfo.numberOfParameters() == 0) {
          throw SQLError.createSQLException(Messages
              .getString("CallableStatement.7"), //$NON-NLS-1$
              SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
        }
        throw SQLError.createSQLException(Messages.getString("CallableStatement.8"), //$NON-NLS-1$
            SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
      }
 
      return this.outputParameterResults;
    }
  }

  public ParameterMetaData getParameterMetaData()
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (this.placeholderToParameterIndexMap == null) {
        return (CallableStatementParamInfoJDBC3) this.paramInfo;
      }
       
      return new CallableStatementParamInfoJDBC3(this.paramInfo);
    }
  }

  /**
   * @see java.sql.CallableStatement#getRef(int)
   */
  public Ref getRef(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Ref retValue = rs
          .getRef(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getRef(java.lang.String)
   */
  public Ref getRef(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Ref retValue = rs.getRef(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getShort(int)
   */
  public short getShort(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      short retValue = rs
          .getShort(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getShort(java.lang.String)
   */
  public short getShort(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      short retValue = rs.getShort(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getString(int)
   */
  public String getString(int parameterIndex)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      String retValue = rs
          .getString(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getString(java.lang.String)
   */
  public String getString(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      String retValue = rs.getString(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTime(int)
   */
  public Time getTime(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Time retValue = rs
          .getTime(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTime(int, java.util.Calendar)
   */
  public Time getTime(int parameterIndex, Calendar cal)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Time retValue = rs.getTime(
          mapOutputParameterIndexToRsIndex(parameterIndex), cal);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTime(java.lang.String)
   */
  public Time getTime(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Time retValue = rs.getTime(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTime(java.lang.String,
   *      java.util.Calendar)
   */
  public Time getTime(String parameterName, Calendar cal)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Time retValue = rs.getTime(fixParameterName(parameterName), cal);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTimestamp(int)
   */
  public Timestamp getTimestamp(int parameterIndex)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Timestamp retValue = rs
          .getTimestamp(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTimestamp(int, java.util.Calendar)
   */
  public Timestamp getTimestamp(int parameterIndex, Calendar cal)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      Timestamp retValue = rs.getTimestamp(
          mapOutputParameterIndexToRsIndex(parameterIndex), cal);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTimestamp(java.lang.String)
   */
  public Timestamp getTimestamp(String parameterName)
      throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Timestamp retValue = rs.getTimestamp(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getTimestamp(java.lang.String,
   *      java.util.Calendar)
   */
  public Timestamp getTimestamp(String parameterName,
      Calendar cal) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      Timestamp retValue = rs.getTimestamp(fixParameterName(parameterName),
          cal);
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getURL(int)
   */
  public URL getURL(int parameterIndex) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
 
      URL retValue = rs
          .getURL(mapOutputParameterIndexToRsIndex(parameterIndex));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  /**
   * @see java.sql.CallableStatement#getURL(java.lang.String)
   */
  public URL getURL(String parameterName) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
      // from ?=
 
      URL retValue = rs.getURL(fixParameterName(parameterName));
 
      this.outputParamWasNull = rs.wasNull();
 
      return retValue;
    }
  }

  protected int mapOutputParameterIndexToRsIndex(int paramIndex)
      throws SQLException {

    synchronized (checkClosed().getConnectionMutex()) {
      if (this.returnValueParam != null && paramIndex == 1) {
        return 1;
      }
 
      checkParameterIndexBounds(paramIndex);
 
      int localParamIndex = paramIndex - 1;
 
      if (this.placeholderToParameterIndexMap != null) {
        localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
      }
 
      int rsIndex = this.parameterIndexToRsIndex[localParamIndex];
 
      if (rsIndex == NOT_OUTPUT_PARAMETER_INDICATOR) {
        throw SQLError.createSQLException(
            Messages.getString("CallableStatement.21") + paramIndex //$NON-NLS-1$
                + Messages.getString("CallableStatement.22"), //$NON-NLS-1$
            SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
      }
 
      return rsIndex + 1;
    }
  }

  /**
   * @see java.sql.CallableStatement#registerOutParameter(int, int)
   */
  public void registerOutParameter(int parameterIndex, int sqlType)
      throws SQLException {
    CallableStatementParam paramDescriptor = checkIsOutputParam(parameterIndex);
    paramDescriptor.desiredJdbcType = sqlType;
  }

  /**
   * @see java.sql.CallableStatement#registerOutParameter(int, int, int)
   */
  public void registerOutParameter(int parameterIndex, int sqlType, int scale)
      throws SQLException {
    registerOutParameter(parameterIndex, sqlType);
  }

  /**
   * @see java.sql.CallableStatement#registerOutParameter(int, int,
   *      java.lang.String)
   */
  public void registerOutParameter(int parameterIndex, int sqlType,
      String typeName) throws SQLException {
    checkIsOutputParam(parameterIndex);
  }

  /**
   * @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
   *      int)
   */
  public void registerOutParameter(String parameterName,
      int sqlType) throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      registerOutParameter(getNamedParamIndex(parameterName, true), sqlType);
    }
  }

  /**
   * @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
   *      int, int)
   */
  public void registerOutParameter(String parameterName, int sqlType,
      int scale) throws SQLException {
    registerOutParameter(getNamedParamIndex(parameterName, true), sqlType);
  }

  /**
   * @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
   *      int, java.lang.String)
   */
  public void registerOutParameter(String parameterName, int sqlType,
      String typeName) throws SQLException {
    registerOutParameter(getNamedParamIndex(parameterName, true), sqlType,
        typeName);
  }

  /**
   * Issues a second query to retrieve all output parameters.
   *
   * @throws SQLException
   *             if an error occurs.
   */
  private void retrieveOutParams() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      int numParameters = this.paramInfo.numberOfParameters();
 
      this.parameterIndexToRsIndex = new int[numParameters];
 
      for (int i = 0; i < numParameters; i++) {
        this.parameterIndexToRsIndex[i] = NOT_OUTPUT_PARAMETER_INDICATOR;
      }
 
      int localParamIndex = 0;
 
      if (numParameters > 0) {
        StringBuffer outParameterQuery = new StringBuffer("SELECT "); //$NON-NLS-1$
 
        boolean firstParam = true;
        boolean hadOutputParams = false;
 
        for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
            .hasNext();) {
          CallableStatementParam retrParamInfo = paramIter
              .next();
 
          if (retrParamInfo.isOut) {
            hadOutputParams = true;
 
            this.parameterIndexToRsIndex[retrParamInfo.index] = localParamIndex++;
 
            if ((retrParamInfo.paramName == null) && (hasParametersView())) {
              retrParamInfo.paramName = "nullnp" + retrParamInfo.index;
            }
           
            String outParameterName = mangleParameterName(retrParamInfo.paramName);
 
            if (!firstParam) {
              outParameterQuery.append(","); //$NON-NLS-1$
            } else {
              firstParam = false;
            }
 
            if (!outParameterName.startsWith("@")) { //$NON-NLS-1$
              outParameterQuery.append('@');
            }
 
            outParameterQuery.append(outParameterName);
          }
        }
 
        if (hadOutputParams) {
          // We can't use 'ourself' to execute this query, or any
          // pending result sets would be overwritten
          java.sql.Statement outParameterStmt = null;
          java.sql.ResultSet outParamRs = null;
 
          try {
            outParameterStmt = this.connection.createStatement();
            outParamRs = outParameterStmt
                .executeQuery(outParameterQuery.toString());
            this.outputParameterResults = ((com.mysql.jdbc.ResultSetInternalMethods) outParamRs)
                .copy();
 
            if (!this.outputParameterResults.next()) {
              this.outputParameterResults.close();
              this.outputParameterResults = null;
            }
          } finally {
            if (outParameterStmt != null) {
              outParameterStmt.close();
            }
          }
        } else {
          this.outputParameterResults = null;
        }
      } else {
        this.outputParameterResults = null;
      }
    }
  }

  /**
   * @see java.sql.CallableStatement#setAsciiStream(java.lang.String,
   *      java.io.InputStream, int)
   */
  public void setAsciiStream(String parameterName, InputStream x, int length)
      throws SQLException {
    setAsciiStream(getNamedParamIndex(parameterName, false), x, length);
  }

  /**
   * @see java.sql.CallableStatement#setBigDecimal(java.lang.String,
   *      java.math.BigDecimal)
   */
  public void setBigDecimal(String parameterName, BigDecimal x)
      throws SQLException {
    setBigDecimal(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setBinaryStream(java.lang.String,
   *      java.io.InputStream, int)
   */
  public void setBinaryStream(String parameterName, InputStream x, int length)
      throws SQLException {
    setBinaryStream(getNamedParamIndex(parameterName, false), x, length);
  }

  /**
   * @see java.sql.CallableStatement#setBoolean(java.lang.String, boolean)
   */
  public void setBoolean(String parameterName, boolean x) throws SQLException {
    setBoolean(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setByte(java.lang.String, byte)
   */
  public void setByte(String parameterName, byte x) throws SQLException {
    setByte(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setBytes(java.lang.String, byte[])
   */
  public void setBytes(String parameterName, byte[] x) throws SQLException {
    setBytes(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setCharacterStream(java.lang.String,
   *      java.io.Reader, int)
   */
  public void setCharacterStream(String parameterName, Reader reader,
      int length) throws SQLException {
    setCharacterStream(getNamedParamIndex(parameterName, false), reader,
        length);
  }

  /**
   * @see java.sql.CallableStatement#setDate(java.lang.String, java.sql.Date)
   */
  public void setDate(String parameterName, Date x) throws SQLException {
    setDate(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setDate(java.lang.String, java.sql.Date,
   *      java.util.Calendar)
   */
  public void setDate(String parameterName, Date x, Calendar cal)
      throws SQLException {
    setDate(getNamedParamIndex(parameterName, false), x, cal);
  }

  /**
   * @see java.sql.CallableStatement#setDouble(java.lang.String, double)
   */
  public void setDouble(String parameterName, double x) throws SQLException {
    setDouble(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setFloat(java.lang.String, float)
   */
  public void setFloat(String parameterName, float x) throws SQLException {
    setFloat(getNamedParamIndex(parameterName, false), x);
  }

  /**
   *
   */
  private void setInOutParamsOnServer() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (this.paramInfo.numParameters > 0) {
        for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
            .hasNext();) {
 
          CallableStatementParam inParamInfo = paramIter
              .next();
 
          //Fix for 5.5+
          if (inParamInfo.isOut && inParamInfo.isIn) {
            if ((inParamInfo.paramName == null) && (hasParametersView())) {
              inParamInfo.paramName = "nullnp" + inParamInfo.index;
            };
           
            String inOutParameterName = mangleParameterName(inParamInfo.paramName);
            StringBuffer queryBuf = new StringBuffer(
                4 + inOutParameterName.length() + 1 + 1);
            queryBuf.append("SET "); //$NON-NLS-1$
            queryBuf.append(inOutParameterName);
            queryBuf.append("=?"); //$NON-NLS-1$
 
            PreparedStatement setPstmt = null;
 
            try {
              setPstmt = (PreparedStatement) this.connection
                  .clientPrepareStatement(queryBuf.toString());
 
              if (this.isNull[inParamInfo.index]) {
                setPstmt.setBytesNoEscapeNoQuotes(1, "NULL".getBytes());
               
              } else {
                byte[] parameterAsBytes = getBytesRepresentation(
                    inParamInfo.index);
   
                if (parameterAsBytes != null) {
                  if (parameterAsBytes.length > 8
                      && parameterAsBytes[0] == '_'
                      && parameterAsBytes[1] == 'b'
                      && parameterAsBytes[2] == 'i'
                      && parameterAsBytes[3] == 'n'
                      && parameterAsBytes[4] == 'a'
                      && parameterAsBytes[5] == 'r'
                      && parameterAsBytes[6] == 'y'
                      && parameterAsBytes[7] == '\'') {
                    setPstmt.setBytesNoEscapeNoQuotes(1,
                        parameterAsBytes);
                  } else {
                    int sqlType = inParamInfo.desiredJdbcType;
                   
                    switch (sqlType) {
                    case Types.BIT:
                    case Types.BINARY:
                    case Types.BLOB:
                    case Types.JAVA_OBJECT:
                    case Types.LONGVARBINARY:
                    case Types.VARBINARY:
                      setPstmt.setBytes(1, parameterAsBytes);
                      break;
                    default:
                      // the inherited PreparedStatement methods
                      // have already escaped and quoted these parameters
                      setPstmt.setBytesNoEscape(1, parameterAsBytes);
                    }
                  }
                } else {
                  setPstmt.setNull(1, Types.NULL);
                }
              }
 
              setPstmt.executeUpdate();
            } finally {
              if (setPstmt != null) {
                setPstmt.close();
              }
            }
          }
        }
      }
    }
  }

  /**
   * @see java.sql.CallableStatement#setInt(java.lang.String, int)
   */
  public void setInt(String parameterName, int x) throws SQLException {
    setInt(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setLong(java.lang.String, long)
   */
  public void setLong(String parameterName, long x) throws SQLException {
    setLong(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setNull(java.lang.String, int)
   */
  public void setNull(String parameterName, int sqlType) throws SQLException {
    setNull(getNamedParamIndex(parameterName, false), sqlType);
  }

  /**
   * @see java.sql.CallableStatement#setNull(java.lang.String, int,
   *      java.lang.String)
   */
  public void setNull(String parameterName, int sqlType, String typeName)
      throws SQLException {
    setNull(getNamedParamIndex(parameterName, false), sqlType, typeName);
  }

  /**
   * @see java.sql.CallableStatement#setObject(java.lang.String,
   *      java.lang.Object)
   */
  public void setObject(String parameterName, Object x) throws SQLException {
    setObject(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setObject(java.lang.String,
   *      java.lang.Object, int)
   */
  public void setObject(String parameterName, Object x, int targetSqlType)
      throws SQLException {
    setObject(getNamedParamIndex(parameterName, false), x, targetSqlType);
  }

  /**
   * @see java.sql.CallableStatement#setObject(java.lang.String,
   *      java.lang.Object, int, int)
   */
  public void setObject(String parameterName, Object x, int targetSqlType,
      int scale) throws SQLException {
  }

  private void setOutParams() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (this.paramInfo.numParameters > 0) {
        for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
            .hasNext();) {
          CallableStatementParam outParamInfo = paramIter
              .next();
 
          if (!this.callingStoredFunction && outParamInfo.isOut) {
 
            if ((outParamInfo.paramName == null) && (hasParametersView())) {
              outParamInfo.paramName = "nullnp" + outParamInfo.index;
            };
 
            String outParameterName = mangleParameterName(outParamInfo.paramName);
 
            int outParamIndex = 0;
           
            if (this.placeholderToParameterIndexMap == null) {
                outParamIndex = outParamInfo.index + 1;
            } else {
                // Find it, todo: remove this linear search
                boolean found = false;
               
                for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
                  if (this.placeholderToParameterIndexMap[i] == outParamInfo.index) {
                    outParamIndex = i + 1; /* JDBC is 1-based */
                    found = true;
                    break;
                  }
                }
               
                if (!found) {
                  throw SQLError.createSQLException("boo!", "S1000", this.connection.getExceptionInterceptor());
                }
            }
           
            this.setBytesNoEscapeNoQuotes(outParamIndex,
                StringUtils.getBytes(outParameterName,
                    this.charConverter, this.charEncoding,
                    this.connection
                        .getServerCharacterEncoding(),
                    this.connection.parserKnowsUnicode(), getExceptionInterceptor()));
          }
        }
      }
    }
  }

  /**
   * @see java.sql.CallableStatement#setShort(java.lang.String, short)
   */
  public void setShort(String parameterName, short x) throws SQLException {
    setShort(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setString(java.lang.String,
   *      java.lang.String)
   */
  public void setString(String parameterName, String x) throws SQLException {
    setString(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setTime(java.lang.String, java.sql.Time)
   */
  public void setTime(String parameterName, Time x) throws SQLException {
    setTime(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setTime(java.lang.String, java.sql.Time,
   *      java.util.Calendar)
   */
  public void setTime(String parameterName, Time x, Calendar cal)
      throws SQLException {
    setTime(getNamedParamIndex(parameterName, false), x, cal);
  }

  /**
   * @see java.sql.CallableStatement#setTimestamp(java.lang.String,
   *      java.sql.Timestamp)
   */
  public void setTimestamp(String parameterName, Timestamp x)
      throws SQLException {
    setTimestamp(getNamedParamIndex(parameterName, false), x);
  }

  /**
   * @see java.sql.CallableStatement#setTimestamp(java.lang.String,
   *      java.sql.Timestamp, java.util.Calendar)
   */
  public void setTimestamp(String parameterName, Timestamp x, Calendar cal)
      throws SQLException {
    setTimestamp(getNamedParamIndex(parameterName, false), x, cal);
  }

  /**
   * @see java.sql.CallableStatement#setURL(java.lang.String, java.net.URL)
   */
  public void setURL(String parameterName, URL val) throws SQLException {
    setURL(getNamedParamIndex(parameterName, false), val);
  }

  /**
   * @see java.sql.CallableStatement#wasNull()
   */
  public boolean wasNull() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      return this.outputParamWasNull;
    }
  }

  public int[] executeBatch() throws SQLException {
    if (this.hasOutputParams) {
      throw SQLError.createSQLException("Can't call executeBatch() on CallableStatement with OUTPUT parameters",
          SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
    }
   
    return super.executeBatch();
  }

  protected int getParameterIndexOffset() {
    if (this.callingStoredFunction) {
      return -1;
    }
   
    return super.getParameterIndexOffset();
  }
 
  public void setAsciiStream(String parameterName, InputStream x) throws SQLException {
    setAsciiStream(getNamedParamIndex(parameterName, false), x);
   
  }

  public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {
    setAsciiStream(getNamedParamIndex(parameterName, false), x, length);
   
  }

  public void setBinaryStream(String parameterName, InputStream x) throws SQLException {
    setBinaryStream(getNamedParamIndex(parameterName, false), x);
   
  }

  public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {
    setBinaryStream(getNamedParamIndex(parameterName, false), x, length);
   
  }

  public void setBlob(String parameterName, Blob x) throws SQLException {
    setBlob(getNamedParamIndex(parameterName, false), x);
   
  }

  public void setBlob(String parameterName, InputStream inputStream) throws SQLException {
    setBlob(getNamedParamIndex(parameterName, false), inputStream);
   
  }

  public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {
    setBlob(getNamedParamIndex(parameterName, false), inputStream, length);
   
  }

  public void setCharacterStream(String parameterName, Reader reader) throws SQLException {
    setCharacterStream(getNamedParamIndex(parameterName, false), reader);
   
  }

  public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {
    setCharacterStream(getNamedParamIndex(parameterName, false), reader, length);
   
  }

  public void setClob(String parameterName, Clob x) throws SQLException {
    setClob(getNamedParamIndex(parameterName, false), x);
   
  }

  public void setClob(String parameterName, Reader reader) throws SQLException {
    setClob(getNamedParamIndex(parameterName, false), reader);
   
  }

  public void setClob(String parameterName, Reader reader, long length) throws SQLException {
    setClob(getNamedParamIndex(parameterName, false), reader, length);
   
  }

  public void setNCharacterStream(String parameterName, Reader value) throws SQLException {
    setNCharacterStream(getNamedParamIndex(parameterName, false), value);
   
  }

  public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {
    setNCharacterStream(getNamedParamIndex(parameterName, false), value, length);
   
  }
 
  /**
   * Check whether the stored procedure alters any data or is safe for read-only usage.
   *
   * @return true if procedure does not alter data
   * @throws SQLException
   */
  private boolean checkReadOnlyProcedure() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      if (this.connection.getNoAccessToProcedureBodies()) {
        return false;
      }

      if (this.paramInfo.isReadOnlySafeChecked) {
        return this.paramInfo.isReadOnlySafeProcedure;
      }

      ResultSet rs = null;
      java.sql.PreparedStatement ps = null;
     
      try {
        String procName = extractProcedureName();

        String catalog = this.currentCatalog;

        if (procName.indexOf(".") != -1) {
          catalog = procName.substring(0, procName.indexOf("."));
         
          if (StringUtils.startsWithIgnoreCaseAndWs(catalog, "`") && catalog.trim().endsWith("`")) {
            catalog = catalog.substring(1, catalog.length() - 1);
          }
         
          procName = procName.substring(procName.indexOf(".") + 1);
          procName = StringUtils.toString(StringUtils.stripEnclosure(
              StringUtils.getBytes(procName), "`", "`"));
        }
        ps = this.connection
            .prepareStatement("SELECT SQL_DATA_ACCESS FROM "
                + " information_schema.routines "
                + " WHERE routine_schema = ? "
                + " AND routine_name = ?");
        ps.setMaxRows(0);
        ps.setFetchSize(0);

        ps.setString(1, catalog);
        ps.setString(2, procName);
        rs = ps.executeQuery();
        if (rs.next()) {
          String sqlDataAccess = rs.getString(1);
          if ("READS SQL DATA".equalsIgnoreCase(sqlDataAccess)
              || "NO SQL".equalsIgnoreCase(sqlDataAccess)) {
            synchronized (this.paramInfo) {
              this.paramInfo.isReadOnlySafeChecked = true;
              this.paramInfo.isReadOnlySafeProcedure = true;
            }
            return true;
          }
        }
      } catch (SQLException e) {
        // swallow the Exception
      } finally {
        if(rs != null){
          rs.close();
        }
        if(ps != null){
          ps.close();
        }
       
      }
      this.paramInfo.isReadOnlySafeChecked = false;
      this.paramInfo.isReadOnlySafeProcedure = false;
    }
    return false;
         
  }

  protected boolean checkReadOnlySafeStatement() throws SQLException {
    return (super.checkReadOnlySafeStatement() || this.checkReadOnlyProcedure());
  }
 
  private boolean hasParametersView() throws SQLException {
    synchronized (checkClosed().getConnectionMutex()) {
      try {
        if (this.connection.versionMeetsMinimum(5, 5, 0)) {
          java.sql.DatabaseMetaData dbmd1 = new DatabaseMetaDataUsingInfoSchema(this.connection, this.connection.getCatalog());
          return ((DatabaseMetaDataUsingInfoSchema)dbmd1).gethasParametersView();
        }
         
        return false;
      } catch (SQLException e) {
        return false;
      }
    }
  }
}
TOP

Related Classes of com.mysql.jdbc.CallableStatement$CallableStatementParamInfoJDBC3

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.