0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.drda.DRDAStatement
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.drda;
0023:
0024: import java.io.UnsupportedEncodingException;
0025: import java.lang.reflect.InvocationTargetException;
0026: import java.lang.reflect.Method;
0027: import java.math.BigInteger;
0028: import java.sql.CallableStatement;
0029: import java.sql.Connection;
0030: import java.sql.PreparedStatement;
0031: import java.sql.ResultSet;
0032: import java.sql.SQLException;
0033: import java.sql.Statement;
0034: import java.util.ArrayList;
0035: import java.util.Hashtable;
0036: import java.util.StringTokenizer;
0037: import java.util.Vector;
0038:
0039: import org.apache.derby.iapi.jdbc.BrokeredConnection;
0040: import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement;
0041: import org.apache.derby.iapi.jdbc.EngineConnection;
0042: import org.apache.derby.iapi.jdbc.EngineStatement;
0043: import org.apache.derby.iapi.jdbc.EnginePreparedStatement;
0044: import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
0045: import org.apache.derby.iapi.reference.JDBC30Translation;
0046: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0047: import org.apache.derby.iapi.util.StringUtil;
0048: import org.apache.derby.impl.jdbc.Util;
0049:
0050: /**
0051: DRDAStatement stores information about the statement being executed
0052: */
0053: class DRDAStatement {
0054:
0055: //NOTE!
0056: //
0057: // Since DRDAStatements are reused, ALL variables (except those noted in
0058: // the comments for reset method) should be set to their default values
0059: // in reset().
0060:
0061: protected String typDefNam; //TYPDEFNAM for this statement
0062: protected int byteOrder; //deduced from typDefNam, save String comparisons
0063: protected int ccsidSBC; //CCSID for single byte characters
0064: protected int ccsidDBC; //CCSID for double byte characters
0065: protected int ccsidMBC; //CCSID for mixed byte characters
0066: protected String ccsidSBCEncoding; //Java encoding for CCSIDSBC
0067: protected String ccsidDBCEncoding; //Java encoding for CCSIDDBC
0068: protected String ccsidMBCEncoding; //Java encoding for CCSIDMBC
0069:
0070: protected Database database; // Database this statement is created for
0071: private Pkgnamcsn pkgnamcsn; // Package name/section # and consistency token
0072: protected ConsistencyToken pkgcnstkn; // Consistency token for the first result set
0073: protected String pkgid; // package id
0074: protected int pkgsn; // section number
0075: int withHoldCursor = -1; // hold cursor after commit attribute.
0076: protected int isolationLevel; //JCC isolation level for Statement
0077: protected String cursorName;
0078: protected int scrollType = ResultSet.TYPE_FORWARD_ONLY; // Sensitive or Insensitive scroll attribute
0079: protected int concurType = ResultSet.CONCUR_READ_ONLY;; // Concurency type
0080: protected long rowCount; // Number of rows we have processed
0081: protected byte[] rslsetflg; // Result Set Flags
0082: protected int maxrslcnt; // Maximum Result set count
0083: protected PreparedStatement ps; // Prepared statement
0084: protected EngineParameterMetaData stmtPmeta; // param metadata
0085: protected boolean isCall;
0086: protected String procName; // callable statement's method name
0087: private int[] outputTypes; // jdbc type for output parameter or NOT_OUTPUT_PARAM
0088: // if not an output parameter.
0089: protected static int NOT_OUTPUT_PARAM = -100000;
0090: protected boolean outputExpected; // expect output from a callable statement
0091: private Statement stmt; // SQL statement
0092:
0093: private DRDAResultSet currentDrdaRs; // Current ResultSet
0094: private Hashtable resultSetTable; // Hashtable with resultsets
0095: private ArrayList resultSetKeyList; // ordered list of hash keys
0096: private int numResultSets = 0;
0097:
0098: // State for parameter data
0099: protected Vector cliParamDrdaTypes = new Vector();
0100: protected Vector cliParamLens = new Vector();
0101: protected ArrayList cliParamExtPositions = null;
0102:
0103: // Query options sent on EXCSQLSTT
0104: // These the default for ResultSets created for this statement.
0105: // These can be overriden by OPNQRY or CNTQRY,
0106: protected int nbrrow; // number of fetch or insert rows
0107: protected int qryrowset; // Query row set
0108: protected int blksize; // Query block size
0109: protected int maxblkext; // Maximum number of extra blocks
0110: protected int outovropt; // Output Override option
0111: protected boolean qryrfrtbl; // Query refresh answer set table
0112: private int qryprctyp = CodePoint.QRYBLKCTL_DEFAULT; // Protocol type
0113:
0114: boolean needsToSendParamData = false;
0115: boolean explicitlyPrepared = false; //Prepared with PRPSQLSTT (reusable)
0116:
0117: // constructor
0118: /**
0119: * DRDAStatement constructor
0120: *
0121: * @param database
0122: *
0123: */
0124: DRDAStatement(Database database) {
0125: this .database = database;
0126: setTypDefValues();
0127: this .currentDrdaRs = new DRDAResultSet();
0128: }
0129:
0130: /**
0131: * set TypDef values
0132: *
0133: */
0134: protected void setTypDefValues() {
0135: // initialize statement values to current database values
0136: this .typDefNam = database.typDefNam;
0137: this .byteOrder = database.byteOrder;
0138: this .ccsidSBC = database.ccsidSBC;
0139: this .ccsidDBC = database.ccsidDBC;
0140: this .ccsidMBC = database.ccsidMBC;
0141: this .ccsidSBCEncoding = database.ccsidSBCEncoding;
0142: this .ccsidDBCEncoding = database.ccsidDBCEncoding;
0143: this .ccsidMBCEncoding = database.ccsidMBCEncoding;
0144: }
0145:
0146: /**
0147: * Set database
0148: *
0149: * @param database
0150: */
0151: protected void setDatabase(Database database) {
0152: this .database = database;
0153: setTypDefValues();
0154: }
0155:
0156: /**
0157: * Set statement
0158: *
0159: * @param conn Connection
0160: * @exception SQLException
0161: */
0162: protected void setStatement(Connection conn) throws SQLException {
0163: stmt = conn.createStatement();
0164: //beetle 3849 - see prepareStatement for details
0165: if (cursorName != null)
0166: stmt.setCursorName(cursorName);
0167: }
0168:
0169: /**
0170: * Get the statement
0171: *
0172: * @return statement
0173: * @exception SQLException
0174: */
0175: protected Statement getStatement() throws SQLException {
0176: return stmt;
0177: }
0178:
0179: /**Set resultSet defaults to match
0180: * the statement defaults sent on EXCSQLSTT
0181: * This might be overridden on OPNQRY or CNTQRY
0182: **/
0183:
0184: protected void setRsDefaultOptions(DRDAResultSet drs) {
0185: drs.nbrrow = nbrrow;
0186: drs.qryrowset = qryrowset;
0187: drs.blksize = blksize;
0188: drs.maxblkext = maxblkext;
0189: drs.outovropt = outovropt;
0190: drs.rslsetflg = rslsetflg;
0191: drs.scrollType = scrollType;
0192: drs.concurType = concurType;
0193: drs.setQryprctyp(qryprctyp);
0194: drs.qryrowset = qryrowset;
0195: }
0196:
0197: /**
0198: * Get the extData Objects
0199: *
0200: * @return ArrayList with extdta
0201: */
0202: protected ArrayList getExtDtaObjects() {
0203: return currentDrdaRs.getExtDtaObjects();
0204: }
0205:
0206: /**
0207: * Set the extData Objects
0208: */
0209: protected void setExtDtaObjects(ArrayList a) {
0210: currentDrdaRs.setExtDtaObjects(a);
0211: }
0212:
0213: public void setSplitQRYDTA(byte[] data) {
0214: currentDrdaRs.setSplitQRYDTA(data);
0215: }
0216:
0217: public byte[] getSplitQRYDTA() {
0218: return currentDrdaRs.getSplitQRYDTA();
0219: }
0220:
0221: /**
0222: * Add extDtaObject
0223: * @param o - object to add
0224: * @param jdbcIndex - jdbc index for parameter
0225: */
0226: protected void addExtDtaObject(Object o, int jdbcIndex) {
0227: currentDrdaRs.addExtDtaObject(o, jdbcIndex);
0228: }
0229:
0230: /**
0231: * Clear externalized lob objects in current result set
0232: */
0233: protected void clearExtDtaObjects() {
0234: currentDrdaRs.clearExtDtaObjects();
0235: }
0236:
0237: /**
0238: *
0239: * get resultSetHoldability.
0240: *
0241: * @return the resultSet holdability for the prepared statement
0242: *
0243: */
0244: protected int getResultSetHoldability() throws SQLException {
0245: Statement rsstmt;
0246: ResultSet rs = getResultSet();
0247:
0248: if (rs != null)
0249: rsstmt = rs.getStatement();
0250: else
0251: rsstmt = getPreparedStatement();
0252:
0253: int holdValue = ((EngineStatement) rsstmt)
0254: .getResultSetHoldability();
0255:
0256: return holdValue;
0257: }
0258:
0259: /**
0260: *
0261: * get resultSetHoldability.
0262: *
0263: * @param rs ResultSet
0264: * @return the resultSet holdability for the prepared statement
0265: *
0266: */
0267: int getResultSetHoldability(ResultSet rs) throws SQLException {
0268: Statement rsstmt;
0269:
0270: if (rs != null)
0271: rsstmt = rs.getStatement();
0272: else
0273: rsstmt = getPreparedStatement();
0274:
0275: int holdValue = ((EngineStatement) rsstmt)
0276: .getResultSetHoldability();
0277:
0278: return holdValue;
0279: }
0280:
0281: /*
0282: * Is lob object nullable
0283: * @param index - offset starting with 0
0284: * @return true if object is nullable
0285: */
0286: protected boolean isExtDtaValueNullable(int index) {
0287: return currentDrdaRs.isExtDtaValueNullable(index);
0288: }
0289:
0290: /**
0291: * Set query options sent on OPNQRY and pass options down to the
0292: * current <code>DRDAResultSet</code> object.
0293: *
0294: * @param blksize QRYBLKSZ (Query Block Size)
0295: * @param qryblkctl QRYPRCTYP (Query Protocol Type)
0296: * @param maxblkext MAXBLKEXT (Maximum Number of Extra Blocks)
0297: * @param outovropt OUTOVROPT (Output Override Option)
0298: * @param qryrowset QRYROWSET (Query Rowset Size)
0299: * @param qryclsimpl QRYCLSIMP (Query Close Implicit)
0300: * @see DRDAResultSet#setOPNQRYOptions(int, int, int, int, int, int)
0301: */
0302: protected void setOPNQRYOptions(int blksize, int qryblkctl,
0303: int maxblkext, int outovropt, int qryrowset, int qryclsimpl) {
0304: this .blksize = blksize;
0305: this .qryprctyp = qryblkctl;
0306: this .maxblkext = maxblkext;
0307: this .outovropt = outovropt;
0308: this .qryrowset = qryrowset;
0309: currentDrdaRs.setOPNQRYOptions(blksize, qryblkctl, maxblkext,
0310: outovropt, qryrowset, qryclsimpl);
0311: }
0312:
0313: /*
0314: * Set query options sent on CNTQRY
0315: */
0316: protected void setQueryOptions(int blksize, boolean qryrelscr,
0317: long qryrownbr, boolean qryfrtbl, int nbrrow,
0318: int maxblkext, int qryscrorn, boolean qryrowsns,
0319: boolean qryblkrst, boolean qryrtndta, int qryrowset,
0320: int rtnextdta) {
0321: currentDrdaRs.blksize = blksize;
0322: currentDrdaRs.qryrelscr = qryrelscr;
0323: currentDrdaRs.qryrownbr = qryrownbr;
0324: currentDrdaRs.qryrfrtbl = qryrfrtbl;
0325: currentDrdaRs.nbrrow = nbrrow;
0326: currentDrdaRs.maxblkext = maxblkext;
0327: currentDrdaRs.qryscrorn = qryscrorn;
0328: currentDrdaRs.qryrowsns = qryrowsns;
0329: currentDrdaRs.qryblkrst = qryblkrst;
0330: currentDrdaRs.qryrtndta = qryrtndta;
0331: currentDrdaRs.qryrowset = qryrowset;
0332: currentDrdaRs.rtnextdta = rtnextdta;
0333: }
0334:
0335: protected void setQryprctyp(int qryprctyp) {
0336: this .qryprctyp = qryprctyp;
0337: currentDrdaRs.setQryprctyp(qryprctyp);
0338: }
0339:
0340: protected int getQryprctyp() throws SQLException {
0341: return currentDrdaRs.getQryprctyp();
0342: }
0343:
0344: protected void setQryrownbr(long qryrownbr) {
0345: currentDrdaRs.qryrownbr = qryrownbr;
0346: }
0347:
0348: protected long getQryrownbr() {
0349: return currentDrdaRs.qryrownbr;
0350: }
0351:
0352: protected int getQryrowset() {
0353: return currentDrdaRs.qryrowset;
0354: }
0355:
0356: protected int getBlksize() {
0357: return currentDrdaRs.blksize;
0358: }
0359:
0360: protected void setQryrtndta(boolean qryrtndta) {
0361: currentDrdaRs.qryrtndta = qryrtndta;
0362: }
0363:
0364: protected boolean getQryrtndta() {
0365: return currentDrdaRs.qryrtndta;
0366: }
0367:
0368: protected void setQryscrorn(int qryscrorn) {
0369: currentDrdaRs.qryscrorn = qryscrorn;
0370: }
0371:
0372: protected int getQryscrorn() {
0373: return currentDrdaRs.qryscrorn;
0374: }
0375:
0376: protected void setScrollType(int scrollType) {
0377: currentDrdaRs.scrollType = scrollType;
0378: }
0379:
0380: protected int getScrollType() {
0381: return currentDrdaRs.scrollType;
0382: }
0383:
0384: /**
0385: * is this a scrollable cursor?
0386: * return true if this is not a forward only cursor
0387: */
0388: protected boolean isScrollable() {
0389: return (getScrollType() != ResultSet.TYPE_FORWARD_ONLY);
0390: }
0391:
0392: protected void setConcurType(int scrollType) {
0393: currentDrdaRs.concurType = scrollType;
0394: }
0395:
0396: protected int getConcurType() {
0397: return currentDrdaRs.concurType;
0398: }
0399:
0400: protected void setOutovr_drdaType(int[] outovr_drdaType) {
0401: currentDrdaRs.outovr_drdaType = outovr_drdaType;
0402: }
0403:
0404: protected int[] getOutovr_drdaType() {
0405: return currentDrdaRs.outovr_drdaType;
0406: }
0407:
0408: protected boolean hasdata() {
0409: return currentDrdaRs.hasdata;
0410: }
0411:
0412: protected void setHasdata(boolean hasdata) {
0413: currentDrdaRs.hasdata = hasdata;
0414: }
0415:
0416: /**
0417: * This method is used to initialize the default statement of the database
0418: * for re-use. It is different from reset() method since default statements
0419: * get initiliazed differently. e.g: stmt variable used in default statement
0420: * is created only once in Database.makeConnection.
0421: * TODO: Need to see what exactly it means to initialize the default
0422: * statement. (DERBY-1002)
0423: *
0424: */
0425: protected void initialize() {
0426: setTypDefValues();
0427: }
0428:
0429: protected PreparedStatement explicitPrepare(String sqlStmt)
0430: throws SQLException {
0431: explicitlyPrepared = true;
0432: return prepare(sqlStmt);
0433: }
0434:
0435: protected boolean wasExplicitlyPrepared() {
0436: return explicitlyPrepared;
0437: }
0438:
0439: /**
0440: * Create a prepared statement
0441: *
0442: * @param sqlStmt - SQL statement
0443: *
0444: * @exception SQLException
0445: */
0446: protected PreparedStatement prepare(String sqlStmt)
0447: throws SQLException {
0448: // save current prepare iso level
0449: int saveIsolationLevel = -1;
0450: boolean isolationSet = false;
0451: if (pkgnamcsn != null
0452: && isolationLevel != Connection.TRANSACTION_NONE) {
0453: saveIsolationLevel = database.getPrepareIsolation();
0454: database.setPrepareIsolation(isolationLevel);
0455: isolationSet = true;
0456: }
0457:
0458: if (isCallableSQL(sqlStmt)) {
0459: isCall = true;
0460: ps = database.getConnection().prepareCall(sqlStmt);
0461: setupCallableStatementParams((CallableStatement) ps);
0462: if (isolationSet)
0463: database.setPrepareIsolation(saveIsolationLevel);
0464: return ps;
0465: }
0466: parsePkgidToFindHoldability();
0467: ps = prepareStatementJDBC3(sqlStmt, scrollType, concurType,
0468: withHoldCursor);
0469: // beetle 3849 - Need to change the cursor name to what
0470: // JCC thinks it will be, since there is no way in the
0471: // protocol to communicate the actual cursor name. JCC keeps
0472: // a mapping from the client cursor names to the DB2 style cursor names
0473: if (cursorName != null)//cursorName not null means we are dealing with dynamic pacakges
0474: ps.setCursorName(cursorName);
0475: if (isolationSet)
0476: database.setPrepareIsolation(saveIsolationLevel);
0477: return ps;
0478: }
0479:
0480: /**
0481: * Get prepared statement
0482: *
0483: * @return prepared statement
0484: */
0485: protected PreparedStatement getPreparedStatement()
0486: throws SQLException {
0487: return ps;
0488: }
0489:
0490: /**
0491: * Executes the prepared statement and populates the resultSetTable.
0492: * Access to the various resultSets is then possible by using
0493: * setCurrentDrdaResultSet(String pkgnamcsn) to set the current
0494: * resultSet and then calling getResultSet() or the other access
0495: * methods to get resultset data.
0496: *
0497: * @return true if the execution has resultSets
0498: */
0499: protected boolean execute() throws SQLException {
0500: boolean hasResultSet = ps.execute();
0501:
0502: // java.sql.Statement says any result sets that are opened
0503: // when the statement is re-executed must be closed; this
0504: // is handled by the call to "ps.execute()" above--but we
0505: // also have to reset our 'numResultSets' counter, since
0506: // all previously opened result sets are now invalid.
0507: numResultSets = 0;
0508:
0509: ResultSet rs = null;
0510: boolean isCallable = (ps instanceof java.sql.CallableStatement);
0511: if (isCallable)
0512: needsToSendParamData = true;
0513:
0514: do {
0515: rs = ps.getResultSet();
0516: if (rs != null) {
0517: //For callable statement, get holdability of statement generating the result set
0518: if (isCallable)
0519: addResultSet(rs, getResultSetHoldability(rs));
0520: else
0521: addResultSet(rs, withHoldCursor);
0522: hasResultSet = true;
0523: }
0524: // For normal selects we are done, but procedures might
0525: // have more resultSets
0526: } while (isCallable
0527: && getMoreResults(JDBC30Translation.KEEP_CURRENT_RESULT));
0528:
0529: return hasResultSet;
0530:
0531: }
0532:
0533: /**
0534: * clear out type data for parameters.
0535: * Unfortunately we currently overload the resultSet type info
0536: * rsDRDATypes et al with parameter info.
0537: * RESOLVE: Need to separate this
0538: */
0539: protected void finishParams() {
0540: needsToSendParamData = false;
0541: }
0542:
0543: /**
0544: * Set the pkgid sec num for this statement and the
0545: * consistency token that will be used for the first resultSet.
0546: * For dyamic packages The package name is encoded as follows
0547: * SYS(S/L)(H/N)xyy
0548: * where 'S' represents Small package and 'L' large
0549: * (ignored by cloudscape)
0550: * Where 'H' represents WITH HOLD, and 'N' represents NO WITH HOLD.
0551: * (May be overridden by SQLATTR for WITH
0552: * HOLD")
0553: *
0554: * Where 'www' is the package iteration (ignored by cloudcape)
0555: * Where 'x' is the isolation level: 0=NC, 1=UR, 2=CS, 3=RS, 4=RR
0556: * Where 'yy' is the package iteration 00 through FF
0557: * Where 'zz' is unique for each platform
0558: * Happilly, these values correspond precisely to the internal cloudscape
0559: * isolation levels in ExecutionContext.java
0560: * x Isolation Level
0561: * -- ---------------------
0562: * 0 NC (java.sql.Connection.TRANSACTION_NONE)
0563: * 1 UR (java.sql.Connection.TRANACTION_READ_UNCOMMITTED)
0564: * 2 CS (java.sql.Connection.TRANSACTION_READ_COMMITTED)
0565: * 3 RS (java.sql.Connection.TRANSACTION_REPEATABLE_READ)
0566: * 4 RR (java.sql.Connection.TRANSACTION_SERIALIZABLE)
0567: *
0568: * static packages have preset isolation levels
0569: * (see getStaticPackageIsolation)
0570: * @param pkgnamcsn package id section number and token from the client
0571: */
0572: protected void setPkgnamcsn(Pkgnamcsn pkgnamcsn) {
0573: this .pkgnamcsn = pkgnamcsn;
0574: // Store the consistency string for the first ResultSet.
0575: // this will be used to calculate consistency strings for the
0576: // other result sets.
0577: pkgid = pkgnamcsn.getPkgid();
0578:
0579: if (isDynamicPkgid(pkgid)) {
0580: isolationLevel = Integer.parseInt(pkgid.substring(5, 6));
0581:
0582: /*
0583: * generate DB2-style cursorname
0584: * example value : SQL_CURSN200C1
0585: * where
0586: * SQL_CUR is db2 cursor name prefix;
0587: * S - Small package , L -Large package
0588: * N - normal cursor, H - hold cursor
0589: * 200 - package id as sent by jcc
0590: * C - tack-on code for cursors
0591: * 1 - section number sent by jcc
0592: */
0593:
0594: // cursor name
0595: // trim the SYS off the pkgid so it wont' be in the cursor name
0596: String shortPkgid = pkgid.substring(pkgid.length() - 5,
0597: pkgid.length());
0598: pkgsn = pkgnamcsn.getPkgsn();
0599: this .cursorName = "SQL_CUR" + shortPkgid + "C" + pkgsn;
0600: } else // static package
0601: {
0602: isolationLevel = getStaticPackageIsolation(pkgid);
0603: }
0604:
0605: this .pkgcnstkn = pkgnamcsn.getPkgcnstkn();
0606:
0607: }
0608:
0609: /**
0610: * get the isolation level for a static package.
0611: * @param pkgid - Package identifier string (e.g. SYSSTAT)
0612: * @return isolation
0613: */
0614: private int getStaticPackageIsolation(String pkgid) {
0615: // SYSSTAT is used for metadata. and is the only static package used
0616: // for JCC. Other static packages will need to be supported for
0617: // CCC. Maybe a static hash table would then be in order.
0618: if (pkgid.equals("SYSSTAT"))
0619: return ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL;
0620: else
0621: return ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL;
0622: }
0623:
0624: /**
0625: * Get pkgnamcsn
0626: *
0627: * @return pkgnamcsn
0628: */
0629: protected Pkgnamcsn getPkgnamcsn() {
0630: return pkgnamcsn;
0631:
0632: }
0633:
0634: /**
0635: * Get result set
0636: *
0637: * @return result set
0638: */
0639: protected ResultSet getResultSet() {
0640: return currentDrdaRs.getResultSet();
0641: }
0642:
0643: /**
0644: * Just get the resultset. Don't set it to current
0645: * Assumes resultSet rsnum exists.
0646: *
0647: * @param rsNum resultSetNumber starting with 0
0648: * @return The result set in the order it was retrieved
0649: *
0650: * with getMoreResults()
0651: **/
0652: private ResultSet getResultSet(int rsNum) {
0653: if (rsNum == 0)
0654: return currentDrdaRs.getResultSet();
0655: else {
0656: ConsistencyToken key = (ConsistencyToken) resultSetKeyList
0657: .get(rsNum);
0658: return ((DRDAResultSet) (resultSetTable.get(key)))
0659: .getResultSet();
0660: }
0661: }
0662:
0663: /**
0664: * Set result set
0665: *
0666: * @param value
0667: */
0668: protected void setResultSet(ResultSet value) throws SQLException {
0669: if (currentDrdaRs.getResultSet() == null)
0670: numResultSets = 1;
0671: currentDrdaRs.setResultSet(value);
0672: setRsDefaultOptions(currentDrdaRs);
0673: }
0674:
0675: /**
0676: * Gets the current DRDA ResultSet
0677: *
0678: * @return DRDAResultSet
0679: */
0680: protected DRDAResultSet getCurrentDrdaResultSet() {
0681: return currentDrdaRs;
0682: }
0683:
0684: /**
0685: * Set currentDrdaResultSet
0686: *
0687: * @param rsNum The result set number starting with 0
0688: *
0689: */
0690: protected void setCurrentDrdaResultSet(int rsNum) {
0691: ConsistencyToken consistToken = getResultSetPkgcnstkn(rsNum);
0692: if (currentDrdaRs.pkgcnstkn == consistToken)
0693: return;
0694: currentDrdaRs = getDrdaResultSet(consistToken);
0695:
0696: }
0697:
0698: /**
0699: * Set currentDrdaResultSet
0700: *
0701: * @param pkgnamcsn The pkgid section number and unique resultset
0702: * consistency token
0703: *
0704: */
0705: protected void setCurrentDrdaResultSet(Pkgnamcsn pkgnamcsn) {
0706: pkgid = pkgnamcsn.getPkgid();
0707: pkgsn = pkgnamcsn.getPkgsn();
0708: ConsistencyToken consistToken = pkgnamcsn.getPkgcnstkn();
0709: DRDAResultSet newDrdaRs = getDrdaResultSet(consistToken);
0710: if (newDrdaRs != null)
0711: currentDrdaRs = newDrdaRs;
0712: }
0713:
0714: /*
0715: * get DRDAResultSet by consistency token
0716: *
0717: */
0718: private DRDAResultSet getDrdaResultSet(ConsistencyToken consistToken) {
0719: if (resultSetTable == null
0720: || (currentDrdaRs != null && currentDrdaRs.pkgcnstkn == consistToken)) {
0721: return currentDrdaRs;
0722: } else {
0723: return (DRDAResultSet) (resultSetTable.get(consistToken));
0724: }
0725: }
0726:
0727: /*
0728: * get DRDAResultSet by result set number
0729: *
0730: */
0731: private DRDAResultSet getDrdaResultSet(int rsNum) {
0732: ConsistencyToken consistToken = getResultSetPkgcnstkn(rsNum);
0733: return getDrdaResultSet(consistToken);
0734: }
0735:
0736: /** Add a new resultSet to this statement.
0737: * Set as the current result set if there is not an
0738: * existing current resultset.
0739: * @param value - ResultSet to add
0740: * @param holdValue - Holdability of the ResultSet
0741: * @return Consistency token for this resultSet
0742: * For a single resultSet that is the same as the statement's
0743: * For multiple resultSets just the consistency token is changed
0744: */
0745: protected ConsistencyToken addResultSet(ResultSet value,
0746: int holdValue) throws SQLException {
0747:
0748: DRDAResultSet newDrdaRs = null;
0749:
0750: int rsNum = numResultSets;
0751: ConsistencyToken newRsPkgcnstkn = calculateResultSetPkgcnstkn(rsNum);
0752:
0753: if (rsNum == 0)
0754: newDrdaRs = currentDrdaRs;
0755:
0756: else {
0757: newDrdaRs = new DRDAResultSet();
0758:
0759: // Multiple resultSets we neeed to setup the hash table
0760: if (resultSetTable == null) {
0761: // If hashtable doesn't exist, create it and store resultSet 0
0762: // before we store our new resultSet.
0763: // For just a single resultSet we don't ever create the Hashtable.
0764: resultSetTable = new Hashtable();
0765: resultSetTable.put(pkgcnstkn, currentDrdaRs);
0766: resultSetKeyList = new ArrayList();
0767: resultSetKeyList.add(0, pkgcnstkn);
0768: }
0769:
0770: resultSetTable.put(newRsPkgcnstkn, newDrdaRs);
0771: resultSetKeyList.add(rsNum, newRsPkgcnstkn);
0772: }
0773:
0774: newDrdaRs.setResultSet(value);
0775: newDrdaRs.setPkgcnstkn(newRsPkgcnstkn);
0776: newDrdaRs.withHoldCursor = holdValue;
0777: setRsDefaultOptions(newDrdaRs);
0778: newDrdaRs.suspend();
0779: numResultSets++;
0780: return newRsPkgcnstkn;
0781: }
0782:
0783: /**
0784: *
0785: * @return number of result sets
0786: */
0787: protected int getNumResultSets() {
0788: return numResultSets;
0789: }
0790:
0791: /**
0792: * @param rsNum result set starting with 0
0793: * @return consistency token (key) for the result set
0794: */
0795: protected ConsistencyToken getResultSetPkgcnstkn(int rsNum) {
0796: if (rsNum == 0)
0797: return pkgcnstkn;
0798: else
0799: return (ConsistencyToken) resultSetKeyList.get(rsNum);
0800: }
0801:
0802: /**
0803: * Set ResultSet DRDA DataTypes
0804: * @param value drdaTypes for columns.
0805: **/
0806: protected void setRsDRDATypes(int[] value) {
0807: currentDrdaRs.setRsDRDATypes(value);
0808: }
0809:
0810: /**
0811: *@return ResultSet DRDA DataTypes
0812: **/
0813:
0814: protected int[] getRsDRDATypes() {
0815: return currentDrdaRs.getRsDRDATypes();
0816:
0817: }
0818:
0819: /**
0820: * Set ResultSet DRDA DataTypes Lengths
0821: * @param value drdaTypes for columns.
0822: **/
0823: protected void setRsLens(int[] value) {
0824: currentDrdaRs.rsLens = value;
0825:
0826: }
0827:
0828: /**
0829: *@return ResultSet DRDA DataTypes Lengths
0830: **/
0831:
0832: protected int[] getRsLens() {
0833: return currentDrdaRs.rsLens;
0834: }
0835:
0836: /**
0837: * Close the current resultSet
0838: */
0839: protected void rsClose() throws SQLException {
0840: if (currentDrdaRs.getResultSet() == null)
0841: return;
0842:
0843: currentDrdaRs.close();
0844: needsToSendParamData = false;
0845: numResultSets--;
0846: }
0847:
0848: /**
0849: * Explicitly close the result set by CLSQRY
0850: * needed to check for double close.
0851: */
0852: protected void CLSQRY() {
0853: currentDrdaRs.CLSQRY();
0854: }
0855:
0856: /*
0857: * @return whether CLSQRY has been called on the
0858: * current result set.
0859: */
0860: protected boolean wasExplicitlyClosed() {
0861: return currentDrdaRs.wasExplicitlyClosed();
0862: }
0863:
0864: /**
0865: * This method closes the JDBC objects and frees up all references held by
0866: * this object.
0867: *
0868: * @throws SQLException
0869: */
0870: protected void close() throws SQLException {
0871: if (ps != null)
0872: ps.close();
0873: if (stmt != null)
0874: stmt.close();
0875: currentDrdaRs.close();
0876: resultSetTable = null;
0877: resultSetKeyList = null;
0878: ps = null;
0879: stmtPmeta = null;
0880: stmt = null;
0881: rslsetflg = null;
0882: procName = null;
0883: outputTypes = null;
0884: cliParamDrdaTypes = null;
0885: cliParamLens = null;
0886: cliParamExtPositions = null;
0887:
0888: }
0889:
0890: /**
0891: * This method resets the state of this DRDAStatement object so that it can
0892: * be re-used. This method should reset all variables of this class except
0893: * the following:
0894: * 1. database - This variable gets initialized in the constructor and by
0895: * call to setDatabase.
0896: * 2. members which get initialized in setPkgnamcsn (pkgnamcsn, pkgcnstkn,
0897: * pkgid, pkgsn, isolationLevel, cursorName). pkgnamcsn is the key used to
0898: * find if the DRDAStatement can be re-used. Hence its value will not change
0899: * when the object is re-used.
0900: *
0901: */
0902: protected void reset() {
0903: setTypDefValues();
0904:
0905: withHoldCursor = -1;
0906: scrollType = ResultSet.TYPE_FORWARD_ONLY;
0907: concurType = ResultSet.CONCUR_READ_ONLY;
0908: ;
0909: rowCount = 0;
0910: rslsetflg = null;
0911: maxrslcnt = 0;
0912: ps = null;
0913: stmtPmeta = null;
0914: isCall = false;
0915: procName = null;
0916: outputTypes = null;
0917: outputExpected = false;
0918: stmt = null;
0919:
0920: currentDrdaRs.reset();
0921: resultSetTable = null;
0922: resultSetKeyList = null;
0923: numResultSets = 0;
0924:
0925: cliParamDrdaTypes = new Vector();
0926: cliParamLens = new Vector();
0927: cliParamExtPositions = null;
0928:
0929: nbrrow = 0;
0930: qryrowset = 0;
0931: blksize = 0;
0932: maxblkext = 0;
0933: outovropt = 0;
0934: qryrfrtbl = false;
0935: qryprctyp = CodePoint.QRYBLKCTL_DEFAULT;
0936:
0937: needsToSendParamData = false;
0938: explicitlyPrepared = false;
0939: }
0940:
0941: /**
0942: * is Statement closed
0943: * @return whether the statement is closed
0944: */
0945: protected boolean rsIsClosed() {
0946: return currentDrdaRs.isClosed();
0947: }
0948:
0949: /**
0950: * Set state to SUSPENDED (result set is opened)
0951: */
0952: protected void rsSuspend() {
0953: currentDrdaRs.suspend();
0954: }
0955:
0956: /**
0957: * set resultset/out parameter precision
0958: *
0959: * @param index - starting with 1
0960: * @param precision
0961: */
0962: protected void setRsPrecision(int index, int precision) {
0963: currentDrdaRs.setRsPrecision(index, precision);
0964: }
0965:
0966: /**
0967: * get resultset /out paramter precision
0968: * @param index -starting with 1
0969: * @return precision of column
0970: */
0971: protected int getRsPrecision(int index) {
0972: return currentDrdaRs.getRsPrecision(index);
0973: }
0974:
0975: /**
0976: * set resultset/out parameter scale
0977: *
0978: * @param index - starting with 1
0979: * @param scale
0980: */
0981: protected void setRsScale(int index, int scale) {
0982: currentDrdaRs.setRsScale(index, scale);
0983: }
0984:
0985: /**
0986: * get resultset /out paramter scale
0987: * @param index -starting with 1
0988: * @return scale of column
0989: */
0990: protected int getRsScale(int index) {
0991: return currentDrdaRs.getRsScale(index);
0992: }
0993:
0994: /**
0995: * set result DRDAType
0996: *
0997: * @param index - starting with 1
0998: * @param type
0999: */
1000: protected void setRsDRDAType(int index, int type) {
1001: currentDrdaRs.setRsDRDAType(index, type);
1002:
1003: }
1004:
1005: /**
1006: * get parameter DRDAType
1007: *
1008: * @param index - starting with 1
1009: * @return DRDA Type of column
1010: */
1011: protected int getParamDRDAType(int index) {
1012:
1013: return ((Byte) cliParamDrdaTypes.get(index - 1)).intValue();
1014: }
1015:
1016: /**
1017: * set param DRDAType
1018: *
1019: * @param index - starting with 1
1020: * @param type
1021: */
1022: protected void setParamDRDAType(int index, byte type) {
1023: cliParamDrdaTypes.addElement(new Byte(type));
1024:
1025: }
1026:
1027: /**
1028: * returns drda length of parameter as sent by client.
1029: * @param index
1030: * @return data length
1031:
1032: */
1033:
1034: protected int getParamLen(int index) {
1035: return ((Integer) cliParamLens.elementAt(index - 1)).intValue();
1036: }
1037:
1038: /**
1039: * get parameter precision or DB2 max (31)
1040: *
1041: * @param index parameter index starting with 1
1042: *
1043: * @return precision
1044: */
1045: protected int getParamPrecision(int index) throws SQLException {
1046: if (ps != null && ps instanceof CallableStatement) {
1047: EngineParameterMetaData pmeta = getParameterMetaData();
1048:
1049: return Math.min(pmeta.getPrecision(index),
1050: FdocaConstants.NUMERIC_MAX_PRECISION);
1051:
1052: } else
1053: return -1;
1054: }
1055:
1056: /**
1057: * get parameter scale or DB2 max (31)
1058: *
1059: * @param index parameter index starting with 1
1060: *
1061: * @return scale
1062: */
1063: protected int getParamScale(int index) throws SQLException {
1064: if (ps != null && ps instanceof CallableStatement) {
1065: EngineParameterMetaData pmeta = getParameterMetaData();
1066: return Math.min(pmeta.getScale(index),
1067: FdocaConstants.NUMERIC_MAX_PRECISION);
1068: } else
1069: return -1;
1070: }
1071:
1072: /**
1073: * save parameter len sent by client
1074: * @param index parameter index starting with 1
1075: * @param value length of data value
1076: *
1077: */
1078: protected void setParamLen(int index, int value) {
1079: cliParamLens.add(index - 1, new Integer(value));
1080: }
1081:
1082: /**
1083: * get the number of parameters for this statement
1084: *
1085: * @return number of parameters
1086: */
1087: protected int getNumParams() {
1088: if (cliParamDrdaTypes != null)
1089: return cliParamDrdaTypes.size();
1090: else
1091: return 0;
1092: }
1093:
1094: /**
1095: * get the number of result set columns for the current resultSet
1096: *
1097: * @return number of columns
1098: */
1099:
1100: protected int getNumRsCols() {
1101: int[] rsDrdaTypes = getRsDRDATypes();
1102: if (rsDrdaTypes != null)
1103: return rsDrdaTypes.length;
1104: else
1105: return 0;
1106: }
1107:
1108: /**
1109: * get resultset/out parameter DRDAType
1110: *
1111: * @param index - starting with 1
1112: * @return DRDA Type of column
1113: */
1114: protected int getRsDRDAType(int index) {
1115: return currentDrdaRs.getRsDRDAType(index);
1116: }
1117:
1118: /**
1119: * get resultset/out parameter DRDALen
1120: * @param index starting with 1
1121: *
1122: * @return length of drda data
1123: */
1124:
1125: protected int getRsLen(int index) {
1126: return currentDrdaRs.getRsLen(index);
1127: }
1128:
1129: /**
1130: * set resultset column data length
1131: * @param index starting with 1
1132: * @param value length
1133: */
1134: protected void setRsLen(int index, int value) {
1135: currentDrdaRs.setRsLen(index, value);
1136: }
1137:
1138: /**
1139: * @param rsNum - result set # starting with 0
1140: */
1141: public String getResultSetCursorName(int rsNum) throws SQLException {
1142: DRDAResultSet drdaRs = getDrdaResultSet(rsNum);
1143: return drdaRs.getResultSetCursorName();
1144:
1145: }
1146:
1147: protected String toDebugString(String indent) {
1148: ResultSet rs = currentDrdaRs.getResultSet();
1149:
1150: String s = "";
1151: if (ps == null)
1152: s += indent + ps;
1153: else {
1154: s += indent + pkgid + pkgsn;
1155: s += "\t" + getSQLText();
1156: }
1157: return s;
1158: }
1159:
1160: /** For a single result set, just echo the consistency token that the client sent us.
1161: * For subsequent resultSets, just subtract the resultset number from
1162: * the consistency token and that will differentiate the result sets.
1163: * This seems to be what DB2 does
1164: * @param rsNum - result set # starting with 0
1165: *
1166: * @return Consistency token for result set
1167: */
1168:
1169: protected ConsistencyToken calculateResultSetPkgcnstkn(int rsNum) {
1170: ConsistencyToken consistToken = pkgcnstkn;
1171:
1172: if (rsNum == 0 || pkgcnstkn == null)
1173: return consistToken;
1174: else {
1175: BigInteger consistTokenBi = new BigInteger(consistToken
1176: .getBytes());
1177: BigInteger rsNumBi = BigInteger.valueOf(rsNum);
1178: consistTokenBi = consistTokenBi.subtract(rsNumBi);
1179: consistToken = new ConsistencyToken(consistTokenBi
1180: .toByteArray());
1181: }
1182: return consistToken;
1183: }
1184:
1185: protected boolean isCallableStatement() {
1186: return isCall;
1187: }
1188:
1189: private boolean isCallableSQL(String sql) {
1190: java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
1191: sql, "\t\n\r\f=? (");
1192: String firstToken = tokenizer.nextToken();
1193: if (StringUtil.SQLEqualsIgnoreCase(firstToken, "call")) // captures CALL...and ?=CALL...
1194: return true;
1195: return false;
1196:
1197: }
1198:
1199: private void setupCallableStatementParams(CallableStatement cs)
1200: throws SQLException {
1201: EngineParameterMetaData pmeta = getParameterMetaData();
1202: int numElems = pmeta.getParameterCount();
1203:
1204: for (int i = 0; i < numElems; i++) {
1205: boolean outputFlag = false;
1206:
1207: int parameterMode = pmeta.getParameterMode(i + 1);
1208: int parameterType = pmeta.getParameterType(i + 1);
1209:
1210: switch (parameterMode) {
1211: case JDBC30Translation.PARAMETER_MODE_IN:
1212: break;
1213: case JDBC30Translation.PARAMETER_MODE_OUT:
1214: case JDBC30Translation.PARAMETER_MODE_IN_OUT:
1215: outputFlag = true;
1216: break;
1217: case JDBC30Translation.PARAMETER_MODE_UNKNOWN:
1218: // It's only unknown if array
1219: String objectType = pmeta.getParameterClassName(i + 1);
1220: parameterType = getOutputParameterTypeFromClassName(objectType);
1221: if (parameterType != NOT_OUTPUT_PARAM)
1222: outputFlag = true;
1223: }
1224:
1225: if (outputFlag) {
1226: if (outputTypes == null) //not initialized yet, since previously none output
1227: {
1228: outputTypes = new int[numElems];
1229: for (int j = 0; j < numElems; j++)
1230: outputTypes[j] = NOT_OUTPUT_PARAM; //default init value
1231: }
1232: // save the output type so we can register when we parse
1233: // the SQLDTA
1234: outputTypes[i] = parameterType;
1235: }
1236:
1237: }
1238: }
1239:
1240: /**
1241: Given an object class name get the paramameter type if the
1242: parameter mode is unknown.
1243:
1244: Arrays except for byte arrrays are assumed to be output parameters
1245: TINYINT output parameters are going to be broken because there
1246: is no way to differentiate them from binary input parameters.
1247: @param objectName Class name of object being evaluated.
1248: indicating if this an output parameter
1249: @return type from java.sql.Types
1250: **/
1251:
1252: protected static int getOutputParameterTypeFromClassName(
1253: String objectName) {
1254:
1255: if (objectName.endsWith("[]")) {
1256: // For byte[] we are going to assume it is input.
1257: // For TINYINT output params you gotta use
1258: // object Integer[] or use a procedure
1259: if (objectName.equals("byte[]")) {
1260: return NOT_OUTPUT_PARAM;
1261:
1262: //isOutParam[offset] = false;
1263: //return java.sql.Types.VARBINARY;
1264: }
1265:
1266: // Known arrays are output parameters
1267: // otherwise we pass it's a JAVA_OBJECT
1268: if (objectName.equals("java.lang.Byte[]"))
1269: return java.sql.Types.TINYINT;
1270:
1271: if (objectName.equals("byte[][]"))
1272: return java.sql.Types.VARBINARY;
1273: if (objectName.equals("java.lang.String[]"))
1274: return java.sql.Types.VARCHAR;
1275: if (objectName.equals("int[]")
1276: || objectName.equals("java.lang.Integer[]"))
1277: return java.sql.Types.INTEGER;
1278: else if (objectName.equals("long[]")
1279: || objectName.equals("java.lang.Long[]"))
1280: return java.sql.Types.BIGINT;
1281: else if (objectName.equals("java.math.BigDecimal[]"))
1282: return java.sql.Types.NUMERIC;
1283: else if (objectName.equals("boolean[]")
1284: || objectName.equals("java.lang.Boolean[]"))
1285: return java.sql.Types.BIT;
1286: else if (objectName.equals("short[]"))
1287: return java.sql.Types.SMALLINT;
1288: else if (objectName.equals("float[]")
1289: || objectName.equals("java.lang.Float[]"))
1290: return java.sql.Types.REAL;
1291: else if (objectName.equals("double[]")
1292: || objectName.equals("java.lang.Double[]"))
1293: return java.sql.Types.DOUBLE;
1294: else if (objectName.equals("java.sql.Date[]"))
1295: return java.sql.Types.DATE;
1296: else if (objectName.equals("java.sql.Time[]"))
1297: return java.sql.Types.TIME;
1298: else if (objectName.equals("java.sql.Timestamp[]"))
1299: return java.sql.Types.TIMESTAMP;
1300: }
1301: // Not one of the ones we know. This must be a JAVA_OBJECT
1302: return NOT_OUTPUT_PARAM;
1303: //isOutParam[offset] = false;
1304: //return java.sql.Types.JAVA_OBJECT;
1305:
1306: }
1307:
1308: public void registerAllOutParams() throws SQLException {
1309: if (isCall && (outputTypes != null))
1310: for (int i = 1; i <= outputTypes.length; i++)
1311: registerOutParam(i);
1312:
1313: }
1314:
1315: public void registerOutParam(int paramNum) throws SQLException {
1316: CallableStatement cs;
1317: if (isOutputParam(paramNum)) {
1318: cs = (CallableStatement) ps;
1319: cs.registerOutParameter(paramNum,
1320: getOutputParamType(paramNum));
1321: }
1322: }
1323:
1324: protected boolean hasOutputParams() {
1325: return (outputTypes != null);
1326: }
1327:
1328: /**
1329: * is parameter an ouput parameter
1330: * @param paramNum parameter number starting with 1.
1331: * return true if this is an output parameter.
1332: */
1333: boolean isOutputParam(int paramNum) {
1334: if (outputTypes != null)
1335: return (outputTypes[paramNum - 1] != NOT_OUTPUT_PARAM);
1336: return false;
1337:
1338: }
1339:
1340: /**
1341: * get type for output parameter.
1342: *
1343: * @param paramNum - parameter number starting with 1
1344: * @return jdbcType or NOT_OUTPUT_PARAM if this is not an output parameter
1345: */
1346: int getOutputParamType(int paramNum) {
1347: if (outputTypes != null)
1348: return (outputTypes[paramNum - 1]);
1349: return NOT_OUTPUT_PARAM;
1350: }
1351:
1352: private boolean isDynamicPkgid(String pkgid) {
1353: char size = pkgid.charAt(3);
1354:
1355: // separate attribute used for holdability in 5.1.60
1356: // this is just for checking that it is a dynamic package
1357: char holdability = pkgid.charAt(4);
1358: return (pkgid.substring(0, 3).equals("SYS")
1359: && (size == 'S' || size == 'L') && (holdability == 'H' || holdability == 'N'));
1360:
1361: }
1362:
1363: private void parsePkgidToFindHoldability() {
1364: if (withHoldCursor != -1)
1365: return;
1366:
1367: //First, check if holdability was passed as a SQL attribute "WITH HOLD" for this prepare. If yes, then withHoldCursor
1368: //should not get overwritten by holdability from package name and that is why the check for -1
1369: if (isDynamicPkgid(pkgid)) {
1370: if (pkgid.charAt(4) == 'N')
1371: withHoldCursor = JDBC30Translation.CLOSE_CURSORS_AT_COMMIT;
1372: else
1373: withHoldCursor = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
1374: } else {
1375: withHoldCursor = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
1376:
1377: }
1378: }
1379:
1380: /**
1381: * prepare a statement using EngineConnection.prepareStatement
1382: * so that server can run on jdk131 and still pass holdability.
1383: * @param sqlStmt - SQL statement text
1384: * @param scrollType - scroll type
1385: * @param concurType - concurrency type
1386: * @param withHoldCursor - holdability
1387: *
1388: * @throws SQLException
1389: * @return Prepared Statement
1390: * @see java.sql.Connection#prepareStatement
1391: */
1392: private PreparedStatement prepareStatementJDBC3(String sqlStmt,
1393: int scrollType, int concurType, int withHoldCursor)
1394: throws SQLException {
1395: EngineConnection conn = database.getConnection();
1396: if (withHoldCursor == -1) {
1397: // Holdability not explictly set, let the
1398: // connection provide the default.
1399: return conn.prepareStatement(sqlStmt, scrollType,
1400: concurType);
1401: }
1402:
1403: // Holdability explictly set.
1404: return conn.prepareStatement(sqlStmt, scrollType, concurType,
1405: withHoldCursor);
1406: }
1407:
1408: /**
1409: * Retrieve the ParameterMetaData for the prepared statement.
1410: * To do so, use the engine defined interfaces:
1411: * @see org.apache.derby.iapi.jdbc.EnginePreparedStatement
1412: * @see org.apache.derby.iapi.jdbc.EngineParameterMetaData
1413: * @return EngineParameterMetaData for the prepared statement.
1414: * Note: there is no separate BrokeredParameterSetMetaData.
1415: */
1416: protected EngineParameterMetaData getParameterMetaData()
1417: throws SQLException {
1418: if (stmtPmeta != null)
1419: return stmtPmeta;
1420:
1421: stmtPmeta = ((EnginePreparedStatement) ps)
1422: .getEmbedParameterSetMetaData();
1423:
1424: return stmtPmeta;
1425: }
1426:
1427: /**
1428: * get more results using reflection.
1429: * @param current - flag to pass to Statement.getMoreResults(current)
1430: * @return true if there are more results.
1431: * @throws SQLException
1432: * @see java.sql.Statement#getMoreResults
1433: *
1434: */
1435: private boolean getMoreResults(int current) throws SQLException {
1436: return ((EngineStatement) getPreparedStatement())
1437: .getMoreResults(current);
1438: }
1439:
1440: /**
1441: * Use reflection to retrieve SQL Text for EmbedPreparedStatement
1442: * or BrokeredPreparedStatement.
1443: * @return SQL text
1444: */
1445: private String getSQLText() {
1446: String retVal = null;
1447: Class[] emptyPARAM = {};
1448: Object[] args = null;
1449: try {
1450: Method sh = getPreparedStatement().getClass().getMethod(
1451: "getSQLText", emptyPARAM);
1452: retVal = (String) sh.invoke(getPreparedStatement(), args);
1453: } catch (Exception e) {
1454: // do nothing we will just return a null string
1455: }
1456: return retVal;
1457:
1458: }
1459:
1460: /** helper method to handle exceptions generated by methods invoked
1461: * through reflection.
1462: * @param e - exception thrown
1463: * @throws SQLException - actual exception that occurred
1464: */
1465: private void handleReflectionException(Exception e)
1466: throws SQLException {
1467: if (e instanceof InvocationTargetException) {
1468: Throwable t = ((InvocationTargetException) e)
1469: .getTargetException();
1470:
1471: if (t instanceof SQLException) {
1472: throw (SQLException) t;
1473: } else {
1474: t.printStackTrace();
1475: throw Util.javaException(t);
1476: }
1477: } else
1478: // invoke can throw IllegalAccessException or
1479: // IllegalArgumentException, but these should not
1480: // occur from this code. Just in case we will throw it
1481: throw Util.javaException(e);
1482:
1483: }
1484:
1485: /**
1486: * Method to decide whether the ResultSet should be closed
1487: * implicitly based on the QRYCLSIMP value sent from the
1488: * client. Only forward-only result sets should be implicitly
1489: * closed. Some clients do not expect result sets to be closed
1490: * implicitly if the protocol is LMTBLKPRC.
1491: *
1492: * @param lmtblkprcOK <code>true</code> if the client expects
1493: * QRYCLSIMP to be respected for the LMTBLKPRC protocol
1494: * @return implicit close boolean
1495: * @exception SQLException
1496: */
1497: boolean isRSCloseImplicit(boolean lmtblkprcOK) throws SQLException {
1498: return (currentDrdaRs.qryclsimp == CodePoint.QRYCLSIMP_YES)
1499: && !isScrollable()
1500: && (lmtblkprcOK || (currentDrdaRs.getQryprctyp() != CodePoint.LMTBLKPRC));
1501: }
1502: }
|