0001: /*
0002:
0003: Derby - Class org.apache.derby.client.net.NetStatementRequest
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: package org.apache.derby.client.net;
0022:
0023: import org.apache.derby.iapi.reference.DRDAConstants;
0024: import org.apache.derby.client.am.Blob;
0025: import org.apache.derby.client.am.Clob;
0026: import org.apache.derby.client.am.ColumnMetaData;
0027: import org.apache.derby.client.am.ResultSet;
0028: import org.apache.derby.client.am.Section;
0029: import org.apache.derby.client.am.SqlException;
0030: import org.apache.derby.client.am.Types;
0031: import org.apache.derby.client.am.ClientMessageId;
0032: import org.apache.derby.shared.common.reference.SQLState;
0033:
0034: // For performance, should we worry about the ordering of our DDM command parameters
0035:
0036: public class NetStatementRequest extends NetPackageRequest implements
0037: StatementRequestInterface {
0038: java.util.ArrayList extdtaPositions_ = null; // Integers: build EXTDTA for column i
0039: int overrideLid_ = FdocaConstants.FIRST_OVERRIDE_LID;
0040:
0041: // promototed parameters hold parameters that are promotoed to a different
0042: // data type because they are too large to represent in PROTOCOL otherwise.
0043: // This currently only applies for promotion of (VAR)CHAR -> CLOB and (VAR)BINARY -> BLOB
0044: // The key for this structure is the parameter index. Note that having this
0045: // collection does not eliminate the need for extdtaPositions_ because that
0046: // is still needed for non-promototed LOBs
0047: java.util.HashMap promototedParameters_ = new java.util.HashMap();
0048:
0049: NetStatementRequest(NetAgent netAgent, CcsidManager ccsidManager,
0050: int bufferSize) {
0051: super (netAgent, ccsidManager, bufferSize);
0052: }
0053:
0054: //----------------------------- entry points ---------------------------------
0055:
0056: // Write the message to perform an execute immediate.
0057: // The SQL statement sent as command data cannot contain references
0058: // to either input variables or output variables.
0059: //
0060: // preconditions:
0061: public void writeExecuteImmediate(NetStatement materialStatement,
0062: String sql, Section section) throws SqlException {
0063: buildEXCSQLIMM(section, false, //sendQryinsid
0064: 0); //qryinsid
0065: buildSQLSTTcommandData(sql); // statement follows in sqlstt command data object
0066: }
0067:
0068: // Write the message to preform a prepare into.
0069: // Once the SQL statement has been prepared, it is executed until the unit of work, in
0070: // which the PRPSQLSTT command was issued, ends. An exception to this is if
0071: // Keep Dynamic is being used.
0072: //
0073: // preconditions:
0074: public void writePrepareDescribeOutput(
0075: NetStatement materialStatement, String sql, Section section)
0076: throws SqlException {
0077: buildPRPSQLSTT(section, sql, true, //sendRtnsqlda
0078: true, //sendTypsqlda
0079: CodePoint.TYPSQLDA_X_OUTPUT); //typsqlda
0080:
0081: if (((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_ != null) {
0082: buildSQLATTRcommandData(((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_);
0083: }
0084:
0085: buildSQLSTTcommandData(sql); // statement follows in sqlstt command data object
0086: }
0087:
0088: // Write the message to perform a reprepare.
0089: //
0090: // preconditions:
0091: public void writePrepare(NetStatement materialStatement,
0092: String sql, Section section) throws SqlException {
0093: buildPRPSQLSTT(section, sql, false, //sendRtnsqlda
0094: false, //sendTypsqlda
0095: 0); //typsqlda
0096:
0097: if (((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_ != null) {
0098: buildSQLATTRcommandData(((NetStatement) materialStatement).statement_.cursorAttributesToSendOnPrepare_);
0099: }
0100:
0101: buildSQLSTTcommandData(sql); // statement follows in sqlstt command data object
0102: }
0103:
0104: // Write the message to execute prepared sql statement.
0105: //
0106: // preconditions:
0107: public void writeExecute(
0108: NetPreparedStatement materialPreparedStatement,
0109: Section section, ColumnMetaData parameterMetaData,
0110: Object[] inputs, int numInputColumns,
0111: boolean outputExpected, boolean chained)
0112: throws SqlException // chained flag for blobs only //dupqry
0113: {
0114: buildEXCSQLSTT(section, true, // sendOutexp
0115: outputExpected, // outexp
0116: false, // sendPrcnam
0117: null, // prcnam
0118: false, // sendQryblksz
0119: false, // sendMaxrslcnt,
0120: 0, // maxrslcnt,
0121: false, // sendMaxblkext
0122: 0, // maxblkext
0123: false, // sendRslsetflg
0124: 0, // resultSetFlag
0125: false, // sendQryrowset
0126: 0); // qryrowset
0127:
0128: if (numInputColumns > 0) {
0129: if ((extdtaPositions_ != null)
0130: && (!extdtaPositions_.isEmpty())) {
0131: extdtaPositions_.clear(); // reset extdta column position markers
0132: }
0133:
0134: boolean overrideExists = buildSQLDTAcommandData(
0135: numInputColumns, parameterMetaData, inputs);
0136:
0137: // can we eleminate the chain argument needed for lobs
0138: buildEXTDTA(parameterMetaData, inputs, chained);
0139: }
0140: }
0141:
0142: // Write the message to open a bound or prepared query with input parameters.
0143: // Check this -> For open query with input parameters
0144: //
0145: // preconditions:
0146: public void writeOpenQuery(
0147: NetPreparedStatement materialPreparedStatement,
0148: Section section,
0149: int fetchSize,
0150: int resultSetType,
0151: int numInputColumns,
0152: org.apache.derby.client.am.ColumnMetaData parameterMetaData,
0153: Object[] inputs) throws SqlException {
0154: boolean sendQryrowset = checkSendQryrowset(fetchSize,
0155: resultSetType);
0156: fetchSize = checkFetchsize(fetchSize, resultSetType);
0157: // think about if there is a way we can call build ddm just passing ddm parameters and not passing the material ps object
0158: // maybe not, if sometimes we need to set the caches hanging off the ps object during the ddm build
0159: // maybe we can extricate conditionals in the build ddm logic outside
0160:
0161: buildOPNQRY(section, sendQryrowset, fetchSize);
0162:
0163: // may be able to merge this with firstContinueQuery_ and push above conditional to common
0164: ((NetStatement) materialPreparedStatement).qryrowsetSentOnOpnqry_ = sendQryrowset;
0165:
0166: if (numInputColumns > 0) {
0167: if ((extdtaPositions_ != null)
0168: && (!extdtaPositions_.isEmpty())) {
0169: extdtaPositions_.clear(); // reset extdta column position markers
0170: }
0171: // is this the best place for this
0172: // EXCSQSTT needs this too
0173:
0174: // think about having this method return a boolean to
0175: // indicate the extdta should be built
0176: boolean overrideExists = buildSQLDTAcommandData(
0177: numInputColumns, parameterMetaData, inputs);
0178:
0179: // can we eleminate the chain argument needed for lobs
0180: // do we chain after Extdta's on open, verify this
0181: buildEXTDTA(parameterMetaData, inputs, false); //chained, do we chain after Extdta's on open
0182: }
0183: }
0184:
0185: // Write the message to open a bound or prepared query without input parameters.
0186: // Check this-> For open query without input parameters
0187: public void writeOpenQuery(NetStatement materialStatement,
0188: Section section, int fetchSize, int resultSetType)
0189: throws SqlException {
0190: boolean sendQryrowset = checkSendQryrowset(fetchSize,
0191: resultSetType);
0192: fetchSize = checkFetchsize(fetchSize, resultSetType);
0193:
0194: // think about if there is a way we can call build ddm just passing ddm parameters and not passing the material ps object
0195: // maybe not, if sometimes we need to set the caches hanging off the ps object during the ddm build
0196: // maybe we can extricate conditionals in the build ddm logic outside
0197: buildOPNQRY(section, sendQryrowset, fetchSize);
0198:
0199: // may be able to merge this with firstContinueQuery_ and push above conditional to common
0200: ((NetStatement) materialStatement).qryrowsetSentOnOpnqry_ = sendQryrowset; // net-specific event
0201:
0202: }
0203:
0204: // Write the message to peform a describe input.
0205: //
0206:
0207: public void writeDescribeInput(
0208: NetPreparedStatement materialPreparedStatement,
0209: Section section) throws SqlException {
0210: int typsqlda = CodePoint.TYPSQLDA_X_INPUT;
0211:
0212: buildDSCSQLSTT(section, true, //sendTypsqlda
0213: typsqlda);
0214: }
0215:
0216: // Write the message to peform a describe output.
0217: //
0218: // preconditions:
0219: public void writeDescribeOutput(
0220: NetPreparedStatement materialPreparedStatement,
0221: Section section) throws SqlException {
0222: // pick standard, light, extended sqlda. possibly push this up even more
0223: // right now use SQLAM level as determining factor and go for the most data.
0224: // if standard is the only suported option, don't send the typsqlda
0225: // and let server default to standard. This prevents accidentally sending
0226: // a typsqlda to a downlevel server. typsqlda is only supported at sqlam 6.
0227: //KATHEY CHECK
0228: buildDSCSQLSTT(section, true, //sendTypsqlda
0229: CodePoint.TYPSQLDA_X_OUTPUT); //typsqlda
0230: }
0231:
0232: // Write the message to execute a stored procedure.
0233: //
0234: // preconditions:
0235: public void writeExecuteCall(NetStatement materialStatement,
0236: boolean outputExpected, String procedureName,
0237: Section section, int fetchSize,
0238: boolean suppressResultSets, // for batch updates == true
0239: int resultSetType, ColumnMetaData parameterMetaData,
0240: Object[] inputs) throws SqlException // chain is for blobs
0241: {
0242: // always send QRYROWSET on EXCSQLSTT
0243: boolean sendQryrowset = true;
0244: fetchSize = (fetchSize == 0) ? org.apache.derby.client.am.Configuration.defaultFetchSize
0245: : fetchSize;
0246:
0247: boolean sendPrcnam = (procedureName != null) ? true : false;
0248: int numParameters = (parameterMetaData != null) ? parameterMetaData.columns_
0249: : 0;
0250: outputExpected = numParameters > 0;
0251:
0252: // is it right here to send maxblkext (-1)
0253: buildEXCSQLSTT(section, true, // sendOutexp
0254: outputExpected, // outexp
0255: sendPrcnam, // sendPrcnam
0256: procedureName, // prcnam
0257: true, // sendQryblksz
0258: !suppressResultSets, // sendMaxrslcnt,
0259: CodePoint.MAXRSLCNT_NOLIMIT, // maxrslcnt,
0260: true, // sendMaxblkext
0261: -1, // maxblkext (-1 for AR capable of receiving entire result set)
0262: true, // sendRslsetflg
0263: calculateResultSetFlags(), // resultSetFlag
0264: sendQryrowset, // sendQryrowset
0265: fetchSize); // qryrowset
0266:
0267: if (numParameters > 0) {
0268: if ((extdtaPositions_ != null)
0269: && (!extdtaPositions_.isEmpty())) {
0270: extdtaPositions_.clear(); // reset extdta column position markers
0271: }
0272: // is this the best place for this (OPNQRY needs this too)
0273:
0274: // think about having this method return a boolean to
0275: // indicate the extdta should be built
0276: boolean overrideExists = buildSQLDTAcommandData(
0277: numParameters, parameterMetaData, inputs);
0278:
0279: buildEXTDTA(parameterMetaData, inputs, false); // no chained autocommit for CALLs
0280: }
0281:
0282: ((NetStatement) materialStatement).qryrowsetSentOnOpnqry_ = sendQryrowset;
0283: }
0284:
0285: // Write the message to execute an SQL Set Statement.
0286: /*
0287: public void writeSetGenericSQLSetInfo (org.apache.derby.client.am.SetGenericSQLSetPiggybackCommand setGenericSQLSetPiggybackCommand,
0288: org.apache.derby.client.am.JDBCSection section) throws SqlException
0289: {
0290: buildEXCSQLSET (section);
0291:
0292: java.util.List sqlsttList = setGenericSQLSetPiggybackCommand.getList();
0293: for (int i = 0; i < sqlsttList.size(); i++) {
0294: String sql = (String)sqlsttList.get(i);
0295: // Build SQLSTT only for the SET statement that coming from the server after RLSCONV
0296: buildSQLSTTcommandData (sql);
0297: }
0298: }
0299:
0300: */
0301: //----------------------helper methods----------------------------------------
0302: // These methods are "private protected", which is not a recognized java privilege,
0303: // but means that these methods are private to this class and to subclasses,
0304: // and should not be used as package-wide friendly methods.
0305: // Build the Open Query Command to open a query to a relational database.
0306: // At SQLAM >= 7 we can request the return of a DA, are there
0307: // scenarios where this should currently be done (it is not supported now)
0308: //
0309: // preconditions:
0310: // the sqlam and/or prdid must support command and parameters passed to this method,
0311: // method will not validate against the connection's level of support
0312: //
0313: void buildOPNQRY(Section section, boolean sendQueryRowSet,
0314: int fetchSize) throws SqlException {
0315: createCommand();
0316: markLengthBytes(CodePoint.OPNQRY);
0317:
0318: buildPKGNAMCSN(section);
0319: buildQRYBLKSZ(); // specify a hard coded query block size
0320:
0321: if (sendQueryRowSet) {
0322: buildMAXBLKEXT(-1);
0323: buildQRYROWSET(fetchSize);
0324: }
0325:
0326: // Tell the server to close forward-only result sets
0327: // implicitly when they are exhausted. The server will ignore
0328: // this parameter if the result set is scrollable.
0329: if (netAgent_.netConnection_.serverSupportsQryclsimp()) {
0330: buildQRYCLSIMP();
0331: }
0332:
0333: updateLengthBytes(); // opnqry is complete
0334: }
0335:
0336: // Build the Execute Immediate SQL Statement Command to
0337: // execute a non-cursor SQL statement sent as command data.
0338: //
0339: // precondtions:
0340: void buildEXCSQLIMM(Section section, boolean sendQryinsid,
0341: long qryinsid) throws SqlException {
0342: createCommand();
0343: markLengthBytes(CodePoint.EXCSQLIMM);
0344:
0345: buildPKGNAMCSN(section);
0346: buildRDBCMTOK();
0347: if (sendQryinsid) {
0348: buildQRYINSID(qryinsid);
0349: }
0350:
0351: updateLengthBytes();
0352: }
0353:
0354: // Build the Prepare SQL Statement Command to dynamically binds an
0355: // SQL statement to a section in an existing relational database (RDB) package.
0356: //
0357: // preconditions:
0358: // the sqlam and/or prdid must support command and parameters passed to this method,
0359: // method will not validate against the connection's level of support
0360: void buildPRPSQLSTT(Section section, String sql,
0361: boolean sendRtnsqlda, boolean sendTypsqlda, int typsqlda)
0362: throws SqlException {
0363: createCommand();
0364: markLengthBytes(CodePoint.PRPSQLSTT);
0365:
0366: buildPKGNAMCSN(section);
0367: if (sendRtnsqlda) {
0368: buildRTNSQLDA();
0369: }
0370: if (sendTypsqlda) {
0371: buildTYPSQLDA(typsqlda);
0372: }
0373:
0374: updateLengthBytes();
0375: }
0376:
0377: // Build the command to execute an SQL SET Statement.
0378: // Called by NETSetClientPiggybackCommand.write()
0379: //
0380: // preconditions:
0381: // the sqlam and/or prdid must support command and parameters passed to this method,
0382: // method will not validate against the connection's level of support
0383: void buildEXCSQLSET(Section section) throws SqlException {
0384: createCommand();
0385: markLengthBytes(CodePoint.EXCSQLSET);
0386: buildPKGNAMCSN(section); // is this PKGNAMCSN or PKGNAMCT
0387: updateLengthBytes();
0388: }
0389:
0390: // Build the Execute SQL Statement (EXCSQLSTT) Command
0391: // to execute a non-cursor SQL statement previously bound into a named package
0392: // of a relational database (RDB). The SQL statement can optionally include
0393: // references to input variables, output variables, or both.
0394: //
0395: // At SQLAM >= 7 we can get a DA back on this, are there times that we want to request it
0396: // If so, we probably want to pass a parameter indicating the sqldaLevel requested.
0397: //
0398: // preconditions:
0399: // the sqlam and/or prdid must support command and parameters passed to this method,
0400: // method will not validate against the connection's level of support
0401: // Here is the preferred codepoint ordering:
0402: // PKGNAMCSN
0403: // RDBCMTOK
0404: // OUTEXP
0405: // QRYBLKSZ
0406: // MAXBLKEXT
0407: // MAXRSLCNT
0408: // RSLSETFLG
0409: // QRYROWSET
0410: // RTNSQLDA
0411: // TYPSQLDA
0412: // NBRROW
0413: // ATMIND
0414: // PRCNAM
0415: // OUTOVROPT
0416: // RDBNAM
0417: void buildEXCSQLSTT(Section section, boolean sendOutexp,
0418: boolean outexp, boolean sendPrcnam, String prcnam,
0419: boolean sendQryblksz, boolean sendMaxrslcnt, int maxrslcnt,
0420: boolean sendMaxblkext, int maxblkext,
0421: boolean sendRslsetflg, int resultSetFlag,
0422: boolean sendQryrowset, int qryrowset) throws SqlException {
0423: createCommand();
0424: markLengthBytes(CodePoint.EXCSQLSTT);
0425:
0426: buildPKGNAMCSN(section);
0427: buildRDBCMTOK();
0428: if (sendOutexp) {
0429: buildOUTEXP(outexp);
0430: }
0431: if (sendQryblksz) {
0432: buildQRYBLKSZ();
0433: }
0434: if (sendQryrowset && sendMaxblkext) {
0435: buildMAXBLKEXT(maxblkext);
0436: }
0437: if (sendMaxrslcnt) {
0438: buildMAXRSLCNT(maxrslcnt);
0439: }
0440: if (sendRslsetflg) {
0441: buildRSLSETFLG(resultSetFlag);
0442: }
0443: if (sendQryrowset) {
0444: buildQRYROWSET(qryrowset);
0445: }
0446: if (sendPrcnam) {
0447: buildPRCNAM(prcnam);
0448: }
0449:
0450: updateLengthBytes(); // command is complete, update the length bytes
0451: }
0452:
0453: // Build the Describe SQL Statement command.
0454: //
0455: // preconditions:
0456: // the sqlam and/or prdid must support command and parameters passed to this method,
0457: // method will not validate against the connection's level of support
0458: void buildDSCSQLSTT(Section section, boolean sendTypsqlda,
0459: int typsqlda) throws SqlException {
0460: createCommand();
0461: markLengthBytes(CodePoint.DSCSQLSTT);
0462:
0463: buildPKGNAMCSN(section);
0464: if (sendTypsqlda) {
0465: buildTYPSQLDA(typsqlda);
0466: }
0467:
0468: updateLengthBytes();
0469: }
0470:
0471: // Build the SQL Program Variable Data Command Data Object.
0472: // This object contains the input data to an SQL statement
0473: // that an RDB is executing.
0474: //
0475: // preconditions:
0476: boolean buildSQLDTAcommandData(int numInputColumns,
0477: ColumnMetaData parameterMetaData, Object[] inputRow)
0478: throws SqlException {
0479: createEncryptedCommandData();
0480:
0481: int loc = offset_;
0482:
0483: markLengthBytes(CodePoint.SQLDTA);
0484:
0485: int[][] protocolTypesAndLengths = allocateLidAndLengthsArray(parameterMetaData);
0486:
0487: java.util.Hashtable protocolTypeToOverrideLidMapping = null;
0488: java.util.ArrayList mddOverrideArray = null;
0489: protocolTypeToOverrideLidMapping = computeProtocolTypesAndLengths(
0490: inputRow, parameterMetaData, protocolTypesAndLengths,
0491: protocolTypeToOverrideLidMapping);
0492:
0493: boolean overrideExists = false;
0494:
0495: buildFDODSC(numInputColumns, protocolTypesAndLengths,
0496: overrideExists, protocolTypeToOverrideLidMapping,
0497: mddOverrideArray);
0498:
0499: buildFDODTA(numInputColumns, protocolTypesAndLengths, inputRow);
0500:
0501: updateLengthBytes(); // for sqldta
0502: if (netAgent_.netConnection_.getSecurityMechanism() == NetConfiguration.SECMEC_EUSRIDDTA
0503: || netAgent_.netConnection_.getSecurityMechanism() == NetConfiguration.SECMEC_EUSRPWDDTA) {
0504: encryptDataStream(loc);
0505: }
0506:
0507: return overrideExists;
0508: }
0509:
0510: // Build the FDOCA Data Descriptor Scalar whose value is a FDOCA
0511: // Descriptor or a segment of an FDOCA Descriptor.
0512: //
0513: // preconditions:
0514: private void buildFDODSC(int numColumns,
0515: int[][] protocolTypesAndLengths, boolean overrideExists,
0516: java.util.Hashtable overrideMap,
0517: java.util.ArrayList overrideArray) throws SqlException {
0518: markLengthBytes(CodePoint.FDODSC);
0519: buildSQLDTA(numColumns, protocolTypesAndLengths,
0520: overrideExists, overrideMap, overrideArray);
0521: updateLengthBytes();
0522: }
0523:
0524: // Build the FDOCA SQLDTA Late Row Descriptor.
0525: //
0526: // preconditions:
0527: protected void buildSQLDTA(int numColumns,
0528: int[][] lidAndLengthOverrides, boolean overrideExists,
0529: java.util.Hashtable overrideMap,
0530: java.util.ArrayList overrideArray) throws SqlException {
0531: // mdd overrides need to be built first if any before the descriptors are built.
0532: if (overrideExists) {
0533: buildMddOverrides(overrideArray);
0534: writeBytes(FdocaConstants.MDD_SQLDTAGRP_TOSEND);
0535: }
0536:
0537: buildSQLDTAGRP(numColumns, lidAndLengthOverrides,
0538: overrideExists, overrideMap);
0539:
0540: if (overrideExists) {
0541: writeBytes(FdocaConstants.MDD_SQLDTA_TOSEND);
0542: }
0543: writeBytes(FdocaConstants.SQLDTA_RLO_TOSEND);
0544: }
0545:
0546: // Build the FDOCA SQLDTAGRP Late Group Descriptor.
0547: // preconditions:
0548: protected void buildSQLDTAGRP(int numVars,
0549: int[][] lidAndLengthOverrides, boolean mddRequired,
0550: java.util.Hashtable overrideMap) throws SqlException {
0551: int n = 0;
0552: int offset = 0;
0553:
0554: n = calculateColumnsInSQLDTAGRPtriplet(numVars);
0555: buildTripletHeader(((3 * n) + 3),
0556: FdocaConstants.NGDA_TRIPLET_TYPE,
0557: FdocaConstants.SQLDTAGRP_LID);
0558:
0559: do {
0560: writeLidAndLengths(lidAndLengthOverrides, n, offset,
0561: mddRequired, overrideMap);
0562: numVars -= n;
0563: if (numVars == 0) {
0564: break;
0565: }
0566:
0567: offset += n;
0568: n = calculateColumnsInSQLDTAGRPtriplet(numVars);
0569: buildTripletHeader(((3 * n) + 3),
0570: FdocaConstants.CPT_TRIPLET_TYPE, 0x00);
0571: } while (true);
0572: }
0573:
0574: /////////// perf end
0575:
0576: protected void buildOUTOVR(ResultSet resultSet,
0577: ColumnMetaData resultSetMetaData) throws SqlException {
0578: createCommandData();
0579: markLengthBytes(CodePoint.OUTOVR);
0580: int[][] outputOverrides = calculateOUTOVRLidAndLengthOverrides(
0581: resultSet, resultSetMetaData);
0582: buildSQLDTARD(resultSetMetaData.columns_, outputOverrides);
0583: updateLengthBytes();
0584: }
0585:
0586: private int[][] calculateOUTOVRLidAndLengthOverrides(
0587: ResultSet resultSet, ColumnMetaData resultSetMetaData) {
0588: int numVars = resultSetMetaData.columns_;
0589: int[][] lidAndLengths = new int[numVars][2]; //everything initialized to "default triplet"
0590:
0591: return lidAndLengths;
0592: }
0593:
0594: protected void buildSQLDTARD(int numColumns,
0595: int[][] lidAndLengthOverrides) throws SqlException {
0596: buildSQLCADTA(numColumns, lidAndLengthOverrides);
0597: writeBytes(FdocaConstants.SQLDTARD_RLO_TOSEND);
0598: }
0599:
0600: protected void buildSQLCADTA(int numColumns,
0601: int[][] lidAndLengthOverrides) throws SqlException {
0602: buildSQLDTAGRP(numColumns, lidAndLengthOverrides, false, null); // false means no mdd override
0603: writeBytes(FdocaConstants.SQLCADTA_RLO_TOSEND);
0604: }
0605:
0606: private void buildFDODTA(int numVars,
0607: int[][] protocolTypesAndLengths, Object[] inputs)
0608: throws SqlException {
0609: try {
0610: long dataLength = 0;
0611: Object o = null;
0612:
0613: markLengthBytes(CodePoint.FDODTA);
0614: write1Byte(FdocaConstants.NULL_LID); // write the 1-byte row indicator
0615:
0616: // write data for each input column
0617: for (int i = 0; i < numVars; i++) {
0618: if (inputs[i] == null) {
0619: if ((protocolTypesAndLengths[i][0] % 2) == 1) {
0620: write1Byte(FdocaConstants.NULL_DATA);
0621: } else {
0622: //bug check
0623: }
0624: } else {
0625: if ((protocolTypesAndLengths[i][0] % 2) == 1) {
0626: write1Byte(FdocaConstants.INDICATOR_NULLABLE);
0627: }
0628:
0629: switch (protocolTypesAndLengths[i][0] | 0x01) { // mask out null indicator
0630: case DRDAConstants.DRDA_TYPE_NVARMIX:
0631: case DRDAConstants.DRDA_TYPE_NLONGMIX:
0632: // What to do for server that don't understand 1208 (UTF-8)
0633: // check for a promototed type, and use that instead if it exists
0634: o = retrievePromotedParameterIfExists(i);
0635: if (o == null) {
0636: writeSingleorMixedCcsidLDString(
0637: (String) inputs[i],
0638: netAgent_.typdef_
0639: .getCcsidMbcEncoding());
0640: } else { // use the promototed object instead
0641: Clob c = (Clob) o;
0642: dataLength = c.length();
0643: setFDODTALobLength(protocolTypesAndLengths,
0644: i, dataLength);
0645: }
0646: break;
0647:
0648: case DRDAConstants.DRDA_TYPE_NVARCHAR:
0649: case DRDAConstants.DRDA_TYPE_NLONG:
0650: o = retrievePromotedParameterIfExists(i);
0651: if (o == null) {
0652:
0653: } else { // use the promototed object instead
0654: dataLength = ((Clob) o).length();
0655: setFDODTALobLength(protocolTypesAndLengths,
0656: i, dataLength);
0657: }
0658: break;
0659:
0660: case DRDAConstants.DRDA_TYPE_NINTEGER:
0661: writeIntFdocaData(((Integer) inputs[i])
0662: .intValue());
0663: break;
0664: case DRDAConstants.DRDA_TYPE_NSMALL:
0665: writeShortFdocaData(((Short) inputs[i])
0666: .shortValue());
0667: break;
0668: case DRDAConstants.DRDA_TYPE_NFLOAT4:
0669: writeFloat(((Float) inputs[i]).floatValue());
0670: break;
0671: case DRDAConstants.DRDA_TYPE_NFLOAT8:
0672: writeDouble(((Double) inputs[i]).doubleValue());
0673: break;
0674: case DRDAConstants.DRDA_TYPE_NDECIMAL:
0675: writeBigDecimal(
0676: (java.math.BigDecimal) inputs[i],
0677: (protocolTypesAndLengths[i][1] >> 8) & 0xff, // described precision not actual
0678: protocolTypesAndLengths[i][1] & 0xff); // described scale, not actual
0679: break;
0680: case DRDAConstants.DRDA_TYPE_NDATE:
0681: writeDate((java.sql.Date) inputs[i]);
0682: break;
0683: case DRDAConstants.DRDA_TYPE_NTIME:
0684: writeTime((java.sql.Time) inputs[i]);
0685: break;
0686: case DRDAConstants.DRDA_TYPE_NTIMESTAMP:
0687: writeTimestamp((java.sql.Timestamp) inputs[i]);
0688: break;
0689: case DRDAConstants.DRDA_TYPE_NINTEGER8:
0690: writeLongFdocaData(((Long) inputs[i])
0691: .longValue());
0692: break;
0693: case DRDAConstants.DRDA_TYPE_NVARBYTE:
0694: case DRDAConstants.DRDA_TYPE_NLONGVARBYTE:
0695: o = retrievePromotedParameterIfExists(i);
0696: if (o == null) {
0697: writeLDBytes((byte[]) inputs[i]);
0698: } else { // use the promototed object instead
0699: Blob b = (Blob) o;
0700: dataLength = b.length();
0701: setFDODTALobLength(protocolTypesAndLengths,
0702: i, dataLength);
0703: }
0704: break;
0705: case DRDAConstants.DRDA_TYPE_NLOBCSBCS:
0706: case DRDAConstants.DRDA_TYPE_NLOBCDBCS:
0707: // check for a promoted Clob
0708: o = retrievePromotedParameterIfExists(i);
0709: if (o == null) {
0710: try {
0711: dataLength = ((java.sql.Clob) inputs[i])
0712: .length();
0713: } catch (java.sql.SQLException e) {
0714: throw new SqlException(
0715: netAgent_.logWriter_,
0716: new ClientMessageId(
0717: SQLState.NET_ERROR_GETTING_BLOB_LENGTH),
0718: e);
0719: }
0720: } else {
0721: dataLength = ((Clob) o).length();
0722: }
0723: setFDODTALobLength(protocolTypesAndLengths, i,
0724: dataLength);
0725: break;
0726: case DRDAConstants.DRDA_TYPE_NLOBBYTES:
0727: // check for a promoted Clob
0728: o = retrievePromotedParameterIfExists(i);
0729: if (o == null) {
0730: try {
0731: dataLength = ((java.sql.Blob) inputs[i])
0732: .length();
0733: } catch (java.sql.SQLException e) {
0734: throw new SqlException(
0735: netAgent_.logWriter_,
0736: new ClientMessageId(
0737: SQLState.NET_ERROR_GETTING_BLOB_LENGTH),
0738: e);
0739: }
0740: } else { // use promoted Blob
0741: dataLength = ((Blob) o).length();
0742: }
0743: setFDODTALobLength(protocolTypesAndLengths, i,
0744: dataLength);
0745: break;
0746: case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
0747: // check for a promoted Clob
0748: o = retrievePromotedParameterIfExists(i);
0749: if (o == null) {
0750: if (((Clob) inputs[i]).isString()) {
0751: dataLength = ((Clob) inputs[i])
0752: .getUTF8Length();
0753: } else // must be a Unicode stream
0754: {
0755: dataLength = ((Clob) inputs[i])
0756: .length();
0757: }
0758: } else { // use promoted Clob
0759: dataLength = ((Clob) o).length();
0760: }
0761: setFDODTALobLength(protocolTypesAndLengths, i,
0762: dataLength);
0763: break;
0764: default:
0765: throw new SqlException(
0766: netAgent_.logWriter_,
0767: new ClientMessageId(
0768: SQLState.NET_UNRECOGNIZED_JDBC_TYPE),
0769: new Integer(
0770: protocolTypesAndLengths[i][0]),
0771: new Integer(numVars), new Integer(i));
0772: }
0773: }
0774: }
0775: updateLengthBytes(); // for fdodta
0776: } catch (java.sql.SQLException se) {
0777: throw new SqlException(se);
0778: }
0779: }
0780:
0781: // preconditions:
0782: private void buildEXTDTA(ColumnMetaData parameterMetaData,
0783: Object[] inputRow, boolean chained) throws SqlException {
0784: try {
0785: // build the EXTDTA data, if necessary
0786: if (extdtaPositions_ != null) {
0787: boolean chainFlag, chainedWithSameCorrelator;
0788:
0789: for (int i = 0; i < extdtaPositions_.size(); i++) {
0790: int index = ((Integer) extdtaPositions_.get(i))
0791: .intValue();
0792:
0793: // is this the last EXTDTA to be built?
0794: if (i != extdtaPositions_.size() - 1) { // no
0795: chainFlag = true;
0796: chainedWithSameCorrelator = true;
0797: } else { // yes
0798: chainFlag = chained;
0799: chainedWithSameCorrelator = false;
0800: }
0801:
0802: // do we have to write a null byte?
0803: boolean writeNullByte = false;
0804: if (parameterMetaData.nullable_[index]) {
0805: writeNullByte = true;
0806: }
0807: // Use the type of the input parameter rather than the input
0808: // column if possible.
0809: int parameterType = parameterMetaData.clientParamtertype_[index];
0810: if (parameterType == 0) {
0811: parameterType = parameterMetaData.types_[index];
0812: }
0813:
0814: // the follow types are possible due to promotion to BLOB
0815: if (parameterType == Types.BLOB
0816: || parameterType == Types.BINARY
0817: || parameterType == Types.VARBINARY
0818: || parameterType == Types.LONGVARBINARY) {
0819: Blob o = (Blob) retrievePromotedParameterIfExists(index);
0820: java.sql.Blob b = (o == null) ? (java.sql.Blob) inputRow[index]
0821: : o;
0822: boolean isExternalBlob = !(b instanceof org.apache.derby.client.am.Blob);
0823: if (isExternalBlob) {
0824: try {
0825: writeScalarStream(chainFlag,
0826: chainedWithSameCorrelator,
0827: CodePoint.EXTDTA, (int) b
0828: .length(), b
0829: .getBinaryStream(),
0830: writeNullByte, index + 1);
0831: } catch (java.sql.SQLException e) {
0832: throw new SqlException(
0833: netAgent_.logWriter_,
0834: new ClientMessageId(
0835: SQLState.NET_ERROR_GETTING_BLOB_LENGTH),
0836: e);
0837: }
0838: } else if (((Blob) b).isBinaryStream()) {
0839: writeScalarStream(chainFlag,
0840: chainedWithSameCorrelator,
0841: CodePoint.EXTDTA, (int) ((Blob) b)
0842: .length(), ((Blob) b)
0843: .getBinaryStream(),
0844: writeNullByte, index + 1);
0845: } else { // must be a binary string
0846: // note: a possible optimization is to use writeScalarLobBytes
0847: // when the input is small
0848: // use this: if (b.length () < DssConstants.MAX_DSS_LEN - 6 - 4)
0849: // writeScalarLobBytes (...)
0850: // Yes, this would avoid having to new up a java.io.ByteArrayInputStream
0851: writeScalarStream(chainFlag,
0852: chainedWithSameCorrelator,
0853: CodePoint.EXTDTA, (int) ((Blob) b)
0854: .length(), ((Blob) b)
0855: .getBinaryStream(),
0856: writeNullByte, index + 1);
0857: }
0858: }
0859: // the follow types are possible due to promotion to CLOB
0860: else if (parameterType == Types.CLOB
0861: || parameterType == Types.CHAR
0862: || parameterType == Types.VARCHAR
0863: || parameterType == Types.LONGVARCHAR) {
0864: Clob o = (Clob) retrievePromotedParameterIfExists(index);
0865: java.sql.Clob c = (o == null) ? (java.sql.Clob) inputRow[index]
0866: : o;
0867: boolean isExternalClob = !(c instanceof org.apache.derby.client.am.Clob);
0868:
0869: if (isExternalClob) {
0870: try {
0871: writeScalarStream(chainFlag,
0872: chainedWithSameCorrelator,
0873: CodePoint.EXTDTA, (int) c
0874: .length(), c
0875: .getCharacterStream(),
0876: writeNullByte, index + 1);
0877: } catch (java.sql.SQLException e) {
0878: throw new SqlException(
0879: netAgent_.logWriter_,
0880: new ClientMessageId(
0881: SQLState.NET_ERROR_GETTING_BLOB_LENGTH),
0882: e);
0883: }
0884: } else if (((Clob) c).isCharacterStream()) {
0885: writeScalarStream(chainFlag,
0886: chainedWithSameCorrelator,
0887: CodePoint.EXTDTA, (int) ((Clob) c)
0888: .length(), ((Clob) c)
0889: .getCharacterStream(),
0890: writeNullByte, index + 1);
0891: } else if (((Clob) c).isAsciiStream()) {
0892: writeScalarStream(chainFlag,
0893: chainedWithSameCorrelator,
0894: CodePoint.EXTDTA, (int) ((Clob) c)
0895: .length(), ((Clob) c)
0896: .getAsciiStream(),
0897: writeNullByte, index + 1);
0898: } else if (((Clob) c).isUnicodeStream()) {
0899: writeScalarStream(chainFlag,
0900: chainedWithSameCorrelator,
0901: CodePoint.EXTDTA, (int) ((Clob) c)
0902: .length(), ((Clob) c)
0903: .getUnicodeStream(),
0904: writeNullByte, index + 1);
0905: } else { // must be a String
0906: // note: a possible optimization is to use writeScalarLobBytes
0907: // when the input is small.
0908: // use this: if (c.length () < DssConstants.MAX_DSS_LEN - 6 - 4)
0909: // writeScalarLobBytes (...)
0910: writeScalarStream(
0911: chainFlag,
0912: chainedWithSameCorrelator,
0913: CodePoint.EXTDTA,
0914: (int) ((Clob) c).getUTF8Length(),
0915: new java.io.ByteArrayInputStream(
0916: ((Clob) c).getUtf8String()),
0917: writeNullByte, index + 1);
0918: }
0919: }
0920: }
0921: }
0922: } catch (java.sql.SQLException se) {
0923: throw new SqlException(se);
0924: }
0925: }
0926:
0927: //-------------------------helper methods-------------------------------------
0928: // returns the a promototedParameter object for index or null if it does not exist
0929: private Object retrievePromotedParameterIfExists(int index) {
0930:
0931: // consider using a nonsynchronized container or array
0932: if (promototedParameters_.isEmpty()) {
0933: return null;
0934: }
0935: return promototedParameters_.get(new Integer(index));
0936: }
0937:
0938: private int calculateColumnsInSQLDTAGRPtriplet(int numVars) {
0939: if (numVars > FdocaConstants.MAX_VARS_IN_NGDA) //rename to MAX_VARS_IN_SQLDTAGRP_TRIPLET
0940: {
0941: return FdocaConstants.MAX_VARS_IN_NGDA;
0942: }
0943: return numVars;
0944: }
0945:
0946: // Consider refacctor so that this does not even have to look
0947: // at the actual object data, and only uses tags from the meta data
0948: // only have to call this once, rather than calling this for every input row
0949: // backburner: after refactoring this, later on, think about replacing case statements with table lookups
0950: private java.util.Hashtable computeProtocolTypesAndLengths(
0951: Object[] inputRow, ColumnMetaData parameterMetaData,
0952: int[][] lidAndLengths, java.util.Hashtable overrideMap)
0953: throws SqlException {
0954: try {
0955: int numVars = parameterMetaData.columns_;
0956: String s = null;
0957: if (!promototedParameters_.isEmpty()) {
0958: promototedParameters_.clear();
0959: }
0960:
0961: for (int i = 0; i < numVars; i++) {
0962:
0963: int jdbcType;
0964: // Send the input type unless it is not available.
0965: // (e.g an output parameter)
0966: jdbcType = parameterMetaData.clientParamtertype_[i];
0967: if (jdbcType == 0) {
0968: jdbcType = parameterMetaData.types_[i];
0969: }
0970:
0971: // jdbc semantics - This should happen outside of the build methods
0972: // if describe input is not supported, we require the user to at least
0973: // call setNull() and provide the type information. Otherwise, we won't
0974: // be able to guess the right PROTOCOL type to send to the server, and an
0975: // exception is thrown.
0976:
0977: if (jdbcType == 0) {
0978: throw new SqlException(
0979: netAgent_.logWriter_,
0980: new ClientMessageId(
0981: SQLState.NET_INVALID_JDBC_TYPE_FOR_PARAM),
0982: new Integer(i));
0983: }
0984:
0985: switch (jdbcType) {
0986: case java.sql.Types.CHAR:
0987: case java.sql.Types.VARCHAR:
0988: // lid: PROTOCOL_TYPE_NVARMIX, length override: 32767 (max)
0989: // dataFormat: String
0990: // this won't work if 1208 is not supported
0991: s = (String) inputRow[i];
0992: // assumes UTF-8 characters at most 3 bytes long
0993: // Flow the String as a VARCHAR
0994: if (s == null || s.length() <= 32767 / 3) {
0995: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NVARMIX;
0996: lidAndLengths[i][1] = 32767;
0997: } else {
0998: // Flow the data as CLOB data if the data too large to for LONGVARCHAR
0999: java.io.ByteArrayInputStream bais = null;
1000: byte[] ba = null;
1001: try {
1002: ba = s.getBytes("UTF-8");
1003: bais = new java.io.ByteArrayInputStream(ba);
1004: Clob c = new Clob(netAgent_, bais, "UTF-8",
1005: ba.length);
1006: // inputRow[i] = c;
1007: // Place the new Lob in the promototedParameter_ collection for
1008: // NetStatementRequest use
1009: promototedParameters_
1010: .put(new Integer(i), c);
1011:
1012: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED;
1013: lidAndLengths[i][1] = buildPlaceholderLength(c
1014: .length());
1015: } catch (java.io.UnsupportedEncodingException e) {
1016: throw new SqlException(
1017: netAgent_.logWriter_,
1018: new ClientMessageId(
1019: SQLState.UNSUPPORTED_ENCODING),
1020: "byte array", "Clob", e);
1021: }
1022: }
1023: break;
1024: case java.sql.Types.INTEGER:
1025: // lid: PROTOCOL_TYPE_NINTEGER, length override: 4
1026: // dataFormat: Integer
1027: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NINTEGER;
1028: lidAndLengths[i][1] = 4;
1029: break;
1030: case java.sql.Types.BOOLEAN:
1031: case java.sql.Types.SMALLINT:
1032: case java.sql.Types.TINYINT:
1033: case java.sql.Types.BIT:
1034: // lid: PROTOCOL_TYPE_NSMALL, length override: 2
1035: // dataFormat: Short
1036: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NSMALL;
1037: lidAndLengths[i][1] = 2;
1038: break;
1039: case java.sql.Types.REAL:
1040: // lid: PROTOCOL_TYPE_NFLOAT4, length override: 4
1041: // dataFormat: Float
1042: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NFLOAT4;
1043: lidAndLengths[i][1] = 4;
1044: break;
1045: case java.sql.Types.DOUBLE:
1046: case java.sql.Types.FLOAT:
1047: // lid: PROTOCOL_TYPE_NFLOAT8, length override: 8
1048: // dataFormat: Double
1049: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NFLOAT8;
1050: lidAndLengths[i][1] = 8;
1051: break;
1052: case java.sql.Types.NUMERIC:
1053: case java.sql.Types.DECIMAL:
1054: // lid: PROTOCOL_TYPE_NDECIMAL
1055: // dataFormat: java.math.BigDecimal
1056: // input only:
1057: // if null and describe input - use describe input precision and scale
1058: // if not null and describe input - calculate precision and actual scale from data
1059: // if null and no describe input - guess with precision 1 scale 0
1060: // if not null and no describe input - calculate precision and actual scale from data
1061: // output only:
1062: // use largest precision/scale based on registered scale from registerOutParameter
1063: // inout:
1064: // if null - use largest precision/scale based on scale from registerOutParameter
1065: // if not null - write bigDecimal () pass registered scale so it can pad, you don't even
1066: // have to look at the actual scale at this level.
1067: /*
1068: if (parameterMetaData.isGuessed) {
1069: java.math.BigDecimal bigDecimal = (java.math.BigDecimal) inputRow[i];
1070: int precision = Utils.computeBigDecimalPrecision (bigDecimal);
1071: lidAndLengths[i][1] = (precision << 8) + // use precision above
1072: (bigDecimal.scale() << 0);
1073: }
1074: */
1075: // Split this entire method into two parts, the first method is called only once and the inputRow is not passed,!!
1076: // the second method is called for every inputRow and overrides inputDA lengths/scales based upon the acutal data!
1077: // for decimal and blob columns only
1078: int precision = parameterMetaData.sqlPrecision_[i];
1079: int scale = parameterMetaData.sqlScale_[i];
1080: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NDECIMAL;
1081: lidAndLengths[i][1] = (precision << 8)
1082: + (scale << 0);
1083: break;
1084: case java.sql.Types.DATE:
1085: // for input, output, and inout parameters
1086: // lid: PROTOCOL_TYPE_NDATE, length override: 8
1087: // dataFormat: java.sql.Date
1088: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NDATE;
1089: lidAndLengths[i][1] = 10;
1090: break;
1091: case java.sql.Types.TIME:
1092: // for input, output, and inout parameters
1093: // lid: PROTOCOL_TYPE_NTIME, length override: 8
1094: // dataFormat: java.sql.Time
1095: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NTIME;
1096: lidAndLengths[i][1] = 8;
1097: break;
1098: case java.sql.Types.TIMESTAMP:
1099: // for input, output, and inout parameters
1100: // lid: PROTOCOL_TYPE_NTIME, length overrid: 26
1101: // dataFormat: java.sql.Timestamp
1102: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NTIMESTAMP;
1103: lidAndLengths[i][1] = 26;
1104: break;
1105: case java.sql.Types.BIGINT:
1106: // if SQLAM < 6 this should be mapped to decimal (19,0) in common layer
1107: // if SQLAM >=6, lid: PROTOCOL_TYPE_NINTEGER8, length override: 8
1108: // dataFormat: Long
1109: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NINTEGER8;
1110: lidAndLengths[i][1] = 8;
1111: break;
1112: case java.sql.Types.LONGVARCHAR:
1113: // Is this the right thing to do // should this be 32700
1114: s = (String) inputRow[i];
1115: if (s == null || s.length() <= 32767 / 3) {
1116: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLONGMIX;
1117: lidAndLengths[i][1] = 32767;
1118: } else {
1119: // Flow the data as CLOB data if the data too large to for LONGVARCHAR
1120: java.io.ByteArrayInputStream bais = null;
1121: byte[] ba = null;
1122: try {
1123: ba = s.getBytes("UTF-8");
1124: bais = new java.io.ByteArrayInputStream(ba);
1125: Clob c = new Clob(netAgent_, bais, "UTF-8",
1126: ba.length);
1127:
1128: // inputRow[i] = c;
1129: // Place the new Lob in the promototedParameter_ collection for
1130: // NetStatementRequest use
1131: promototedParameters_
1132: .put(new Integer(i), c);
1133:
1134: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED;
1135: lidAndLengths[i][1] = buildPlaceholderLength(c
1136: .length());
1137: } catch (java.io.UnsupportedEncodingException e) {
1138: throw new SqlException(
1139: netAgent_.logWriter_,
1140: new ClientMessageId(
1141: SQLState.UNSUPPORTED_ENCODING),
1142: "byte array", "Clob");
1143: }
1144: }
1145: break;
1146: case java.sql.Types.BINARY:
1147: case java.sql.Types.VARBINARY:
1148: byte[] ba = (byte[]) inputRow[i];
1149: if (ba == null) {
1150: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NVARBYTE;
1151: lidAndLengths[i][1] = 32767;
1152: } else if (ba.length <= 32767) {
1153: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NVARBYTE;
1154: lidAndLengths[i][1] = 32767;
1155: } else {
1156: // Promote to a BLOB. Only reach this path in the absence of describe information.
1157: Blob b = new Blob(ba, netAgent_, 0);
1158:
1159: // inputRow[i] = b;
1160: // Place the new Lob in the promototedParameter_ collection for
1161: // NetStatementRequest use
1162: promototedParameters_.put(new Integer(i), b);
1163:
1164: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES;
1165: lidAndLengths[i][1] = buildPlaceholderLength(ba.length);
1166: }
1167: break;
1168: case java.sql.Types.LONGVARBINARY:
1169: ba = (byte[]) inputRow[i];
1170: if (ba == null) {
1171: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLONGVARBYTE;
1172: lidAndLengths[i][1] = 32767;
1173: } else if (ba.length <= 32767) {
1174: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLONGVARBYTE;
1175: lidAndLengths[i][1] = 32767;
1176: } else {
1177: // Promote to a BLOB. Only reach this path in the absensce of describe information.
1178: Blob b = new Blob(ba, netAgent_, 0);
1179:
1180: // inputRow[i] = b;
1181: // Place the new Lob in the promototedParameter_ collection for
1182: // NetStatementRequest use
1183: promototedParameters_.put(new Integer(i), b);
1184:
1185: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES;
1186: lidAndLengths[i][1] = buildPlaceholderLength(ba.length);
1187: }
1188: break;
1189: case java.sql.Types.BLOB:
1190: java.sql.Blob b = (java.sql.Blob) inputRow[i];
1191: if (b == null) {
1192: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES;
1193: lidAndLengths[i][1] = buildPlaceholderLength(parameterMetaData.sqlLength_[i]);
1194: } else {
1195: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBBYTES;
1196: try {
1197: lidAndLengths[i][1] = buildPlaceholderLength(b
1198: .length());
1199: } catch (java.sql.SQLException e) {
1200: throw new SqlException(
1201: netAgent_.logWriter_,
1202: new ClientMessageId(
1203: SQLState.NET_ERROR_GETTING_BLOB_LENGTH),
1204: e);
1205: }
1206: }
1207: break;
1208: case java.sql.Types.CLOB: {
1209: // use columnMeta.singleMixedByteOrDouble_ to decide protocolType
1210: java.sql.Clob c = (java.sql.Clob) inputRow[i];
1211: boolean isExternalClob = !(c instanceof org.apache.derby.client.am.Clob);
1212: long lobLength = 0;
1213: if (c == null) {
1214: lobLength = parameterMetaData.sqlLength_[i];
1215: } else if (isExternalClob) {
1216: try {
1217: lobLength = c.length();
1218: } catch (java.sql.SQLException e) {
1219: throw new SqlException(
1220: netAgent_.logWriter_,
1221: new ClientMessageId(
1222: SQLState.NET_ERROR_GETTING_BLOB_LENGTH),
1223: e);
1224: }
1225: } else {
1226: lobLength = ((Clob) c).length();
1227: }
1228: if (c == null) {
1229: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED;
1230: lidAndLengths[i][1] = buildPlaceholderLength(lobLength);
1231: } else if (isExternalClob) {
1232: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCDBCS;
1233: lidAndLengths[i][1] = buildPlaceholderLength(lobLength);
1234: } else if (((Clob) c).isCharacterStream()) {
1235: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCDBCS;
1236: lidAndLengths[i][1] = buildPlaceholderLength(lobLength);
1237: } else if (((Clob) c).isUnicodeStream()) {
1238: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED;
1239: lidAndLengths[i][1] = buildPlaceholderLength(lobLength);
1240: } else if (((Clob) c).isAsciiStream()) {
1241: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCSBCS;
1242: lidAndLengths[i][1] = buildPlaceholderLength(lobLength);
1243: } else if (((Clob) c).isString()) {
1244: lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NLOBCMIXED;
1245: lidAndLengths[i][1] = buildPlaceholderLength(((Clob) c)
1246: .getUTF8Length());
1247: }
1248: }
1249: break;
1250: default:
1251: throw new SqlException(
1252: netAgent_.logWriter_,
1253: new ClientMessageId(
1254: SQLState.UNRECOGNIZED_JAVA_SQL_TYPE),
1255: new Integer(jdbcType));
1256: }
1257:
1258: if (!parameterMetaData.nullable_[i]) {
1259: lidAndLengths[i][0]--;
1260: }
1261: }
1262: return overrideMap;
1263: } catch (java.sql.SQLException se) {
1264: throw new SqlException(se);
1265: }
1266: }
1267:
1268: private int buildPlaceholderLength(long totalLength) {
1269: if (totalLength < 0x7fff) {
1270: return 0x8002; // need 2 bytes
1271: } else if (totalLength < 0x7fffffff) {
1272: return 0x8004; // need 4 bytes
1273: } else if (totalLength < 0x7fffffffffffL) {
1274: return 0x8006;
1275: } else {
1276: return 0x8008; // need 8 bytes
1277: }
1278: }
1279:
1280: // Output Expected indicates wheterh the requester expects the target
1281: // SQLAM to return output with an SQLDTARD reply data object
1282: // as a result of the execution of the referenced SQL statement.
1283: // this is a single byte.
1284: // there are two possible enumerated values:
1285: // 0x'F1' (CodePoint.TRUE) - for true indicating the requester expects output
1286: // 0x'F0' (CodePoint.FALSE) - for false indicating the requeser does not expect output
1287: // 0x'F0' is the default.
1288: //
1289: // preconditions:
1290: // sqlam must support this parameter on the command, method will not check.
1291: private void buildOUTEXP(boolean outputExpected)
1292: throws SqlException {
1293: if (outputExpected) {
1294: writeScalar1Byte(CodePoint.OUTEXP, CodePoint.TRUE);
1295: }
1296: }
1297:
1298: // Maximum Number of Extra Blocks specifies a limit on the number of extra
1299: // blocks of answer set data per result set that the requester is capable of
1300: // receiveing.
1301: // this value must be able to be contained in a two byte signed number.
1302: // there is a minimum value of 0.
1303: // a zero indicates that the requester is not capable of receiving extra
1304: // query blocks of answer set data.
1305: // there is a SPCVAL of -1.
1306: // a value of -1 indicates that the requester is capable of receiving
1307: // the entire result set.
1308: //
1309: // preconditions:
1310: // sqlam must support this parameter on the command, method will not check.
1311: void buildMAXBLKEXT(int maxNumOfExtraBlocks) throws SqlException {
1312: if (maxNumOfExtraBlocks != 0) {
1313: writeScalar2Bytes(CodePoint.MAXBLKEXT, maxNumOfExtraBlocks);
1314: }
1315: }
1316:
1317: // preconditions:
1318: void buildQRYROWSET(int fetchSize) throws SqlException {
1319: writeScalar4Bytes(CodePoint.QRYROWSET, fetchSize);
1320: }
1321:
1322: // The Procedure Name.
1323: // The default value of PRCNAM is the procedure name value contained
1324: // within the section identified by the pkgnamcsn parameter. If that
1325: // value is null, then the prcnam parameter must be specified.
1326: // it has a max length of 255.
1327: // the prcnam is required on commands if the procedure name is
1328: // specified by a host variable.
1329: // the default value is the procedure name contained in the section
1330: // specified by the pkgnamcsn parameter on the EXCSQLSTT command.
1331: //
1332: // preconditions:
1333: // sqlam must support this parameter for the command, method will not check.
1334: // prcnam can not be null, SQLException will be thrown
1335: // prcnam can not be 0 length or > 255 length, SQLException will be thrown.
1336: private void buildPRCNAM(String prcnam) throws SqlException {
1337: if (prcnam == null) {
1338: throw new SqlException(netAgent_.logWriter_,
1339: new ClientMessageId(
1340: SQLState.NET_NULL_PROCEDURE_NAME));
1341: }
1342:
1343: int prcnamLength = prcnam.length();
1344: if ((prcnamLength == 0) || (prcnamLength > 255)) {
1345: throw new SqlException(
1346: netAgent_.logWriter_,
1347: new ClientMessageId(
1348: SQLState.NET_PROCEDURE_NAME_LENGTH_OUT_OF_RANGE),
1349: new Integer(prcnamLength), new Integer(255));
1350: }
1351:
1352: writeScalarString(CodePoint.PRCNAM, prcnam);
1353: }
1354:
1355: // Query Block Size specifies the query block size for the reply
1356: // data objects and the reply messages being returned from this command.
1357: // this is a 4 byte unsigned binary number.
1358: // the sqlam 6 min value is 512 and max value is 32767.
1359: // this value was increased in later sqlam levels.
1360: // until the code is ready to support larger query block sizes,
1361: // it will always use DssConstants.MAX_DSS_LEN which is 32767.
1362: //
1363: // preconditions:
1364: // sqlam must support this parameter for the command, method will not check.
1365: void buildQRYBLKSZ() throws SqlException {
1366: writeScalar4Bytes(CodePoint.QRYBLKSZ, DssConstants.MAX_DSS_LEN);
1367: }
1368:
1369: // Maximum Result Set Count specifies a limit on the number of result sets
1370: // the requester is capable of receiving as reply data in response to an ECSQLSTT
1371: // command that invokes a stored procedure. If the stored procedure generates
1372: // more than MAXRSLCNT result sets, then the target system returns at most, the first
1373: // MAXRSLCNT of these result sets. The stored procedure defines the order
1374: // in which the target system returns result sets.
1375: // this is s two byte signed binary number.
1376: // it has a min value of 0 which indicates the requester is not capable
1377: // of receiving result sets as reply data in response to the command.
1378: // a special value, -1 (CodePoint.MAXRSLCNT_NOLIMIT = 0xffff), indicates the
1379: // requester is capable of receiving all result sets in response the EXCSQLSTT.
1380: //
1381: // preconditions:
1382: // sqlam must support this parameter for the command, method will not check.
1383: // the value must be in correct range (-1 to 32767), method will not check.
1384: private void buildMAXRSLCNT(int maxResultSetCount)
1385: throws SqlException {
1386: if (maxResultSetCount == 0) {
1387: return;
1388: }
1389: writeScalar2Bytes(CodePoint.MAXRSLCNT, maxResultSetCount);
1390: }
1391:
1392: // RDB Commit Allowed specifies whether an RDB should allow the processing of any
1393: // commit or rollback operations that occure during execution of a statement.
1394: // True allow the processing of commits and rollbacks
1395: private void buildRDBCMTOK() throws SqlException {
1396: writeScalar1Byte(CodePoint.RDBCMTOK, CodePoint.TRUE);
1397: }
1398:
1399: // Result Set Flags is a single byte where each bit it a boolean flag.
1400: // It specifies wheter the requester desires the server to return name,
1401: // label and comment information for the columns of result sets generated by the command.
1402: // The default is b'00000000'.
1403: // columnNamesRequired
1404: // false means the requester does not desire column names returned.
1405: // true means the requester desires column names returned.
1406: // columnLabelsRequired
1407: // false means the requester does not desire column labels returned.
1408: // true means the requester desires column labels returned.
1409: // columnCommentsRequired
1410: // false means the requester does not desire column comments returned.
1411: // true means the requester desired column comments returned.
1412: // cantProcessAnswerSetData
1413: // false means that for each result set, the requester expects the command
1414: // to return an FDOCA description of the answer set data and to possibly
1415: // return answer set data. the block containing the end of the description
1416: // may be completed if room exists with answer set data. additional blocks
1417: // of answer set data may also be chained to the block containing the end of the
1418: // FDOCA description. up to the maximum number of extra blocks of answer set data
1419: // per result set specified in the MAXBLKEXT parameter.
1420: // true means that for each result set, the requester expects the command to return
1421: // an FDOCA description of the answer set data but does not expect the command to
1422: // return any answer set data.
1423: // at SQLAM 7, new flags are supported which can be used to return
1424: // standard, extended, and light sqlda
1425: //
1426: // preconditions:
1427: // sqlam must support this parameter, method will not check.
1428: private void buildRSLSETFLG(int resultSetFlag) throws SqlException {
1429: writeScalar1Byte(CodePoint.RSLSETFLG, resultSetFlag);
1430: }
1431:
1432: void buildQRYINSID(long qryinsid) throws SqlException {
1433: markLengthBytes(CodePoint.QRYINSID);
1434: writeLong(qryinsid);
1435: updateLengthBytes();
1436: }
1437:
1438: // Return SQL Descriptor Area controls whether to return
1439: // an SQL descriptor area that applies to the SQL statement this command
1440: // identifies. The target SQLAM obtains the SQL descriptor area by performing
1441: // an SQL DESCRIBE function on the statement after the statement has been
1442: // prepared.
1443: // The value TRUE, X'F1' (CodePoint.TRUE), indicates an SQLDA is returned
1444: // The value FALSE, X'F0' (CodePoint.FALSE), default, indicates an SQLDA is not returned.
1445: //
1446: // preconditions:
1447: // sqlam must support this parameter for the command, method will not check.
1448: private void buildRTNSQLDA() throws SqlException {
1449: writeScalar1Byte(CodePoint.RTNSQLDA, CodePoint.TRUE);
1450: }
1451:
1452: // Type of SQL Descriptor Area.
1453: // This is a single byte signed number that specifies the type of sqlda to
1454: // return for the command.
1455: // below sqlam 7 there were two possible enumerated values for this parameter.
1456: // 0 (CodePoint.TYPSQLDA_STD_OUTPUT)- the default, indicates return the output sqlda.
1457: // 1 (CodePoint.TYPSQLDA_STD_INPUT) - indicates return the input sqlda.
1458: // the typsqlda was enhanced at sqlam 7 to support extened describe.
1459: // at sqlam 7 the following enumerated values are supported.
1460: // 0 (CodePoint.TYPSQLDA_STD_OUTPUT) - the default, standard output sqlda.
1461: // 1 (CodePoint.TYPSQLDA_STD_INPUT) - standard input sqlda.
1462: // 2 (CodePoint.TYPSQLDA_LIGHT_OUTPUT) - light output sqlda.
1463: // 3 (CodePoint.TYPSQLDA_LIGHT_INPUT) - light input sqlda.
1464: // 4 (CodePoint.TYPSQLDA_X_OUTPUT) - extended output sqlda.
1465: // 5 (CodePoint.TYPSQLDA_X_INPUT) - extended input sqlda.
1466: //
1467: // preconditions:
1468: // sqlam or prdid must support this, method will not check.
1469: // valid enumerated type must be passed to method, method will not check.
1470: private void buildTYPSQLDA(int typeSqlda) throws SqlException {
1471: // possibly inspect typeSqlda value and verify against sqlam level
1472: if (typeSqlda != CodePoint.TYPSQLDA_STD_OUTPUT) {
1473: writeScalar1Byte(CodePoint.TYPSQLDA, typeSqlda);
1474: }
1475: }
1476:
1477: /**
1478: * Build QRYCLSIMP (Query Close Implicit). Query Close Implicit
1479: * controls whether the target server implicitly closes a
1480: * non-scrollable query upon end of data (SQLSTATE 02000).
1481: */
1482: private void buildQRYCLSIMP() {
1483: writeScalar1Byte(CodePoint.QRYCLSIMP, CodePoint.QRYCLSIMP_YES);
1484: }
1485:
1486: // helper method to buildFDODTA to build the actual data length
1487: private void setFDODTALobLength(int[][] protocolTypesAndLengths,
1488: int i, long dataLength) throws SqlException {
1489: if (protocolTypesAndLengths[i][1] == 0x8002) {
1490: writeShort((short) dataLength);
1491: } else if (protocolTypesAndLengths[i][1] == 0x8004) {
1492: writeInt((int) dataLength); // 4 bytes to encode the length
1493: } else if (protocolTypesAndLengths[i][1] == 0x8006)// 6 bytes to encode the length
1494: {
1495: writeLong(dataLength);
1496: }
1497: //throw new SqlException (netAgent_.logWriter_, "0x8006 lob place holders not yet supported");
1498: else if (protocolTypesAndLengths[i][1] == 0x8008)// 8 bytes to encode the length
1499: {
1500: writeLong(dataLength);
1501: }
1502:
1503: if (dataLength != 0) {
1504: if (extdtaPositions_ == null) {
1505: extdtaPositions_ = new java.util.ArrayList();
1506: }
1507: extdtaPositions_.add(new Integer(i));
1508: }
1509: }
1510:
1511: private boolean checkSendQryrowset(int fetchSize, int resultSetType) {
1512: // if the cursor is forward_only, ignore the fetchSize and let the server return
1513: // as many rows as fit in the query block.
1514: // if the cursor is scrollable, send qryrowset if it is supported by the server
1515: boolean sendQryrowset = false;
1516: if (resultSetType != java.sql.ResultSet.TYPE_FORWARD_ONLY) {
1517: sendQryrowset = true;
1518: }
1519: return sendQryrowset;
1520: }
1521:
1522: private int checkFetchsize(int fetchSize, int resultSetType) {
1523: // if fetchSize is not set for scrollable cursors, set it to the default fetchSize
1524: if (resultSetType != java.sql.ResultSet.TYPE_FORWARD_ONLY
1525: && fetchSize == 0) {
1526: fetchSize = org.apache.derby.client.am.Configuration.defaultFetchSize;
1527: }
1528: return fetchSize;
1529: }
1530:
1531: private int calculateResultSetFlags() {
1532: return CodePoint.RSLSETFLG_EXTENDED_SQLDA;
1533: }
1534:
1535: public void writeSetSpecialRegister(java.util.ArrayList sqlsttList)
1536: throws SqlException {
1537: Section section = netAgent_.sectionManager_
1538: .getDynamicSection(java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT);
1539:
1540: buildEXCSQLSET(section);
1541:
1542: // SQLSTT:
1543: for (int i = 0; i < sqlsttList.size(); i++) {
1544: buildSQLSTTcommandData((String) sqlsttList.get(i));
1545: }
1546: }
1547:
1548: private int[][] allocateLidAndLengthsArray(
1549: ColumnMetaData parameterMetaData) {
1550: int numVars = parameterMetaData.columns_;
1551: int[][] lidAndLengths = parameterMetaData.protocolTypesCache_;
1552: if ((lidAndLengths) == null
1553: || (lidAndLengths.length != numVars)) {
1554: lidAndLengths = new int[numVars][2];
1555: parameterMetaData.protocolTypesCache_ = lidAndLengths;
1556: }
1557: return lidAndLengths;
1558: }
1559:
1560: private void buildMddOverrides(java.util.ArrayList sdaOverrides)
1561: throws SqlException {
1562: byte[] mddBytes;
1563: for (int i = 0; i < sdaOverrides.size(); i++) {
1564: mddBytes = (byte[]) (sdaOverrides.get(i));
1565: writeBytes(mddBytes);
1566: }
1567: }
1568:
1569: private int getNextOverrideLid() {
1570: return overrideLid_++;
1571: }
1572: }
|