source: Ballon/out/artifacts/geisa_artifact/WEB-INF/lib/mysql-connector-java-5.1.21/src/com/mysql/jdbc/CallableStatement.java @ 848

Last change on this file since 848 was 766, checked in by npipsl, 11 years ago
File size: 74.8 KB
Line 
1/*
2  Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
3
4  The MySQL Connector/J is licensed under the terms of the GPLv2
5  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
6  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
7  this software, see the FLOSS License Exception
8  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
9
10  This program is free software; you can redistribute it and/or modify it under the terms
11  of the GNU General Public License as published by the Free Software Foundation; version 2
12  of the License.
13
14  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  See the GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License along with this
19  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
20  Floor, Boston, MA 02110-1301  USA
21 
22 */
23package com.mysql.jdbc;
24
25import java.io.InputStream;
26import java.io.Reader;
27import java.io.UnsupportedEncodingException;
28import java.lang.reflect.Constructor;
29import java.math.BigDecimal;
30import java.net.URL;
31import java.sql.Array;
32import java.sql.Blob;
33import java.sql.Clob;
34import java.sql.Date;
35import java.sql.ParameterMetaData;
36import java.sql.Ref;
37import java.sql.ResultSet;
38import java.sql.SQLException;
39import java.sql.Time;
40import java.sql.Timestamp;
41import java.sql.Types;
42import java.util.ArrayList;
43import java.util.Calendar;
44import java.util.HashMap;
45import java.util.Iterator;
46import java.util.List;
47import java.util.Map;
48
49/**
50 * Representation of stored procedures for JDBC
51 *
52 * @author Mark Matthews
53 * @version $Id: CallableStatement.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
54 *          Exp $
55 */
56public class CallableStatement extends PreparedStatement implements
57                java.sql.CallableStatement {
58        protected final static Constructor<?> JDBC_4_CSTMT_2_ARGS_CTOR;
59       
60        protected final static Constructor<?> JDBC_4_CSTMT_4_ARGS_CTOR;
61       
62        static {
63                if (Util.isJdbc4()) {
64                        try {
65                                JDBC_4_CSTMT_2_ARGS_CTOR = Class.forName(
66                                                "com.mysql.jdbc.JDBC4CallableStatement")
67                                                .getConstructor(
68                                                                new Class[] { MySQLConnection.class,
69                                                                                CallableStatementParamInfo.class });
70                                JDBC_4_CSTMT_4_ARGS_CTOR = Class.forName(
71                                                "com.mysql.jdbc.JDBC4CallableStatement")
72                                                .getConstructor(
73                                                                new Class[] { MySQLConnection.class,
74                                                                                String.class, String.class,
75                                                                                Boolean.TYPE });
76                        } catch (SecurityException e) {
77                                throw new RuntimeException(e);
78                        } catch (NoSuchMethodException e) {
79                                throw new RuntimeException(e);
80                        } catch (ClassNotFoundException e) {
81                                throw new RuntimeException(e);
82                        }
83                } else {
84                        JDBC_4_CSTMT_4_ARGS_CTOR = null;
85                        JDBC_4_CSTMT_2_ARGS_CTOR = null;
86                }
87        }
88       
89        protected static class CallableStatementParam {
90                int desiredJdbcType;
91
92                int index;
93
94                int inOutModifier;
95
96                boolean isIn;
97
98                boolean isOut;
99
100                int jdbcType;
101
102                short nullability;
103
104                String paramName;
105
106                int precision;
107
108                int scale;
109
110                String typeName;
111
112                CallableStatementParam(String name, int idx, boolean in, boolean out,
113                                int jdbcType, String typeName, int precision, int scale,
114                                short nullability, int inOutModifier) {
115                        this.paramName = name;
116                        this.isIn = in;
117                        this.isOut = out;
118                        this.index = idx;
119
120                        this.jdbcType = jdbcType;
121                        this.typeName = typeName;
122                        this.precision = precision;
123                        this.scale = scale;
124                        this.nullability = nullability;
125                        this.inOutModifier = inOutModifier;
126                }
127
128                /*
129                 * (non-Javadoc)
130                 *
131                 * @see java.lang.Object#clone()
132                 */
133                protected Object clone() throws CloneNotSupportedException {
134                        return super.clone();
135                }
136        }
137
138        protected class CallableStatementParamInfo {
139                String catalogInUse;
140
141                boolean isFunctionCall;
142
143                String nativeSql;
144
145                int numParameters;
146
147                List<CallableStatementParam> parameterList;
148
149                Map<String, CallableStatementParam> parameterMap;
150
151               
152                /**
153                 * synchronized externally in checkReadOnlyProcedure()
154                 */
155                boolean isReadOnlySafeProcedure = false;
156               
157                /**
158                 * synchronized externally in checkReadOnlyProcedure()
159                 */
160                boolean isReadOnlySafeChecked = false;
161
162                /**
163                 * Constructor that converts a full list of parameter metadata into one
164                 * that only represents the placeholders present in the {CALL ()}.
165                 *
166                 * @param fullParamInfo the metadata for all parameters for this stored
167                 * procedure or function.
168                 */
169                CallableStatementParamInfo(CallableStatementParamInfo fullParamInfo) {
170                        this.nativeSql = originalSql;
171                        this.catalogInUse = currentCatalog;
172                        isFunctionCall = fullParamInfo.isFunctionCall;
173                        @SuppressWarnings("synthetic-access")
174                        int[] localParameterMap = placeholderToParameterIndexMap;
175                        int parameterMapLength = localParameterMap.length;
176                       
177                        this.isReadOnlySafeProcedure = fullParamInfo.isReadOnlySafeProcedure;
178                        this.isReadOnlySafeChecked = fullParamInfo.isReadOnlySafeChecked;
179                        parameterList = new ArrayList<CallableStatementParam>(fullParamInfo.numParameters);
180                        parameterMap = new HashMap<String, CallableStatementParam>(fullParamInfo.numParameters);
181                       
182                        if (isFunctionCall) {
183                                // Take the return value
184                                parameterList.add(fullParamInfo.parameterList.get(0));
185                        }
186                       
187                        int offset = isFunctionCall ? 1 : 0;
188                       
189                        for (int i = 0; i < parameterMapLength; i++) {
190                                if (localParameterMap[i] != 0) {
191                                        CallableStatementParam param = fullParamInfo.parameterList.get(localParameterMap[i] + offset);
192                                       
193                                        parameterList.add(param);
194                                        parameterMap.put(param.paramName, param);
195                                }
196                        }
197                       
198                        this.numParameters = parameterList.size();
199                }
200               
201                @SuppressWarnings("synthetic-access")
202                CallableStatementParamInfo(java.sql.ResultSet paramTypesRs)
203                                throws SQLException {
204                        boolean hadRows = paramTypesRs.last();
205
206                        this.nativeSql = originalSql;
207                        this.catalogInUse = currentCatalog;
208                        isFunctionCall = callingStoredFunction;
209
210                        if (hadRows) {
211                                this.numParameters = paramTypesRs.getRow();
212
213                                this.parameterList = new ArrayList<CallableStatementParam>(this.numParameters);
214                                this.parameterMap = new HashMap<String, CallableStatementParam>(this.numParameters);
215
216                                paramTypesRs.beforeFirst();
217
218                                addParametersFromDBMD(paramTypesRs);
219                        } else {
220                                this.numParameters = 0;
221                        }
222                       
223                        if (isFunctionCall) {
224                                this.numParameters += 1;
225                }
226                }
227
228                private void addParametersFromDBMD(java.sql.ResultSet paramTypesRs)
229                                throws SQLException {
230                        int i = 0;
231
232                        while (paramTypesRs.next()) {
233                                String paramName = paramTypesRs.getString(4);
234                                int inOutModifier = paramTypesRs.getInt(5);
235
236                                boolean isOutParameter = false;
237                                boolean isInParameter = false;
238
239                                if (i == 0 && isFunctionCall) {
240                                        isOutParameter = true;
241                                        isInParameter = false;
242                                } else if (inOutModifier == DatabaseMetaData.procedureColumnInOut) {
243                                        isOutParameter = true;
244                                        isInParameter = true;
245                                } else if (inOutModifier == DatabaseMetaData.procedureColumnIn) {
246                                        isOutParameter = false;
247                                        isInParameter = true;
248                                } else if (inOutModifier == DatabaseMetaData.procedureColumnOut) {
249                                        isOutParameter = true;
250                                        isInParameter = false;
251                                }
252
253                                int jdbcType = paramTypesRs.getInt(6);
254                                String typeName = paramTypesRs.getString(7);
255                                int precision = paramTypesRs.getInt(8);
256                                int scale = paramTypesRs.getInt(10);
257                                short nullability = paramTypesRs.getShort(12);
258
259                                CallableStatementParam paramInfoToAdd = new CallableStatementParam(
260                                                paramName, i++, isInParameter, isOutParameter,
261                                                jdbcType, typeName, precision, scale, nullability,
262                                                inOutModifier);
263
264                                this.parameterList.add(paramInfoToAdd);
265                                this.parameterMap.put(paramName, paramInfoToAdd);
266                        }
267                }
268
269                protected void checkBounds(int paramIndex) throws SQLException {
270                        int localParamIndex = paramIndex - 1;
271
272                        if ((paramIndex < 0) || (localParamIndex >= this.numParameters)) {
273                                throw SQLError.createSQLException(
274                                                Messages.getString("CallableStatement.11") + paramIndex //$NON-NLS-1$
275                                                                + Messages.getString("CallableStatement.12") + numParameters //$NON-NLS-1$
276                                                                + Messages.getString("CallableStatement.13"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); //$NON-NLS-1$
277                        }
278                }
279
280                /*
281                 * (non-Javadoc)
282                 *
283                 * @see java.lang.Object#clone()
284                 */
285                protected Object clone() throws CloneNotSupportedException {
286                        return super.clone();
287                }
288
289                CallableStatementParam getParameter(int index) {
290                        return this.parameterList.get(index);
291                }
292
293                CallableStatementParam getParameter(String name) {
294                        return this.parameterMap.get(name);
295                }
296
297                public String getParameterClassName(int arg0) throws SQLException {
298                        String mysqlTypeName = getParameterTypeName(arg0);
299                       
300                        boolean isBinaryOrBlob = StringUtils.indexOfIgnoreCase(mysqlTypeName, "BLOB") != -1 || 
301                                StringUtils.indexOfIgnoreCase(mysqlTypeName, "BINARY") != -1;
302                       
303                        boolean isUnsigned = StringUtils.indexOfIgnoreCase(mysqlTypeName, "UNSIGNED") != -1;
304                       
305                        int mysqlTypeIfKnown = 0;
306                       
307                        if (StringUtils.startsWithIgnoreCase(mysqlTypeName, "MEDIUMINT")) {
308                                mysqlTypeIfKnown = MysqlDefs.FIELD_TYPE_INT24;
309                        }
310                       
311                        return ResultSetMetaData.getClassNameForJavaType(getParameterType(arg0), 
312                                        isUnsigned, mysqlTypeIfKnown, isBinaryOrBlob, false);
313                }
314
315                public int getParameterCount() throws SQLException {
316                        if (this.parameterList == null) {
317                                return 0;
318                        }
319                       
320                        return this.parameterList.size();
321                }
322
323                public int getParameterMode(int arg0) throws SQLException {
324                        checkBounds(arg0);
325
326                        return getParameter(arg0 - 1).inOutModifier;
327                }
328
329                public int getParameterType(int arg0) throws SQLException {
330                        checkBounds(arg0);
331
332                        return getParameter(arg0 - 1).jdbcType;
333                }
334
335                public String getParameterTypeName(int arg0) throws SQLException {
336                        checkBounds(arg0);
337
338                        return getParameter(arg0 - 1).typeName;
339                }
340
341                public int getPrecision(int arg0) throws SQLException {
342                        checkBounds(arg0);
343
344                        return getParameter(arg0 - 1).precision;
345                }
346
347                public int getScale(int arg0) throws SQLException {
348                        checkBounds(arg0);
349
350                        return getParameter(arg0 - 1).scale;
351                }
352
353                public int isNullable(int arg0) throws SQLException {
354                        checkBounds(arg0);
355
356                        return getParameter(arg0 - 1).nullability;
357                }
358
359                public boolean isSigned(int arg0) throws SQLException {
360                        checkBounds(arg0);
361
362                        return false;
363                }
364
365                Iterator<CallableStatementParam> iterator() {
366                        return this.parameterList.iterator();
367                }
368
369                int numberOfParameters() {
370                        return this.numParameters;
371                }
372        }
373
374        /**
375         * Can't implement this directly, as then you can't use callable statements
376         * on JDK-1.3.1, which unfortunately isn't EOL'd yet, and still present
377         * quite a bit out there in the wild (Websphere, FreeBSD, anyone?)
378         */
379
380        protected class CallableStatementParamInfoJDBC3 extends CallableStatementParamInfo
381                        implements ParameterMetaData {
382
383                CallableStatementParamInfoJDBC3(java.sql.ResultSet paramTypesRs)
384                                throws SQLException {
385                        super(paramTypesRs);
386                }
387
388                public CallableStatementParamInfoJDBC3(CallableStatementParamInfo paramInfo) {
389                        super(paramInfo);
390                }
391               
392                /**
393             * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
394             * for an object that does. Returns false otherwise. If this implements the interface then return true,
395             * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
396             * object. If this does not implement the interface and is not a wrapper, return false.
397             * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
398             * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
399             * returns true then calling <code>unwrap</code> with the same argument should succeed.
400             *
401             * @param interfaces a Class defining an interface.
402             * @return true if this implements the interface or directly or indirectly wraps an object that does.
403             * @throws java.sql.SQLException  if an error occurs while determining whether this is a wrapper
404             * for an object with the given interface.
405             * @since 1.6
406             */
407                public boolean isWrapperFor(Class<?> iface) throws SQLException {
408                        checkClosed();
409                       
410                        // This works for classes that aren't actually wrapping
411                        // anything
412                        return iface.isInstance(this);
413                }
414
415            /**
416             * Returns an object that implements the given interface to allow access to non-standard methods,
417             * or standard methods not exposed by the proxy.
418             * The result may be either the object found to implement the interface or a proxy for that object.
419             * If the receiver implements the interface then that is the object. If the receiver is a wrapper
420             * and the wrapped object implements the interface then that is the object. Otherwise the object is
421             *  the result of calling <code>unwrap</code> recursively on the wrapped object. If the receiver is not a
422             * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
423             *
424             * @param iface A Class defining an interface that the result must implement.
425             * @return an object that implements the interface. May be a proxy for the actual implementing object.
426             * @throws java.sql.SQLException If no object found that implements the interface
427             * @since 1.6
428             */
429                public Object unwrap(Class<?> iface) throws java.sql.SQLException {
430                try {
431                        // This works for classes that aren't actually wrapping
432                        // anything
433                        return Util.cast(iface, this);
434                } catch (ClassCastException cce) {
435                    throw SQLError.createSQLException("Unable to unwrap to " + iface.toString(), 
436                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
437                }
438            }
439        }
440
441        private final static int NOT_OUTPUT_PARAMETER_INDICATOR = Integer.MIN_VALUE;
442
443        private final static String PARAMETER_NAMESPACE_PREFIX = "@com_mysql_jdbc_outparam_"; //$NON-NLS-1$
444
445        private static String mangleParameterName(String origParameterName) {
446                //Fixed for 5.5+ in callers
447                if (origParameterName == null) {
448                        return null;
449                }
450
451                int offset = 0;
452
453                if (origParameterName.length() > 0
454                                && origParameterName.charAt(0) == '@') {
455                        offset = 1;
456                }
457
458                StringBuffer paramNameBuf = new StringBuffer(PARAMETER_NAMESPACE_PREFIX
459                                .length()
460                                + origParameterName.length());
461                paramNameBuf.append(PARAMETER_NAMESPACE_PREFIX);
462                paramNameBuf.append(origParameterName.substring(offset));
463
464                return paramNameBuf.toString();
465        }
466
467        private boolean callingStoredFunction = false;
468
469        private ResultSetInternalMethods functionReturnValueResults;
470
471        private boolean hasOutputParams = false;
472
473        // private List parameterList;
474        // private Map parameterMap;
475        private ResultSetInternalMethods outputParameterResults;
476
477        protected boolean outputParamWasNull = false;
478
479        private int[] parameterIndexToRsIndex;
480
481        protected CallableStatementParamInfo paramInfo;
482
483        private CallableStatementParam returnValueParam;
484       
485        /**
486         * Creates a new CallableStatement
487         *
488         * @param conn
489         *            the connection creating this statement
490         * @param paramInfo
491         *            the SQL to prepare
492         *
493         * @throws SQLException
494         *             if an error occurs
495         */
496        public CallableStatement(MySQLConnection conn,
497                        CallableStatementParamInfo paramInfo) throws SQLException {
498                super(conn, paramInfo.nativeSql, paramInfo.catalogInUse);
499
500                this.paramInfo = paramInfo;
501                this.callingStoredFunction = this.paramInfo.isFunctionCall;
502               
503                if (this.callingStoredFunction) {
504                        this.parameterCount += 1;
505                }
506               
507                this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
508        }
509
510        /**
511         * Creates a callable statement instance -- We need to provide factory-style methods
512         * so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
513         * the class verifier complains when it tries to load JDBC4-only interface
514         * classes that are present in JDBC4 method signatures.
515         */
516
517        protected static CallableStatement getInstance(MySQLConnection conn, String sql,
518                        String catalog, boolean isFunctionCall) throws SQLException {
519                if (!Util.isJdbc4()) {
520                        return new CallableStatement(conn, sql, catalog, isFunctionCall);
521                }
522
523                return (CallableStatement) Util.handleNewInstance(
524                                JDBC_4_CSTMT_4_ARGS_CTOR, new Object[] { conn, sql, catalog,
525                                                Boolean.valueOf(isFunctionCall) }, conn.getExceptionInterceptor());
526        }
527       
528        /**
529         * Creates a callable statement instance -- We need to provide factory-style methods
530         * so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
531         * the class verifier complains when it tries to load JDBC4-only interface
532         * classes that are present in JDBC4 method signatures.
533         */
534
535        protected static CallableStatement getInstance(MySQLConnection conn,
536                        CallableStatementParamInfo paramInfo) throws SQLException {
537                if (!Util.isJdbc4()) {
538                        return new CallableStatement(conn, paramInfo);
539                }
540
541                return (CallableStatement) Util.handleNewInstance(
542                                JDBC_4_CSTMT_2_ARGS_CTOR, new Object[] { conn, paramInfo }, conn.getExceptionInterceptor());
543
544        }
545       
546        private int[] placeholderToParameterIndexMap;
547       
548        private void generateParameterMap() throws SQLException {
549                synchronized (checkClosed()) {
550                        if (this.paramInfo == null) {
551                                return;
552                        }
553                       
554                        // if the user specified some parameters as literals, we need to
555                        // provide a map from the specified placeholders to the actual
556                        // parameter numbers
557                       
558                        int parameterCountFromMetaData = this.paramInfo.getParameterCount();
559                       
560                        // Ignore the first ? if this is a stored function, it doesn't count
561                       
562                        if (this.callingStoredFunction) {
563                                parameterCountFromMetaData--;
564                        }
565                       
566                        if (this.paramInfo != null &&
567                                        this.parameterCount != parameterCountFromMetaData) {
568                                this.placeholderToParameterIndexMap = new int[this.parameterCount];
569                               
570                                int startPos = this.callingStoredFunction ? StringUtils.indexOfIgnoreCase(this.originalSql, 
571                                "SELECT") : StringUtils.indexOfIgnoreCase(this.originalSql, "CALL");
572                               
573                                if (startPos != -1) {
574                                        int parenOpenPos = this.originalSql.indexOf('(', startPos + 4);
575                                       
576                                        if (parenOpenPos != -1) {
577                                                int parenClosePos = StringUtils.indexOfIgnoreCaseRespectQuotes(parenOpenPos, 
578                                                                this.originalSql, ")", '\'', true);
579                                               
580                                                if (parenClosePos != -1) {
581                                                        List<?> parsedParameters = StringUtils.split(this.originalSql.substring(parenOpenPos + 1, parenClosePos), ",", "'\"", "'\"", true);
582                                                       
583                                                        int numParsedParameters = parsedParameters.size();
584                                                       
585                                                        // sanity check
586                                                       
587                                                        if (numParsedParameters != this.parameterCount) {
588                                                                // bail?
589                                                        }
590                                                       
591                                                        int placeholderCount = 0;
592                                                       
593                                                        for (int i = 0; i < numParsedParameters; i++) {
594                                                                if (((String)parsedParameters.get(i)).equals("?")) {
595                                                                        this.placeholderToParameterIndexMap[placeholderCount++] = i;
596                                                                }
597                                                        }
598                                                }
599                                        }
600                                }
601                        }
602                }
603        }
604       
605        /**
606         * Creates a new CallableStatement
607         *
608         * @param conn
609         *            the connection creating this statement
610         * @param sql
611         *            the SQL to prepare
612         * @param catalog
613         *            the current catalog
614         *
615         * @throws SQLException
616         *             if an error occurs
617         */
618        public CallableStatement(MySQLConnection conn, String sql, String catalog,
619                        boolean isFunctionCall) throws SQLException {
620                super(conn, sql, catalog);
621
622                this.callingStoredFunction = isFunctionCall;
623
624                if (!this.callingStoredFunction) {
625                        if (!StringUtils.startsWithIgnoreCaseAndWs(sql, "CALL")) {
626                                // not really a stored procedure call
627                                fakeParameterTypes(false);
628                        } else {
629                                determineParameterTypes();
630                        }
631                       
632                        generateParameterMap();
633                } else {
634                        determineParameterTypes();
635                        generateParameterMap();
636                       
637                        this.parameterCount += 1;
638                }
639               
640                this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
641        }
642
643        /*
644         * (non-Javadoc)
645         *
646         * @see java.sql.PreparedStatement#addBatch()
647         */
648        public void addBatch() throws SQLException {
649                setOutParams();
650
651                super.addBatch();
652        }
653
654        private CallableStatementParam checkIsOutputParam(int paramIndex)
655                        throws SQLException {
656
657                synchronized (checkClosed()) {
658                        if (this.callingStoredFunction) {
659                                if (paramIndex == 1) {
660       
661                                        if (this.returnValueParam == null) {
662                                                this.returnValueParam = new CallableStatementParam("", 0,
663                                                                false, true, Types.VARCHAR, "VARCHAR", 0, 0,
664                                                                DatabaseMetaData.attributeNullableUnknown,
665                                                                DatabaseMetaData.procedureColumnReturn);
666                                        }
667       
668                                        return this.returnValueParam;
669                                }
670       
671                                // Move to position in output result set
672                                paramIndex--;
673                        }
674       
675                        checkParameterIndexBounds(paramIndex);
676       
677                        int localParamIndex = paramIndex - 1;
678       
679                        if (this.placeholderToParameterIndexMap != null) {
680                                localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
681                        }
682                       
683                        CallableStatementParam paramDescriptor = this.paramInfo
684                                        .getParameter(localParamIndex);
685       
686                        // We don't have reliable metadata in this case, trust
687                        // the caller
688                       
689                        if (this.connection.getNoAccessToProcedureBodies()) {
690                                paramDescriptor.isOut = true;
691                                paramDescriptor.isIn = true;
692                                paramDescriptor.inOutModifier = DatabaseMetaData.procedureColumnInOut;
693                        } else if (!paramDescriptor.isOut) {
694                                throw SQLError.createSQLException(
695                                                Messages.getString("CallableStatement.9") + paramIndex //$NON-NLS-1$
696                                                                + Messages.getString("CallableStatement.10"), //$NON-NLS-1$
697                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
698                        }
699       
700                        this.hasOutputParams = true;
701       
702                        return paramDescriptor;
703                }
704        }
705
706        /**
707         * DOCUMENT ME!
708         *
709         * @param paramIndex
710         *
711         * @throws SQLException
712         */
713        private void checkParameterIndexBounds(int paramIndex) throws SQLException {
714                synchronized (checkClosed()) {
715                        this.paramInfo.checkBounds(paramIndex);
716                }
717        }
718
719        /**
720         * Checks whether or not this statement is supposed to be providing
721         * streamable result sets...If output parameters are registered, the driver
722         * can not stream the results.
723         *
724         * @throws SQLException
725         *             DOCUMENT ME!
726         */
727        private void checkStreamability() throws SQLException {
728                if (this.hasOutputParams && createStreamingResultSet()) {
729                        throw SQLError.createSQLException(Messages.getString("CallableStatement.14"), //$NON-NLS-1$
730                                        SQLError.SQL_STATE_DRIVER_NOT_CAPABLE, getExceptionInterceptor());
731                }
732        }
733
734        public void clearParameters() throws SQLException {
735                synchronized (checkClosed()) {
736                        super.clearParameters();
737       
738                        try {
739                                if (this.outputParameterResults != null) {
740                                        this.outputParameterResults.close();
741                                }
742                        } finally {
743                                this.outputParameterResults = null;
744                        }
745                }
746        }
747
748        /**
749         * Used to fake up some metadata when we don't have access to
750         * SHOW CREATE PROCEDURE or mysql.proc.
751         *
752         * @throws SQLException if we can't build the metadata.
753         */
754        private void fakeParameterTypes(boolean isReallyProcedure) throws SQLException {
755                synchronized (checkClosed()) {
756                        Field[] fields = new Field[13];
757       
758                        fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
759                        fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
760                        fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
761                        fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 0);
762                        fields[4] = new Field("", "COLUMN_TYPE", Types.CHAR, 0);
763                        fields[5] = new Field("", "DATA_TYPE", Types.SMALLINT, 0);
764                        fields[6] = new Field("", "TYPE_NAME", Types.CHAR, 0);
765                        fields[7] = new Field("", "PRECISION", Types.INTEGER, 0);
766                        fields[8] = new Field("", "LENGTH", Types.INTEGER, 0);
767                        fields[9] = new Field("", "SCALE", Types.SMALLINT, 0);
768                        fields[10] = new Field("", "RADIX", Types.SMALLINT, 0);
769                        fields[11] = new Field("", "NULLABLE", Types.SMALLINT, 0);
770                        fields[12] = new Field("", "REMARKS", Types.CHAR, 0);
771       
772                        String procName = isReallyProcedure ? extractProcedureName() : null;
773       
774                        byte[] procNameAsBytes = null;
775       
776                        try {
777                                procNameAsBytes = procName == null ? null : StringUtils.getBytes(procName, "UTF-8");
778                        } catch (UnsupportedEncodingException ueEx) {
779                                procNameAsBytes = StringUtils.s2b(procName, this.connection);
780                        }
781       
782                        ArrayList<ResultSetRow> resultRows = new ArrayList<ResultSetRow>();
783       
784                        for (int i = 0; i < this.parameterCount; i++) {
785                                byte[][] row = new byte[13][];
786                                row[0] = null; // PROCEDURE_CAT
787                                row[1] = null; // PROCEDURE_SCHEM
788                                row[2] = procNameAsBytes; // PROCEDURE/NAME
789                                row[3] = StringUtils.s2b(String.valueOf(i), this.connection); // COLUMN_NAME
790       
791                                row[4] = StringUtils.s2b(String
792                                                .valueOf(DatabaseMetaData.procedureColumnIn),
793                                                this.connection);
794       
795                                row[5] = StringUtils.s2b(String.valueOf(Types.VARCHAR),
796                                                this.connection); // DATA_TYPE
797                                row[6] = StringUtils.s2b("VARCHAR", this.connection); // TYPE_NAME
798                                row[7] = StringUtils.s2b(Integer.toString(65535), this.connection); // PRECISION
799                                row[8] = StringUtils.s2b(Integer.toString(65535), this.connection); // LENGTH
800                                row[9] = StringUtils.s2b(Integer.toString(0), this.connection); // SCALE
801                                row[10] = StringUtils.s2b(Integer.toString(10), this.connection); // RADIX
802       
803                                row[11] = StringUtils.s2b(Integer
804                                                .toString(DatabaseMetaData.procedureNullableUnknown),
805                                                this.connection); // nullable
806       
807                                row[12] = null;
808       
809                                resultRows.add(new ByteArrayRow(row, getExceptionInterceptor()));
810                        }
811       
812                        java.sql.ResultSet paramTypesRs = DatabaseMetaData.buildResultSet(
813                                        fields, resultRows, this.connection);
814       
815                        convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);
816                }
817        }
818       
819        private void determineParameterTypes() throws SQLException {
820                synchronized (checkClosed()) {
821                        java.sql.ResultSet paramTypesRs = null;
822       
823                        try {
824                                //Bug#57022, we need to check for db.SPname notation first
825                                //  and pass on only SPname
826                                String procName = extractProcedureName();
827                                String quotedId = "";
828                                try {
829                                        quotedId = this.connection.supportsQuotedIdentifiers() ? 
830                                                        this.connection.getMetaData().getIdentifierQuoteString()        : "";
831                                } catch (SQLException sqlEx) {
832                                        // Forced by API, never thrown from getIdentifierQuoteString() in
833                                        // this implementation.
834                                        AssertionFailedException.shouldNotHappen(sqlEx);
835                                }
836                               
837                                List<?> parseList = StringUtils.splitDBdotName(procName, "", 
838                                                quotedId , this.connection.isNoBackslashEscapesSet());
839                                String tmpCatalog = "";
840                                //There *should* be 2 rows, if any.
841                                if (parseList.size() == 2) {
842                                        tmpCatalog = (String) parseList.get(0);
843                                        procName = (String) parseList.get(1);                   
844                                } else {
845                                        //keep values as they are
846                                }
847                               
848                                java.sql.DatabaseMetaData dbmd = this.connection.getMetaData();
849       
850                                boolean useCatalog = false;
851       
852                                if (tmpCatalog.length() <= 0) {
853                                        useCatalog = true;
854                                }
855                               
856                                paramTypesRs = dbmd.getProcedureColumns(this.connection
857                                                .versionMeetsMinimum(5, 0, 2)
858                                                && useCatalog ? this.currentCatalog : tmpCatalog/*null*/, null, procName,
859                                                "%"); //$NON-NLS-1$
860                               
861                                boolean hasResults = false;
862                                try {
863                                        if (paramTypesRs.next()) {
864                                                paramTypesRs.previous();
865                                                hasResults = true;
866                                        }
867                                } catch (Exception e) {
868                                        // paramTypesRs is empty, proceed with fake params. swallow, was expected
869                                }
870                                if (hasResults){
871                                        convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);
872                                } else {
873                                        fakeParameterTypes(true);
874                                }
875                        } finally {
876                                SQLException sqlExRethrow = null;
877       
878                                if (paramTypesRs != null) {
879                                        try {
880                                                paramTypesRs.close();
881                                        } catch (SQLException sqlEx) {
882                                                sqlExRethrow = sqlEx;
883                                        }
884       
885                                        paramTypesRs = null;
886                                }
887       
888                                if (sqlExRethrow != null) {
889                                        throw sqlExRethrow;
890                                }
891                        }
892                }
893        }
894
895        private void convertGetProcedureColumnsToInternalDescriptors(java.sql.ResultSet paramTypesRs) throws SQLException {
896                synchronized (checkClosed()) {
897                        if (!this.connection.isRunningOnJDK13()) {
898                                this.paramInfo = new CallableStatementParamInfoJDBC3(
899                                                paramTypesRs);
900                        } else {
901                                this.paramInfo = new CallableStatementParamInfo(paramTypesRs);
902                        }
903                }
904        }
905
906        /*
907         * (non-Javadoc)
908         *
909         * @see java.sql.PreparedStatement#execute()
910         */
911        public boolean execute() throws SQLException {
912                synchronized (checkClosed()) {
913                        boolean returnVal = false;
914
915                        checkStreamability();
916
917                        setInOutParamsOnServer();
918                        setOutParams();
919
920                        returnVal = super.execute();
921
922                        if (this.callingStoredFunction) {
923                                this.functionReturnValueResults = this.results;
924                                this.functionReturnValueResults.next();
925                                this.results = null;
926                        }
927
928                        retrieveOutParams();
929               
930
931                        if (!this.callingStoredFunction) {
932                                return returnVal;
933                        }
934       
935                        // Functions can't return results
936                        return false;
937                }
938        }
939
940        /*
941         * (non-Javadoc)
942         *
943         * @see java.sql.PreparedStatement#executeQuery()
944         */
945        public java.sql.ResultSet executeQuery() throws SQLException {
946                synchronized (checkClosed()) {
947
948                        checkStreamability();
949       
950                        java.sql.ResultSet execResults = null;
951
952                        setInOutParamsOnServer();
953                        setOutParams();
954
955                        execResults = super.executeQuery();
956
957                        retrieveOutParams();
958                       
959                        return execResults;
960                }
961        }
962
963        /*
964         * (non-Javadoc)
965         *
966         * @see java.sql.PreparedStatement#executeUpdate()
967         */
968        public int executeUpdate() throws SQLException {
969                synchronized (checkClosed()) {
970                        int returnVal = -1;
971       
972                       
973                        checkStreamability();
974       
975                        if (this.callingStoredFunction) {
976                                execute();
977       
978                                return -1;
979                        }
980
981                        setInOutParamsOnServer();
982                        setOutParams();
983
984                        returnVal = super.executeUpdate();
985
986                        retrieveOutParams();
987
988                        return returnVal;
989                }
990        }
991
992        private String extractProcedureName() throws SQLException {
993                String sanitizedSql = StringUtils.stripComments(this.originalSql, 
994                                "`\"'", "`\"'", true, false, true, true);
995               
996                // TODO: Do this with less memory allocation
997                int endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql,
998                                "CALL "); //$NON-NLS-1$
999                int offset = 5;
1000
1001                if (endCallIndex == -1) {
1002                        endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql,
1003                                        "SELECT ");
1004                        offset = 7;
1005                }
1006
1007                if (endCallIndex != -1) {
1008                        StringBuffer nameBuf = new StringBuffer();
1009
1010                        String trimmedStatement = sanitizedSql.substring(
1011                                        endCallIndex + offset).trim();
1012
1013                        int statementLength = trimmedStatement.length();
1014
1015                        for (int i = 0; i < statementLength; i++) {
1016                                char c = trimmedStatement.charAt(i);
1017
1018                                if (Character.isWhitespace(c) || (c == '(') || (c == '?')) {
1019                                        break;
1020                                }
1021                                nameBuf.append(c);
1022
1023                        }
1024
1025                        return nameBuf.toString();
1026                }
1027               
1028                throw SQLError.createSQLException(Messages.getString("CallableStatement.1"), //$NON-NLS-1$
1029                                SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
1030        }
1031
1032        /**
1033         * Adds 'at' symbol to beginning of parameter names if needed.
1034         *
1035         * @param paramNameIn
1036         *            the parameter name to 'fix'
1037         *
1038         * @return the parameter name with an 'a' prepended, if needed
1039         *
1040         * @throws SQLException
1041         *             if the parameter name is null or empty.
1042         */
1043        protected String fixParameterName(String paramNameIn) throws SQLException {
1044                synchronized (checkClosed()) {
1045                        //Fixed for 5.5+
1046                        if (((paramNameIn == null) || (paramNameIn.length() == 0)) && (!hasParametersView())) {
1047                                throw SQLError.createSQLException(
1048                                                ((Messages.getString("CallableStatement.0") + paramNameIn) == null) //$NON-NLS-1$
1049                                                                ? Messages.getString("CallableStatement.15") : Messages.getString("CallableStatement.16"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, 
1050                                                                                getExceptionInterceptor()); //$NON-NLS-1$ //$NON-NLS-2$
1051                        }
1052       
1053                        if ((paramNameIn == null) && (hasParametersView())) {
1054                                paramNameIn = "nullpn";
1055                        };
1056       
1057                        if (this.connection.getNoAccessToProcedureBodies()) {
1058                                throw SQLError.createSQLException("No access to parameters by name when connection has been configured not to access procedure bodies",
1059                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1060                        }
1061                       
1062                        return mangleParameterName(paramNameIn);
1063                }
1064        }
1065
1066        /**
1067         * @see java.sql.CallableStatement#getArray(int)
1068         */
1069        public Array getArray(int i) throws SQLException {
1070                synchronized (checkClosed()) {
1071                        ResultSetInternalMethods rs = getOutputParameters(i);
1072       
1073                        Array retValue = rs.getArray(mapOutputParameterIndexToRsIndex(i));
1074       
1075                        this.outputParamWasNull = rs.wasNull();
1076       
1077                        return retValue;
1078                }
1079        }
1080
1081        /**
1082         * @see java.sql.CallableStatement#getArray(java.lang.String)
1083         */
1084        public Array getArray(String parameterName)
1085                        throws SQLException {
1086                synchronized (checkClosed()) {
1087                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1088                        // from ?=
1089       
1090                        Array retValue = rs.getArray(fixParameterName(parameterName));
1091       
1092                        this.outputParamWasNull = rs.wasNull();
1093       
1094                        return retValue;
1095                }
1096        }
1097
1098        /**
1099         * @see java.sql.CallableStatement#getBigDecimal(int)
1100         */
1101        public BigDecimal getBigDecimal(int parameterIndex)
1102                        throws SQLException {
1103                synchronized (checkClosed()) {
1104                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1105       
1106                        BigDecimal retValue = rs
1107                                        .getBigDecimal(mapOutputParameterIndexToRsIndex(parameterIndex));
1108       
1109                        this.outputParamWasNull = rs.wasNull();
1110       
1111                        return retValue;
1112                }
1113        }
1114
1115        /**
1116         * DOCUMENT ME!
1117         *
1118         * @param parameterIndex
1119         *            DOCUMENT ME!
1120         * @param scale
1121         *            DOCUMENT ME!
1122         *
1123         * @return DOCUMENT ME!
1124         *
1125         * @throws SQLException
1126         *             DOCUMENT ME!
1127         *
1128         * @see java.sql.CallableStatement#getBigDecimal(int, int)
1129         * @deprecated
1130         */
1131        public BigDecimal getBigDecimal(int parameterIndex, int scale)
1132                        throws SQLException {
1133                synchronized (checkClosed()) {
1134                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1135       
1136                        BigDecimal retValue = rs.getBigDecimal(
1137                                        mapOutputParameterIndexToRsIndex(parameterIndex), scale);
1138       
1139                        this.outputParamWasNull = rs.wasNull();
1140       
1141                        return retValue;
1142                }
1143        }
1144
1145        /**
1146         * @see java.sql.CallableStatement#getBigDecimal(java.lang.String)
1147         */
1148        public BigDecimal getBigDecimal(String parameterName)
1149                        throws SQLException {
1150                synchronized (checkClosed()) {
1151                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1152                        // from ?=
1153       
1154                        BigDecimal retValue = rs.getBigDecimal(fixParameterName(parameterName));
1155       
1156                        this.outputParamWasNull = rs.wasNull();
1157       
1158                        return retValue;
1159                }
1160        }
1161
1162        /**
1163         * @see java.sql.CallableStatement#getBlob(int)
1164         */
1165        public Blob getBlob(int parameterIndex) throws SQLException {
1166                synchronized (checkClosed()) {
1167                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1168       
1169                        Blob retValue = rs
1170                                        .getBlob(mapOutputParameterIndexToRsIndex(parameterIndex));
1171       
1172                        this.outputParamWasNull = rs.wasNull();
1173       
1174                        return retValue;
1175                }
1176        }
1177
1178        /**
1179         * @see java.sql.CallableStatement#getBlob(java.lang.String)
1180         */
1181        public Blob getBlob(String parameterName) throws SQLException {
1182                synchronized (checkClosed()) {
1183                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1184                        // from ?=
1185       
1186                        Blob retValue = rs.getBlob(fixParameterName(parameterName));
1187       
1188                        this.outputParamWasNull = rs.wasNull();
1189       
1190                        return retValue;
1191                }
1192        }
1193
1194        /**
1195         * @see java.sql.CallableStatement#getBoolean(int)
1196         */
1197        public boolean getBoolean(int parameterIndex)
1198                        throws SQLException {
1199                synchronized (checkClosed()) {
1200                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1201       
1202                        boolean retValue = rs
1203                                        .getBoolean(mapOutputParameterIndexToRsIndex(parameterIndex));
1204       
1205                        this.outputParamWasNull = rs.wasNull();
1206       
1207                        return retValue;
1208                }
1209        }
1210
1211        /**
1212         * @see java.sql.CallableStatement#getBoolean(java.lang.String)
1213         */
1214        public boolean getBoolean(String parameterName)
1215                        throws SQLException {
1216                synchronized (checkClosed()) {
1217                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1218                        // from ?=
1219       
1220                        boolean retValue = rs.getBoolean(fixParameterName(parameterName));
1221       
1222                        this.outputParamWasNull = rs.wasNull();
1223       
1224                        return retValue;
1225                }
1226        }
1227
1228        /**
1229         * @see java.sql.CallableStatement#getByte(int)
1230         */
1231        public byte getByte(int parameterIndex) throws SQLException {
1232                synchronized (checkClosed()) {
1233                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1234       
1235                        byte retValue = rs
1236                                        .getByte(mapOutputParameterIndexToRsIndex(parameterIndex));
1237       
1238                        this.outputParamWasNull = rs.wasNull();
1239       
1240                        return retValue;
1241                }
1242        }
1243
1244        /**
1245         * @see java.sql.CallableStatement#getByte(java.lang.String)
1246         */
1247        public byte getByte(String parameterName) throws SQLException {
1248                synchronized (checkClosed()) {
1249                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1250                        // from ?=
1251       
1252                        byte retValue = rs.getByte(fixParameterName(parameterName));
1253       
1254                        this.outputParamWasNull = rs.wasNull();
1255       
1256                        return retValue;
1257                }
1258        }
1259
1260        /**
1261         * @see java.sql.CallableStatement#getBytes(int)
1262         */
1263        public byte[] getBytes(int parameterIndex) throws SQLException {
1264                synchronized (checkClosed()) {
1265                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1266       
1267                        byte[] retValue = rs
1268                                        .getBytes(mapOutputParameterIndexToRsIndex(parameterIndex));
1269       
1270                        this.outputParamWasNull = rs.wasNull();
1271       
1272                        return retValue;
1273                }
1274        }
1275
1276        /**
1277         * @see java.sql.CallableStatement#getBytes(java.lang.String)
1278         */
1279        public byte[] getBytes(String parameterName)
1280                        throws SQLException {
1281                synchronized (checkClosed()) {
1282                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1283                        // from ?=
1284       
1285                        byte[] retValue = rs.getBytes(fixParameterName(parameterName));
1286       
1287                        this.outputParamWasNull = rs.wasNull();
1288       
1289                        return retValue;
1290                }
1291        }
1292
1293        /**
1294         * @see java.sql.CallableStatement#getClob(int)
1295         */
1296        public Clob getClob(int parameterIndex) throws SQLException {
1297                synchronized (checkClosed()) {
1298                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1299       
1300                        Clob retValue = rs
1301                                        .getClob(mapOutputParameterIndexToRsIndex(parameterIndex));
1302       
1303                        this.outputParamWasNull = rs.wasNull();
1304       
1305                        return retValue;
1306                }
1307        }
1308
1309        /**
1310         * @see java.sql.CallableStatement#getClob(java.lang.String)
1311         */
1312        public Clob getClob(String parameterName) throws SQLException {
1313                synchronized (checkClosed()) {
1314                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1315                        // from ?=
1316       
1317                        Clob retValue = rs.getClob(fixParameterName(parameterName));
1318       
1319                        this.outputParamWasNull = rs.wasNull();
1320       
1321                        return retValue;
1322                }
1323        }
1324
1325        /**
1326         * @see java.sql.CallableStatement#getDate(int)
1327         */
1328        public Date getDate(int parameterIndex) throws SQLException {
1329                synchronized (checkClosed()) {
1330                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1331       
1332                        Date retValue = rs
1333                                        .getDate(mapOutputParameterIndexToRsIndex(parameterIndex));
1334       
1335                        this.outputParamWasNull = rs.wasNull();
1336       
1337                        return retValue;
1338                }
1339        }
1340
1341        /**
1342         * @see java.sql.CallableStatement#getDate(int, java.util.Calendar)
1343         */
1344        public Date getDate(int parameterIndex, Calendar cal)
1345                        throws SQLException {
1346                synchronized (checkClosed()) {
1347                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1348       
1349                        Date retValue = rs.getDate(
1350                                        mapOutputParameterIndexToRsIndex(parameterIndex), cal);
1351       
1352                        this.outputParamWasNull = rs.wasNull();
1353       
1354                        return retValue;
1355                }
1356        }
1357
1358        /**
1359         * @see java.sql.CallableStatement#getDate(java.lang.String)
1360         */
1361        public Date getDate(String parameterName) throws SQLException {
1362                synchronized (checkClosed()) {
1363                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1364                        // from ?=
1365       
1366                        Date retValue = rs.getDate(fixParameterName(parameterName));
1367       
1368                        this.outputParamWasNull = rs.wasNull();
1369       
1370                        return retValue;
1371                }
1372        }
1373
1374        /**
1375         * @see java.sql.CallableStatement#getDate(java.lang.String,
1376         *      java.util.Calendar)
1377         */
1378        public Date getDate(String parameterName, Calendar cal)
1379                        throws SQLException {
1380                synchronized (checkClosed()) {
1381                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1382                        // from ?=
1383       
1384                        Date retValue = rs.getDate(fixParameterName(parameterName), cal);
1385       
1386                        this.outputParamWasNull = rs.wasNull();
1387       
1388                        return retValue;
1389                }
1390        }
1391
1392        /**
1393         * @see java.sql.CallableStatement#getDouble(int)
1394         */
1395        public double getDouble(int parameterIndex)
1396                        throws SQLException {
1397                synchronized (checkClosed()) {
1398                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1399       
1400                        double retValue = rs
1401                                        .getDouble(mapOutputParameterIndexToRsIndex(parameterIndex));
1402       
1403                        this.outputParamWasNull = rs.wasNull();
1404       
1405                        return retValue;
1406                }
1407        }
1408
1409        /**
1410         * @see java.sql.CallableStatement#getDouble(java.lang.String)
1411         */
1412        public double getDouble(String parameterName)
1413                        throws SQLException {
1414                synchronized (checkClosed()) {
1415                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1416                        // from ?=
1417       
1418                        double retValue = rs.getDouble(fixParameterName(parameterName));
1419       
1420                        this.outputParamWasNull = rs.wasNull();
1421       
1422                        return retValue;
1423                }
1424        }
1425
1426        /**
1427         * @see java.sql.CallableStatement#getFloat(int)
1428         */
1429        public float getFloat(int parameterIndex) throws SQLException {
1430                synchronized (checkClosed()) {
1431                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1432       
1433                        float retValue = rs
1434                                        .getFloat(mapOutputParameterIndexToRsIndex(parameterIndex));
1435       
1436                        this.outputParamWasNull = rs.wasNull();
1437       
1438                        return retValue;
1439                }
1440        }
1441
1442        /**
1443         * @see java.sql.CallableStatement#getFloat(java.lang.String)
1444         */
1445        public float getFloat(String parameterName)
1446                        throws SQLException {
1447                synchronized (checkClosed()) {
1448                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1449                        // from ?=
1450       
1451                        float retValue = rs.getFloat(fixParameterName(parameterName));
1452       
1453                        this.outputParamWasNull = rs.wasNull();
1454       
1455                        return retValue;
1456                }
1457        }
1458
1459        /**
1460         * @see java.sql.CallableStatement#getInt(int)
1461         */
1462        public int getInt(int parameterIndex) throws SQLException {
1463                synchronized (checkClosed()) {
1464                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1465       
1466                        int retValue = rs
1467                                        .getInt(mapOutputParameterIndexToRsIndex(parameterIndex));
1468       
1469                        this.outputParamWasNull = rs.wasNull();
1470       
1471                        return retValue;
1472                }
1473        }
1474
1475        /**
1476         * @see java.sql.CallableStatement#getInt(java.lang.String)
1477         */
1478        public int getInt(String parameterName) throws SQLException {
1479                synchronized (checkClosed()) {
1480                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1481                        // from ?=
1482       
1483                        int retValue = rs.getInt(fixParameterName(parameterName));
1484       
1485                        this.outputParamWasNull = rs.wasNull();
1486       
1487                        return retValue;
1488                }
1489        }
1490
1491        /**
1492         * @see java.sql.CallableStatement#getLong(int)
1493         */
1494        public long getLong(int parameterIndex) throws SQLException {
1495                synchronized (checkClosed()) {
1496                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1497       
1498                        long retValue = rs
1499                                        .getLong(mapOutputParameterIndexToRsIndex(parameterIndex));
1500       
1501                        this.outputParamWasNull = rs.wasNull();
1502       
1503                        return retValue;
1504                }
1505        }
1506
1507        /**
1508         * @see java.sql.CallableStatement#getLong(java.lang.String)
1509         */
1510        public long getLong(String parameterName) throws SQLException {
1511                synchronized (checkClosed()) {
1512                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1513                        // from ?=
1514       
1515                        long retValue = rs.getLong(fixParameterName(parameterName));
1516       
1517                        this.outputParamWasNull = rs.wasNull();
1518       
1519                        return retValue;
1520                }
1521        }
1522
1523        protected int getNamedParamIndex(String paramName, boolean forOut)
1524        throws SQLException {
1525                synchronized (checkClosed()) {
1526                        if (this.connection.getNoAccessToProcedureBodies()) {
1527                                throw SQLError.createSQLException("No access to parameters by name when connection has been configured not to access procedure bodies",
1528                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1529                        }
1530                       
1531                        //Fixed for 5.5+ in callers
1532                        if ((paramName == null) || (paramName.length() == 0)) {
1533                                throw SQLError.createSQLException(Messages.getString("CallableStatement.2"), //$NON-NLS-1$
1534                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1535                        }
1536       
1537                        if (this.paramInfo == null) {
1538                                throw SQLError.createSQLException(
1539                                                Messages.getString("CallableStatement.3") + paramName + Messages.getString("CallableStatement.4"), //$NON-NLS-1$ //$NON-NLS-2$
1540                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1541                        }
1542       
1543                        CallableStatementParam namedParamInfo = this.paramInfo
1544                                .getParameter(paramName);
1545       
1546                        if (forOut && !namedParamInfo.isOut) {
1547                                throw SQLError.createSQLException(
1548                                                Messages.getString("CallableStatement.5") + paramName //$NON-NLS-1$
1549                                                + Messages.getString("CallableStatement.6"), //$NON-NLS-1$
1550                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1551                        }
1552       
1553       
1554                        if (this.placeholderToParameterIndexMap == null) {
1555                                return namedParamInfo.index + 1; // JDBC indices are 1-based
1556                        } 
1557       
1558                        for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
1559                                if (this.placeholderToParameterIndexMap[i] == namedParamInfo.index) {
1560                                        return i + 1;
1561                                }
1562                        }
1563       
1564                        throw SQLError.createSQLException("Can't find local placeholder mapping for parameter named \"" + 
1565                                        paramName + "\".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1566                }
1567        }
1568
1569        /**
1570         * @see java.sql.CallableStatement#getObject(int)
1571         */
1572        public Object getObject(int parameterIndex)
1573                        throws SQLException {
1574                synchronized (checkClosed()) {
1575                        CallableStatementParam paramDescriptor = checkIsOutputParam(parameterIndex);
1576       
1577                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1578       
1579                        Object retVal = rs.getObjectStoredProc(
1580                                        mapOutputParameterIndexToRsIndex(parameterIndex),
1581                                        paramDescriptor.desiredJdbcType);
1582       
1583                        this.outputParamWasNull = rs.wasNull();
1584       
1585                        return retVal;
1586                }
1587        }
1588
1589        /**
1590         * @see java.sql.CallableStatement#getObject(int, java.util.Map)
1591         */
1592        public Object getObject(int parameterIndex, Map<String, Class<?>> map)
1593                        throws SQLException {
1594                synchronized (checkClosed()) {
1595                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1596       
1597                        Object retVal = rs.getObject(
1598                                        mapOutputParameterIndexToRsIndex(parameterIndex), map);
1599       
1600                        this.outputParamWasNull = rs.wasNull();
1601       
1602                        return retVal;
1603                }
1604        }
1605
1606        /**
1607         * @see java.sql.CallableStatement#getObject(java.lang.String)
1608         */
1609        public Object getObject(String parameterName)
1610                        throws SQLException {
1611                synchronized (checkClosed()) {
1612                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1613                        // from ?=
1614       
1615                        Object retValue = rs.getObject(fixParameterName(parameterName));
1616       
1617                        this.outputParamWasNull = rs.wasNull();
1618       
1619                        return retValue;
1620                }
1621        }
1622
1623        /**
1624         * @see java.sql.CallableStatement#getObject(java.lang.String,
1625         *      java.util.Map)
1626         */
1627        public Object getObject(String parameterName, Map<String, Class<?>> map)
1628                        throws SQLException {
1629                synchronized (checkClosed()) {
1630                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1631                        // from ?=
1632       
1633                        Object retValue = rs.getObject(fixParameterName(parameterName), map);
1634       
1635                        this.outputParamWasNull = rs.wasNull();
1636       
1637                        return retValue;
1638                }
1639        }
1640       
1641        // JDBC-4.1
1642        public <T> T getObject(int parameterIndex, Class<T> type) throws SQLException {
1643                synchronized (checkClosed()) {
1644                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1645       
1646                        // remove cast once 1.5, 1.6 EOL'd
1647                        T retVal = ((ResultSetImpl)rs).getObject(
1648                                        mapOutputParameterIndexToRsIndex(parameterIndex), type);
1649       
1650                        this.outputParamWasNull = rs.wasNull();
1651       
1652                        return retVal;
1653                }
1654        }
1655       
1656        public <T> T getObject(String parameterName, Class<T> type) throws SQLException {
1657                synchronized (checkClosed()) {
1658                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1659                        // from ?=
1660       
1661                        T retValue = ((ResultSetImpl)rs).getObject(fixParameterName(parameterName), type);
1662       
1663                        this.outputParamWasNull = rs.wasNull();
1664       
1665                        return retValue;
1666                }
1667        }
1668
1669        /**
1670         * Returns the ResultSet that holds the output parameters, or throws an
1671         * appropriate exception if none exist, or they weren't returned.
1672         *
1673         * @return the ResultSet that holds the output parameters
1674         *
1675         * @throws SQLException
1676         *             if no output parameters were defined, or if no output
1677         *             parameters were returned.
1678         */
1679        protected ResultSetInternalMethods getOutputParameters(int paramIndex) throws SQLException {
1680                synchronized (checkClosed()) {
1681                        this.outputParamWasNull = false;
1682       
1683                        if (paramIndex == 1 && this.callingStoredFunction
1684                                        && this.returnValueParam != null) {
1685                                return this.functionReturnValueResults;
1686                        }
1687       
1688                        if (this.outputParameterResults == null) {
1689                                if (this.paramInfo.numberOfParameters() == 0) {
1690                                        throw SQLError.createSQLException(Messages
1691                                                        .getString("CallableStatement.7"), //$NON-NLS-1$
1692                                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1693                                }
1694                                throw SQLError.createSQLException(Messages.getString("CallableStatement.8"), //$NON-NLS-1$
1695                                                SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
1696                        }
1697       
1698                        return this.outputParameterResults;
1699                }
1700        }
1701
1702        public ParameterMetaData getParameterMetaData()
1703                        throws SQLException {
1704                synchronized (checkClosed()) {
1705                        if (this.placeholderToParameterIndexMap == null) {
1706                                return (CallableStatementParamInfoJDBC3) this.paramInfo;
1707                        }
1708                               
1709                        return new CallableStatementParamInfoJDBC3(this.paramInfo);
1710                }
1711        }
1712
1713        /**
1714         * @see java.sql.CallableStatement#getRef(int)
1715         */
1716        public Ref getRef(int parameterIndex) throws SQLException {
1717                synchronized (checkClosed()) {
1718                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1719       
1720                        Ref retValue = rs
1721                                        .getRef(mapOutputParameterIndexToRsIndex(parameterIndex));
1722       
1723                        this.outputParamWasNull = rs.wasNull();
1724       
1725                        return retValue;
1726                }
1727        }
1728
1729        /**
1730         * @see java.sql.CallableStatement#getRef(java.lang.String)
1731         */
1732        public Ref getRef(String parameterName) throws SQLException {
1733                synchronized (checkClosed()) {
1734                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1735                        // from ?=
1736       
1737                        Ref retValue = rs.getRef(fixParameterName(parameterName));
1738       
1739                        this.outputParamWasNull = rs.wasNull();
1740       
1741                        return retValue;
1742                }
1743        }
1744
1745        /**
1746         * @see java.sql.CallableStatement#getShort(int)
1747         */
1748        public short getShort(int parameterIndex) throws SQLException {
1749                synchronized (checkClosed()) {
1750                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1751       
1752                        short retValue = rs
1753                                        .getShort(mapOutputParameterIndexToRsIndex(parameterIndex));
1754       
1755                        this.outputParamWasNull = rs.wasNull();
1756       
1757                        return retValue;
1758                }
1759        }
1760
1761        /**
1762         * @see java.sql.CallableStatement#getShort(java.lang.String)
1763         */
1764        public short getShort(String parameterName)
1765                        throws SQLException {
1766                synchronized (checkClosed()) {
1767                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1768                        // from ?=
1769       
1770                        short retValue = rs.getShort(fixParameterName(parameterName));
1771       
1772                        this.outputParamWasNull = rs.wasNull();
1773       
1774                        return retValue;
1775                }
1776        }
1777
1778        /**
1779         * @see java.sql.CallableStatement#getString(int)
1780         */
1781        public String getString(int parameterIndex)
1782                        throws SQLException {
1783                synchronized (checkClosed()) {
1784                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1785       
1786                        String retValue = rs
1787                                        .getString(mapOutputParameterIndexToRsIndex(parameterIndex));
1788       
1789                        this.outputParamWasNull = rs.wasNull();
1790       
1791                        return retValue;
1792                }
1793        }
1794
1795        /**
1796         * @see java.sql.CallableStatement#getString(java.lang.String)
1797         */
1798        public String getString(String parameterName)
1799                        throws SQLException {
1800                synchronized (checkClosed()) {
1801                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1802                        // from ?=
1803       
1804                        String retValue = rs.getString(fixParameterName(parameterName));
1805       
1806                        this.outputParamWasNull = rs.wasNull();
1807       
1808                        return retValue;
1809                }
1810        }
1811
1812        /**
1813         * @see java.sql.CallableStatement#getTime(int)
1814         */
1815        public Time getTime(int parameterIndex) throws SQLException {
1816                synchronized (checkClosed()) {
1817                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1818       
1819                        Time retValue = rs
1820                                        .getTime(mapOutputParameterIndexToRsIndex(parameterIndex));
1821       
1822                        this.outputParamWasNull = rs.wasNull();
1823       
1824                        return retValue;
1825                }
1826        }
1827
1828        /**
1829         * @see java.sql.CallableStatement#getTime(int, java.util.Calendar)
1830         */
1831        public Time getTime(int parameterIndex, Calendar cal)
1832                        throws SQLException {
1833                        synchronized (checkClosed()) {
1834                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1835       
1836                        Time retValue = rs.getTime(
1837                                        mapOutputParameterIndexToRsIndex(parameterIndex), cal);
1838       
1839                        this.outputParamWasNull = rs.wasNull();
1840       
1841                        return retValue;
1842                }
1843        }
1844
1845        /**
1846         * @see java.sql.CallableStatement#getTime(java.lang.String)
1847         */
1848        public Time getTime(String parameterName) throws SQLException {
1849                synchronized (checkClosed()) {
1850                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1851                        // from ?=
1852       
1853                        Time retValue = rs.getTime(fixParameterName(parameterName));
1854       
1855                        this.outputParamWasNull = rs.wasNull();
1856       
1857                        return retValue;
1858                }
1859        }
1860
1861        /**
1862         * @see java.sql.CallableStatement#getTime(java.lang.String,
1863         *      java.util.Calendar)
1864         */
1865        public Time getTime(String parameterName, Calendar cal)
1866                        throws SQLException {
1867                synchronized (checkClosed()) {
1868                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1869                        // from ?=
1870       
1871                        Time retValue = rs.getTime(fixParameterName(parameterName), cal);
1872       
1873                        this.outputParamWasNull = rs.wasNull();
1874       
1875                        return retValue;
1876                }
1877        }
1878
1879        /**
1880         * @see java.sql.CallableStatement#getTimestamp(int)
1881         */
1882        public Timestamp getTimestamp(int parameterIndex)
1883                        throws SQLException {
1884                synchronized (checkClosed()) {
1885                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1886       
1887                        Timestamp retValue = rs
1888                                        .getTimestamp(mapOutputParameterIndexToRsIndex(parameterIndex));
1889       
1890                        this.outputParamWasNull = rs.wasNull();
1891       
1892                        return retValue;
1893                }
1894        }
1895
1896        /**
1897         * @see java.sql.CallableStatement#getTimestamp(int, java.util.Calendar)
1898         */
1899        public Timestamp getTimestamp(int parameterIndex, Calendar cal)
1900                        throws SQLException {
1901                synchronized (checkClosed()) {
1902                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1903       
1904                        Timestamp retValue = rs.getTimestamp(
1905                                        mapOutputParameterIndexToRsIndex(parameterIndex), cal);
1906       
1907                        this.outputParamWasNull = rs.wasNull();
1908       
1909                        return retValue;
1910                }
1911        }
1912
1913        /**
1914         * @see java.sql.CallableStatement#getTimestamp(java.lang.String)
1915         */
1916        public Timestamp getTimestamp(String parameterName)
1917                        throws SQLException {
1918                synchronized (checkClosed()) {
1919                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1920                        // from ?=
1921       
1922                        Timestamp retValue = rs.getTimestamp(fixParameterName(parameterName));
1923       
1924                        this.outputParamWasNull = rs.wasNull();
1925       
1926                        return retValue;
1927                }
1928        }
1929
1930        /**
1931         * @see java.sql.CallableStatement#getTimestamp(java.lang.String,
1932         *      java.util.Calendar)
1933         */
1934        public Timestamp getTimestamp(String parameterName,
1935                        Calendar cal) throws SQLException {
1936                synchronized (checkClosed()) {
1937                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1938                        // from ?=
1939       
1940                        Timestamp retValue = rs.getTimestamp(fixParameterName(parameterName),
1941                                        cal);
1942       
1943                        this.outputParamWasNull = rs.wasNull();
1944       
1945                        return retValue;
1946                }
1947        }
1948
1949        /**
1950         * @see java.sql.CallableStatement#getURL(int)
1951         */
1952        public URL getURL(int parameterIndex) throws SQLException {
1953                synchronized (checkClosed()) {
1954                        ResultSetInternalMethods rs = getOutputParameters(parameterIndex);
1955       
1956                        URL retValue = rs
1957                                        .getURL(mapOutputParameterIndexToRsIndex(parameterIndex));
1958       
1959                        this.outputParamWasNull = rs.wasNull();
1960       
1961                        return retValue;
1962                }
1963        }
1964
1965        /**
1966         * @see java.sql.CallableStatement#getURL(java.lang.String)
1967         */
1968        public URL getURL(String parameterName) throws SQLException {
1969                synchronized (checkClosed()) {
1970                        ResultSetInternalMethods rs = getOutputParameters(0); // definitely not going to be
1971                        // from ?=
1972       
1973                        URL retValue = rs.getURL(fixParameterName(parameterName));
1974       
1975                        this.outputParamWasNull = rs.wasNull();
1976       
1977                        return retValue;
1978                }
1979        }
1980
1981        protected int mapOutputParameterIndexToRsIndex(int paramIndex)
1982                        throws SQLException {
1983
1984                synchronized (checkClosed()) {
1985                        if (this.returnValueParam != null && paramIndex == 1) {
1986                                return 1;
1987                        }
1988       
1989                        checkParameterIndexBounds(paramIndex);
1990       
1991                        int localParamIndex = paramIndex - 1;
1992       
1993                        if (this.placeholderToParameterIndexMap != null) {
1994                                localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
1995                        }
1996       
1997                        int rsIndex = this.parameterIndexToRsIndex[localParamIndex];
1998       
1999                        if (rsIndex == NOT_OUTPUT_PARAMETER_INDICATOR) {
2000                                throw SQLError.createSQLException(
2001                                                Messages.getString("CallableStatement.21") + paramIndex //$NON-NLS-1$
2002                                                                + Messages.getString("CallableStatement.22"), //$NON-NLS-1$
2003                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
2004                        }
2005       
2006                        return rsIndex + 1;
2007                }
2008        }
2009
2010        /**
2011         * @see java.sql.CallableStatement#registerOutParameter(int, int)
2012         */
2013        public void registerOutParameter(int parameterIndex, int sqlType)
2014                        throws SQLException {
2015                CallableStatementParam paramDescriptor = checkIsOutputParam(parameterIndex);
2016                paramDescriptor.desiredJdbcType = sqlType;
2017        }
2018
2019        /**
2020         * @see java.sql.CallableStatement#registerOutParameter(int, int, int)
2021         */
2022        public void registerOutParameter(int parameterIndex, int sqlType, int scale)
2023                        throws SQLException {
2024                registerOutParameter(parameterIndex, sqlType);
2025        }
2026
2027        /**
2028         * @see java.sql.CallableStatement#registerOutParameter(int, int,
2029         *      java.lang.String)
2030         */
2031        public void registerOutParameter(int parameterIndex, int sqlType,
2032                        String typeName) throws SQLException {
2033                checkIsOutputParam(parameterIndex);
2034        }
2035
2036        /**
2037         * @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
2038         *      int)
2039         */
2040        public void registerOutParameter(String parameterName,
2041                        int sqlType) throws SQLException {
2042                synchronized (checkClosed()) {
2043                        registerOutParameter(getNamedParamIndex(parameterName, true), sqlType);
2044                }
2045        }
2046
2047        /**
2048         * @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
2049         *      int, int)
2050         */
2051        public void registerOutParameter(String parameterName, int sqlType,
2052                        int scale) throws SQLException {
2053                registerOutParameter(getNamedParamIndex(parameterName, true), sqlType);
2054        }
2055
2056        /**
2057         * @see java.sql.CallableStatement#registerOutParameter(java.lang.String,
2058         *      int, java.lang.String)
2059         */
2060        public void registerOutParameter(String parameterName, int sqlType,
2061                        String typeName) throws SQLException {
2062                registerOutParameter(getNamedParamIndex(parameterName, true), sqlType,
2063                                typeName);
2064        }
2065
2066        /**
2067         * Issues a second query to retrieve all output parameters.
2068         *
2069         * @throws SQLException
2070         *             if an error occurs.
2071         */
2072        private void retrieveOutParams() throws SQLException {
2073                synchronized (checkClosed()) {
2074                        int numParameters = this.paramInfo.numberOfParameters();
2075       
2076                        this.parameterIndexToRsIndex = new int[numParameters];
2077       
2078                        for (int i = 0; i < numParameters; i++) {
2079                                this.parameterIndexToRsIndex[i] = NOT_OUTPUT_PARAMETER_INDICATOR;
2080                        }
2081       
2082                        int localParamIndex = 0;
2083       
2084                        if (numParameters > 0) {
2085                                StringBuffer outParameterQuery = new StringBuffer("SELECT "); //$NON-NLS-1$
2086       
2087                                boolean firstParam = true;
2088                                boolean hadOutputParams = false;
2089       
2090                                for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
2091                                                .hasNext();) {
2092                                        CallableStatementParam retrParamInfo = paramIter
2093                                                        .next();
2094       
2095                                        if (retrParamInfo.isOut) {
2096                                                hadOutputParams = true;
2097       
2098                                                this.parameterIndexToRsIndex[retrParamInfo.index] = localParamIndex++;
2099       
2100                                                if ((retrParamInfo.paramName == null) && (hasParametersView())) {
2101                                                        retrParamInfo.paramName = "nullnp" + retrParamInfo.index;
2102                                                }
2103                                               
2104                                                String outParameterName = mangleParameterName(retrParamInfo.paramName);
2105       
2106                                                if (!firstParam) {
2107                                                        outParameterQuery.append(","); //$NON-NLS-1$
2108                                                } else {
2109                                                        firstParam = false;
2110                                                }
2111       
2112                                                if (!outParameterName.startsWith("@")) { //$NON-NLS-1$
2113                                                        outParameterQuery.append('@');
2114                                                }
2115       
2116                                                outParameterQuery.append(outParameterName);
2117                                        }
2118                                }
2119       
2120                                if (hadOutputParams) {
2121                                        // We can't use 'ourself' to execute this query, or any
2122                                        // pending result sets would be overwritten
2123                                        java.sql.Statement outParameterStmt = null;
2124                                        java.sql.ResultSet outParamRs = null;
2125       
2126                                        try {
2127                                                outParameterStmt = this.connection.createStatement();
2128                                                outParamRs = outParameterStmt
2129                                                                .executeQuery(outParameterQuery.toString());
2130                                                this.outputParameterResults = ((com.mysql.jdbc.ResultSetInternalMethods) outParamRs)
2131                                                                .copy();
2132       
2133                                                if (!this.outputParameterResults.next()) {
2134                                                        this.outputParameterResults.close();
2135                                                        this.outputParameterResults = null;
2136                                                }
2137                                        } finally {
2138                                                if (outParameterStmt != null) {
2139                                                        outParameterStmt.close();
2140                                                }
2141                                        }
2142                                } else {
2143                                        this.outputParameterResults = null;
2144                                }
2145                        } else {
2146                                this.outputParameterResults = null;
2147                        }
2148                }
2149        }
2150
2151        /**
2152         * @see java.sql.CallableStatement#setAsciiStream(java.lang.String,
2153         *      java.io.InputStream, int)
2154         */
2155        public void setAsciiStream(String parameterName, InputStream x, int length)
2156                        throws SQLException {
2157                setAsciiStream(getNamedParamIndex(parameterName, false), x, length);
2158        }
2159
2160        /**
2161         * @see java.sql.CallableStatement#setBigDecimal(java.lang.String,
2162         *      java.math.BigDecimal)
2163         */
2164        public void setBigDecimal(String parameterName, BigDecimal x)
2165                        throws SQLException {
2166                setBigDecimal(getNamedParamIndex(parameterName, false), x);
2167        }
2168
2169        /**
2170         * @see java.sql.CallableStatement#setBinaryStream(java.lang.String,
2171         *      java.io.InputStream, int)
2172         */
2173        public void setBinaryStream(String parameterName, InputStream x, int length)
2174                        throws SQLException {
2175                setBinaryStream(getNamedParamIndex(parameterName, false), x, length);
2176        }
2177
2178        /**
2179         * @see java.sql.CallableStatement#setBoolean(java.lang.String, boolean)
2180         */
2181        public void setBoolean(String parameterName, boolean x) throws SQLException {
2182                setBoolean(getNamedParamIndex(parameterName, false), x);
2183        }
2184
2185        /**
2186         * @see java.sql.CallableStatement#setByte(java.lang.String, byte)
2187         */
2188        public void setByte(String parameterName, byte x) throws SQLException {
2189                setByte(getNamedParamIndex(parameterName, false), x);
2190        }
2191
2192        /**
2193         * @see java.sql.CallableStatement#setBytes(java.lang.String, byte[])
2194         */
2195        public void setBytes(String parameterName, byte[] x) throws SQLException {
2196                setBytes(getNamedParamIndex(parameterName, false), x);
2197        }
2198
2199        /**
2200         * @see java.sql.CallableStatement#setCharacterStream(java.lang.String,
2201         *      java.io.Reader, int)
2202         */
2203        public void setCharacterStream(String parameterName, Reader reader,
2204                        int length) throws SQLException {
2205                setCharacterStream(getNamedParamIndex(parameterName, false), reader,
2206                                length);
2207        }
2208
2209        /**
2210         * @see java.sql.CallableStatement#setDate(java.lang.String, java.sql.Date)
2211         */
2212        public void setDate(String parameterName, Date x) throws SQLException {
2213                setDate(getNamedParamIndex(parameterName, false), x);
2214        }
2215
2216        /**
2217         * @see java.sql.CallableStatement#setDate(java.lang.String, java.sql.Date,
2218         *      java.util.Calendar)
2219         */
2220        public void setDate(String parameterName, Date x, Calendar cal)
2221                        throws SQLException {
2222                setDate(getNamedParamIndex(parameterName, false), x, cal);
2223        }
2224
2225        /**
2226         * @see java.sql.CallableStatement#setDouble(java.lang.String, double)
2227         */
2228        public void setDouble(String parameterName, double x) throws SQLException {
2229                setDouble(getNamedParamIndex(parameterName, false), x);
2230        }
2231
2232        /**
2233         * @see java.sql.CallableStatement#setFloat(java.lang.String, float)
2234         */
2235        public void setFloat(String parameterName, float x) throws SQLException {
2236                setFloat(getNamedParamIndex(parameterName, false), x);
2237        }
2238
2239        /**
2240         *
2241         */
2242        private void setInOutParamsOnServer() throws SQLException {
2243                synchronized (checkClosed()) {
2244                        if (this.paramInfo.numParameters > 0) {
2245                                for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
2246                                                .hasNext();) {
2247       
2248                                        CallableStatementParam inParamInfo = paramIter
2249                                                        .next();
2250       
2251                                        //Fix for 5.5+
2252                                        if (inParamInfo.isOut && inParamInfo.isIn) {
2253                                                if ((inParamInfo.paramName == null) && (hasParametersView())) {
2254                                                        inParamInfo.paramName = "nullnp" + inParamInfo.index;
2255                                                };
2256                                               
2257                                                String inOutParameterName = mangleParameterName(inParamInfo.paramName);
2258                                                StringBuffer queryBuf = new StringBuffer(
2259                                                                4 + inOutParameterName.length() + 1 + 1);
2260                                                queryBuf.append("SET "); //$NON-NLS-1$
2261                                                queryBuf.append(inOutParameterName);
2262                                                queryBuf.append("=?"); //$NON-NLS-1$
2263       
2264                                                PreparedStatement setPstmt = null;
2265       
2266                                                try {
2267                                                        setPstmt = (PreparedStatement) this.connection
2268                                                                        .clientPrepareStatement(queryBuf.toString());
2269       
2270                                                        byte[] parameterAsBytes = getBytesRepresentation(
2271                                                                        inParamInfo.index);
2272       
2273                                                        if (parameterAsBytes != null) {
2274                                                                if (parameterAsBytes.length > 8
2275                                                                                && parameterAsBytes[0] == '_'
2276                                                                                && parameterAsBytes[1] == 'b'
2277                                                                                && parameterAsBytes[2] == 'i'
2278                                                                                && parameterAsBytes[3] == 'n'
2279                                                                                && parameterAsBytes[4] == 'a'
2280                                                                                && parameterAsBytes[5] == 'r'
2281                                                                                && parameterAsBytes[6] == 'y'
2282                                                                                && parameterAsBytes[7] == '\'') {
2283                                                                        setPstmt.setBytesNoEscapeNoQuotes(1,
2284                                                                                        parameterAsBytes);
2285                                                                } else {
2286                                                                        int sqlType = inParamInfo.desiredJdbcType;
2287                                                                       
2288                                                                        switch (sqlType) {
2289                                                                        case Types.BIT:
2290                                                                        case Types.BINARY: 
2291                                                                        case Types.BLOB: 
2292                                                                        case Types.JAVA_OBJECT:
2293                                                                        case Types.LONGVARBINARY: 
2294                                                                        case Types.VARBINARY:
2295                                                                                setPstmt.setBytes(1, parameterAsBytes);
2296                                                                                break;
2297                                                                        default:
2298                                                                                // the inherited PreparedStatement methods
2299                                                                                // have already escaped and quoted these parameters
2300                                                                                setPstmt.setBytesNoEscape(1, parameterAsBytes);
2301                                                                        }
2302                                                                }
2303                                                        } else {
2304                                                                setPstmt.setNull(1, Types.NULL);
2305                                                        }
2306       
2307                                                        setPstmt.executeUpdate();
2308                                                } finally {
2309                                                        if (setPstmt != null) {
2310                                                                setPstmt.close();
2311                                                        }
2312                                                }
2313                                        }
2314                                }
2315                        }
2316                }
2317        }
2318
2319        /**
2320         * @see java.sql.CallableStatement#setInt(java.lang.String, int)
2321         */
2322        public void setInt(String parameterName, int x) throws SQLException {
2323                setInt(getNamedParamIndex(parameterName, false), x);
2324        }
2325
2326        /**
2327         * @see java.sql.CallableStatement#setLong(java.lang.String, long)
2328         */
2329        public void setLong(String parameterName, long x) throws SQLException {
2330                setLong(getNamedParamIndex(parameterName, false), x);
2331        }
2332
2333        /**
2334         * @see java.sql.CallableStatement#setNull(java.lang.String, int)
2335         */
2336        public void setNull(String parameterName, int sqlType) throws SQLException {
2337                setNull(getNamedParamIndex(parameterName, false), sqlType);
2338        }
2339
2340        /**
2341         * @see java.sql.CallableStatement#setNull(java.lang.String, int,
2342         *      java.lang.String)
2343         */
2344        public void setNull(String parameterName, int sqlType, String typeName)
2345                        throws SQLException {
2346                setNull(getNamedParamIndex(parameterName, false), sqlType, typeName);
2347        }
2348
2349        /**
2350         * @see java.sql.CallableStatement#setObject(java.lang.String,
2351         *      java.lang.Object)
2352         */
2353        public void setObject(String parameterName, Object x) throws SQLException {
2354                setObject(getNamedParamIndex(parameterName, false), x);
2355        }
2356
2357        /**
2358         * @see java.sql.CallableStatement#setObject(java.lang.String,
2359         *      java.lang.Object, int)
2360         */
2361        public void setObject(String parameterName, Object x, int targetSqlType)
2362                        throws SQLException {
2363                setObject(getNamedParamIndex(parameterName, false), x, targetSqlType);
2364        }
2365
2366        /**
2367         * @see java.sql.CallableStatement#setObject(java.lang.String,
2368         *      java.lang.Object, int, int)
2369         */
2370        public void setObject(String parameterName, Object x, int targetSqlType,
2371                        int scale) throws SQLException {
2372        }
2373
2374        private void setOutParams() throws SQLException {
2375                synchronized (checkClosed()) {
2376                        if (this.paramInfo.numParameters > 0) {
2377                                for (Iterator<CallableStatementParam> paramIter = this.paramInfo.iterator(); paramIter
2378                                                .hasNext();) {
2379                                        CallableStatementParam outParamInfo = paramIter
2380                                                        .next();
2381       
2382                                        if (!this.callingStoredFunction && outParamInfo.isOut) {
2383       
2384                                                if ((outParamInfo.paramName == null) && (hasParametersView())) {
2385                                                        outParamInfo.paramName = "nullnp" + outParamInfo.index;
2386                                                };
2387       
2388                                                String outParameterName = mangleParameterName(outParamInfo.paramName);
2389       
2390                                                int outParamIndex = 0;
2391                                               
2392                                                if (this.placeholderToParameterIndexMap == null) { 
2393                                                                outParamIndex = outParamInfo.index + 1;
2394                                                } else {
2395                                                                // Find it, todo: remove this linear search
2396                                                                boolean found = false;
2397                                                               
2398                                                                for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
2399                                                                        if (this.placeholderToParameterIndexMap[i] == outParamInfo.index) {
2400                                                                                outParamIndex = i + 1; /* JDBC is 1-based */
2401                                                                                found = true;
2402                                                                                break;
2403                                                                        }
2404                                                                }
2405                                                               
2406                                                                if (!found) {
2407                                                                        throw SQLError.createSQLException("boo!", "S1000", this.connection.getExceptionInterceptor());
2408                                                                }
2409                                                }
2410                                               
2411                                                this.setBytesNoEscapeNoQuotes(outParamIndex,
2412                                                                StringUtils.getBytes(outParameterName,
2413                                                                                this.charConverter, this.charEncoding,
2414                                                                                this.connection
2415                                                                                                .getServerCharacterEncoding(),
2416                                                                                this.connection.parserKnowsUnicode(), getExceptionInterceptor()));
2417                                        }
2418                                }
2419                        }
2420                }
2421        }
2422
2423        /**
2424         * @see java.sql.CallableStatement#setShort(java.lang.String, short)
2425         */
2426        public void setShort(String parameterName, short x) throws SQLException {
2427                setShort(getNamedParamIndex(parameterName, false), x);
2428        }
2429
2430        /**
2431         * @see java.sql.CallableStatement#setString(java.lang.String,
2432         *      java.lang.String)
2433         */
2434        public void setString(String parameterName, String x) throws SQLException {
2435                setString(getNamedParamIndex(parameterName, false), x);
2436        }
2437
2438        /**
2439         * @see java.sql.CallableStatement#setTime(java.lang.String, java.sql.Time)
2440         */
2441        public void setTime(String parameterName, Time x) throws SQLException {
2442                setTime(getNamedParamIndex(parameterName, false), x);
2443        }
2444
2445        /**
2446         * @see java.sql.CallableStatement#setTime(java.lang.String, java.sql.Time,
2447         *      java.util.Calendar)
2448         */
2449        public void setTime(String parameterName, Time x, Calendar cal)
2450                        throws SQLException {
2451                setTime(getNamedParamIndex(parameterName, false), x, cal);
2452        }
2453
2454        /**
2455         * @see java.sql.CallableStatement#setTimestamp(java.lang.String,
2456         *      java.sql.Timestamp)
2457         */
2458        public void setTimestamp(String parameterName, Timestamp x)
2459                        throws SQLException {
2460                setTimestamp(getNamedParamIndex(parameterName, false), x);
2461        }
2462
2463        /**
2464         * @see java.sql.CallableStatement#setTimestamp(java.lang.String,
2465         *      java.sql.Timestamp, java.util.Calendar)
2466         */
2467        public void setTimestamp(String parameterName, Timestamp x, Calendar cal)
2468                        throws SQLException {
2469                setTimestamp(getNamedParamIndex(parameterName, false), x, cal);
2470        }
2471
2472        /**
2473         * @see java.sql.CallableStatement#setURL(java.lang.String, java.net.URL)
2474         */
2475        public void setURL(String parameterName, URL val) throws SQLException {
2476                setURL(getNamedParamIndex(parameterName, false), val);
2477        }
2478
2479        /**
2480         * @see java.sql.CallableStatement#wasNull()
2481         */
2482        public boolean wasNull() throws SQLException {
2483                synchronized (checkClosed()) {
2484                        return this.outputParamWasNull;
2485                }
2486        }
2487
2488        public int[] executeBatch() throws SQLException {
2489                if (this.hasOutputParams) {
2490                        throw SQLError.createSQLException("Can't call executeBatch() on CallableStatement with OUTPUT parameters",
2491                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
2492                }
2493               
2494                return super.executeBatch();
2495        }
2496
2497        protected int getParameterIndexOffset() {
2498                if (this.callingStoredFunction) {
2499                        return -1;
2500                }
2501               
2502                return super.getParameterIndexOffset();
2503        }
2504       
2505        public void setAsciiStream(String parameterName, InputStream x) throws SQLException {
2506                setAsciiStream(getNamedParamIndex(parameterName, false), x);
2507               
2508        }
2509
2510        public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {
2511                setAsciiStream(getNamedParamIndex(parameterName, false), x, length);
2512               
2513        }
2514
2515        public void setBinaryStream(String parameterName, InputStream x) throws SQLException {
2516                setBinaryStream(getNamedParamIndex(parameterName, false), x);
2517               
2518        }
2519
2520        public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {
2521                setBinaryStream(getNamedParamIndex(parameterName, false), x, length);
2522               
2523        }
2524
2525        public void setBlob(String parameterName, Blob x) throws SQLException {
2526                setBlob(getNamedParamIndex(parameterName, false), x);
2527               
2528        }
2529
2530        public void setBlob(String parameterName, InputStream inputStream) throws SQLException {
2531                setBlob(getNamedParamIndex(parameterName, false), inputStream);
2532               
2533        }
2534
2535        public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {
2536                setBlob(getNamedParamIndex(parameterName, false), inputStream, length);
2537               
2538        }
2539
2540        public void setCharacterStream(String parameterName, Reader reader) throws SQLException {
2541                setCharacterStream(getNamedParamIndex(parameterName, false), reader);
2542               
2543        }
2544
2545        public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {
2546                setCharacterStream(getNamedParamIndex(parameterName, false), reader, length);
2547               
2548        }
2549
2550        public void setClob(String parameterName, Clob x) throws SQLException {
2551                setClob(getNamedParamIndex(parameterName, false), x);
2552               
2553        }
2554
2555        public void setClob(String parameterName, Reader reader) throws SQLException {
2556                setClob(getNamedParamIndex(parameterName, false), reader);
2557               
2558        }
2559
2560        public void setClob(String parameterName, Reader reader, long length) throws SQLException {
2561                setClob(getNamedParamIndex(parameterName, false), reader, length);
2562               
2563        }
2564
2565        public void setNCharacterStream(String parameterName, Reader value) throws SQLException {
2566                setNCharacterStream(getNamedParamIndex(parameterName, false), value);
2567               
2568        }
2569
2570        public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {
2571                setNCharacterStream(getNamedParamIndex(parameterName, false), value, length);
2572               
2573        }
2574       
2575        /**
2576         * Check whether the stored procedure alters any data or is safe for read-only usage.
2577         *
2578         * @return true if procedure does not alter data
2579         * @throws SQLException
2580         */
2581        private boolean checkReadOnlyProcedure() throws SQLException {
2582                synchronized (checkClosed()) {
2583                        if (this.connection.getNoAccessToProcedureBodies()) {
2584                                return false;
2585                        }
2586
2587                        if (this.paramInfo.isReadOnlySafeChecked) {
2588                                return this.paramInfo.isReadOnlySafeProcedure;
2589                        }
2590
2591                        ResultSet rs = null;
2592                        java.sql.PreparedStatement ps = null;
2593                       
2594                        try {
2595                                String procName = extractProcedureName();
2596
2597                                String catalog = this.currentCatalog;
2598
2599                                if (procName.indexOf(".") != -1) {
2600                                        catalog = procName.substring(0, procName.indexOf("."));
2601                                       
2602                                        if (StringUtils.startsWithIgnoreCaseAndWs(catalog, "`") && catalog.trim().endsWith("`")) {
2603                                                catalog = catalog.substring(1, catalog.length() - 1);
2604                                        }
2605                                       
2606                                        procName = procName.substring(procName.indexOf(".") + 1);
2607                                        procName = StringUtils.toString(StringUtils.stripEnclosure(
2608                                                        StringUtils.getBytes(procName), "`", "`"));
2609                                }
2610                                ps = this.connection
2611                                                .prepareStatement("SELECT SQL_DATA_ACCESS FROM "
2612                                                                + " information_schema.routines "
2613                                                                + " WHERE routine_schema = ? "
2614                                                                + " AND routine_name = ?");
2615                                ps.setMaxRows(0);
2616                                ps.setFetchSize(0);
2617
2618                                ps.setString(1, catalog);
2619                                ps.setString(2, procName);
2620                                rs = ps.executeQuery();
2621                                if (rs.next()) {
2622                                        String sqlDataAccess = rs.getString(1);
2623                                        if ("READS SQL DATA".equalsIgnoreCase(sqlDataAccess)
2624                                                        || "NO SQL".equalsIgnoreCase(sqlDataAccess)) {
2625                                                synchronized (this.paramInfo) {
2626                                                        this.paramInfo.isReadOnlySafeChecked = true;
2627                                                        this.paramInfo.isReadOnlySafeProcedure = true;
2628                                                }
2629                                                return true;
2630                                        }
2631                                }
2632                        } catch (SQLException e) {
2633                                // swallow the Exception
2634                        } finally {
2635                                if(rs != null){
2636                                        rs.close();
2637                                }
2638                                if(ps != null){
2639                                        ps.close();
2640                                }
2641                               
2642                        }
2643                        this.paramInfo.isReadOnlySafeChecked = false;
2644                        this.paramInfo.isReadOnlySafeProcedure = false;
2645                }
2646                return false;
2647                                       
2648        }
2649
2650        protected boolean checkReadOnlySafeStatement() throws SQLException {
2651                return (super.checkReadOnlySafeStatement() || this.checkReadOnlyProcedure());
2652        }
2653       
2654        private boolean hasParametersView() throws SQLException {
2655                synchronized (checkClosed()) {
2656                        try {
2657                                if (this.connection.versionMeetsMinimum(5, 5, 0)) {
2658                                        java.sql.DatabaseMetaData dbmd1 = new DatabaseMetaDataUsingInfoSchema(this.connection, this.connection.getCatalog());
2659                                        return ((DatabaseMetaDataUsingInfoSchema)dbmd1).gethasParametersView();
2660                                }
2661                                       
2662                                return false;
2663                        } catch (SQLException e) {
2664                                return false;
2665                        }
2666                }
2667        }
2668}
Note: See TracBrowser for help on using the repository browser.