Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnectionReply.java ------------------------------------------------------------------------------ svn:eol-style = native
Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnectionRequest.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnectionRequest.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnectionRequest.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnectionRequest.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,635 @@ +/* + + Derby - Class org.apache.derby.client.net.NetConnectionRequest + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.net; + + +import org.apache.derby.client.am.SqlException; +import org.apache.derby.client.am.Utils; +import javax.transaction.xa.Xid; + +public class NetConnectionRequest extends Request implements ConnectionRequestInterface +{ + NetConnectionRequest (NetAgent netAgent, CcsidManager ccsidManager, int bufferSize) + { + super (netAgent, ccsidManager, bufferSize); + } + //----------------------------- entry points --------------------------------- + + void writeExchangeServerAttributes (String externalName, + int targetAgent, + int targetSqlam, + int targetRdb, + int targetSecmgr, + int targetCmntcpip, + int targetCmnappc, + int targetXamgr, + int targetSyncptmgr, + int targetRsyncmgr) throws SqlException + { + // send the exchange server attributes command to the server. + // no other commands will be chained to the excsat because + // the manager levels are needed before anything else is attempted. + buildEXCSAT (externalName, + targetAgent, + targetSqlam, + targetRdb, + targetSecmgr, + targetCmntcpip, + targetCmnappc, + targetXamgr, + targetSyncptmgr, + targetRsyncmgr); + + } + + void writeDummyExchangeServerAttributes () throws SqlException + { + // send the exchange server attributes command to the server, + // without any parameters + buildDummyEXCSAT (); + } + + void writeAccessSecurity (int securityMechanism, + String databaseName, + byte[] publicKey) throws SqlException + { + buildACCSEC (securityMechanism, databaseName, publicKey); + } + + void writeSecurityCheck (int securityMechanism, + String databaseName, + String userid, + String password, + byte[] encryptedUserid, + byte[] encryptedPassword) throws SqlException + + + { + buildSECCHK (securityMechanism, + databaseName, + userid, + password, + encryptedUserid, + encryptedPassword); + } + + void writeAccessDatabase (String rdbnam, + boolean readOnly, + byte[] correlationToken, + byte[] productData, + Typdef typdef) throws SqlException + { + buildACCRDB (rdbnam, + readOnly, + correlationToken, + productData, + typdef); + } + + + + public void writeCommitSubstitute (NetConnection connection) throws SqlException + { + buildDummyEXCSAT(); + } + + public void writeLocalCommit (NetConnection connection) throws SqlException + { + buildRDBCMM (); + } + + public void writeLocalRollback (NetConnection connection) throws SqlException + { + buildRDBRLLBCK (); + } + + public void writeLocalXAStart(NetConnection connection) throws SqlException + { + } + + + //Build the SYNNCTL commit command + public void writeLocalXACommit (NetConnection conn) throws SqlException + { + } + + //Build the SYNNCTL rollback command + public void writeLocalXARollback (NetConnection conn) throws SqlException + { + } + + public void writeXaStartUnitOfWork(NetConnection conn) throws SqlException + { + } + + public void writeXaEndUnitOfWork(NetConnection conn) throws SqlException + { + } + + protected void writeXaPrepare(NetConnection conn) throws SqlException + { + } + + protected void writeXaCommit(NetConnection conn, Xid xid) throws SqlException + { + } + + protected void writeXaRollback(NetConnection conn, Xid xid) throws SqlException + { + } + + protected void writeXaRecover(NetConnection conn, int flag) throws SqlException + { + } + + protected void writeXaForget(NetConnection conn, Xid xid) throws SqlException + { + } + + public void writeSYNCType(int codepoint, int syncType) + { + writeScalar1Byte (codepoint, syncType); + } + + public void writeForget(int codepoint, int value) + { + } + + public void writeReleaseConversation(int codepoint, int value) + { + } + + void writeNullXID(int codepoint) + { + } + + void writeXID(int codepoint, Xid xid) throws SqlException + { + } + + + void writeXAFlags(int codepoint, int xaFlags) + { + } + + + //----------------------helper methods---------------------------------------- + // These methods are "private protected", which is not a recognized java privilege, + // but means that these methods are private to this class and to subclasses, + // and should not be used as package-wide friendly methods. + + // RDB Commit Unit of Work (RDBCMM) Command commits all work performed + // for the current unit of work. + // + // The Relational Database Name (RDBNAM) is an optional parameter + // which will not be sent by this command to reduce size, building, + // and parsing. + void buildRDBCMM () throws SqlException + { + createCommand (); + writeLengthCodePoint (0x04, CodePoint.RDBCMM); + } + + // RDB Rollback Unit of Work(RDBRLLBCK) Command rolls back + // all work performed for the current unit of work. + // + // The Relational Database Name (RDBNAM) is an optional parameter + // which will not be sent by this command to reduce size, building, + // and parsing. + void buildRDBRLLBCK () throws SqlException + { + createCommand (); + writeLengthCodePoint (0x04, CodePoint.RDBRLLBCK); + } + + // build the Exchange Server Attributes Command. + // This command sends the following information to the server. + // - this driver's server class name + // - this driver's level of each of the manager's it supports + // - this driver's product release level + // - this driver's external name + // - this driver's server name + void buildEXCSAT (String externalName, + int targetAgent, + int targetSqlam, + int targetRdb, + int targetSecmgr, + int targetCmntcpip, + int targetCmnappc, + int targetXamgr, + int targetSyncptmgr, + int targetRsyncmgr) throws SqlException + { + createCommand (); + + // begin excsat collection by placing the 4 byte llcp in the buffer. + // the length of this command will be computed later and "filled in" + // with the call to request.updateLengthBytes(). + markLengthBytes (CodePoint.EXCSAT); + + // place the external name for the client into the buffer. + // the external name was previously calculated before the call to this method. + buildEXTNAM (externalName); + + // place the server name for the client into the buffer. + buildSRVNAM ("Derby"); + + // place the server release level for the client into the buffer. + // this is a hard coded value for the driver. + buildSRVRLSLV(); + + // the managers supported by this driver and their levels will + // be sent to the server. the variables which store these values + // were initialized during object constrcution to the highest values + // supported by the driver. + + // for the case of the manager levels object, there is no + // need to have the length of the ddm object dynamically calculated + // because this method knows exactly how many will be sent and can set + // this now. + // each manager level class and level are 4 bytes long and + // right now 5 are being sent for a total of 20 bytes or 0x14 bytes. + // writeScalarHeader will be called to insert the llcp. + buildMGRLVLLS (targetAgent, + targetSqlam, + targetRdb, + targetSecmgr, + targetXamgr, + targetSyncptmgr, + targetRsyncmgr); + + + // place the server class name into the buffer. + // this value is hard coded for the driver. + buildSRVCLSNM(); + + // the excsat command is complete so the updateLengthBytes method + // is called to dynamically compute the length for this command and insert + // it into the buffer + updateLengthBytes(); + } + + void buildDummyEXCSAT () throws SqlException + { + createCommand (); + + // begin excsat collection by placing the 4 byte llcp in the buffer. + // the length of this command will be computed later and "filled in" + // with the call to request.updateLengthBytes(). + markLengthBytes (CodePoint.EXCSAT); + + // the excsat command is complete so the updateLengthBytes method + // is called to dynamically compute the length for this command and insert + // it into the buffer + updateLengthBytes(); + } + + void buildACCSEC (int secmec, + String rdbnam, + byte[] sectkn) throws SqlException + { + createCommand (); + + // place the llcp for the ACCSEC in the buffer. save the length bytes for + // later update + markLengthBytes (CodePoint.ACCSEC); + + // the security mechanism is a required instance variable. it will + // always be sent. + buildSECMEC (secmec); + + // the rdbnam will be built and sent. different sqlam levels support + // different lengths. at this point the length has been checked against + // the maximum allowable length. so write the bytes and padd up to the + // minimum length if needed. + buildRDBNAM (rdbnam); + + if (sectkn != null) buildSECTKN (sectkn); + + // the accsec command is complete so notify the the request object to + // update the ddm length and the dss header length. + updateLengthBytes(); + } + + void buildSECCHK (int secmec, + String rdbnam, + String user, + String password, + byte[] sectkn, + byte[] sectkn2) throws SqlException + { + createCommand (); + markLengthBytes (CodePoint.SECCHK); + + // always send the negotiated security mechanism for the connection. + buildSECMEC (secmec); + + // the rdbnam will be built and sent. different sqlam levels support + // different lengths. at this point the length has been checked against + // the maximum allowable length. so write the bytes and padd up to the + // minimum length if needed. + buildRDBNAM (rdbnam); + if (user != null ) buildUSRID (user); + if (password != null ) buildPASSWORD (password); + if (sectkn != null) buildSECTKN (sectkn); + if (sectkn2 != null) buildSECTKN (sectkn2); + updateLengthBytes(); + + } + + // The Access RDB (ACCRDB) command makes a named relational database (RDB) + // available to a requester by creating an instance of an SQL application + // manager. The access RDB command then binds the created instance to the target + // agent and to the RDB. The RDB remains available (accessed) until + // the communications conversation is terminate. + void buildACCRDB (String rdbnam, + boolean readOnly, + byte[] crrtkn, + byte[] prddta, + Typdef typdef) throws SqlException + { + createCommand (); + + markLengthBytes (CodePoint.ACCRDB); + + // the relational database name specifies the name of the rdb to + // be accessed. this can be different sizes depending on the level of + // support. the size will have ben previously checked so at this point just + // write the data and pad with the correct number of bytes as needed. + // this instance variable is always required. + buildRDBNAM (rdbnam); + + // the rdb access manager class specifies an instance of the SQLAM + // that accesses the RDB. the sqlam manager class codepoint + // is always used/required for this. this instance variable + // is always required. + buildRDBACCCL(); + + // product specific identifier specifies the product release level + // of this driver. see the hard coded value in the NetConfiguration class. + // this instance variable is always required. + buildPRDID(); + + // product specific data. this is an optional parameter which carries + // product specific information. although it is optional, it will be + // sent to the server. use the first byte to determine the number + // of the prddta bytes to write to the buffer. note: this length + // doesn't include itself so increment by it by 1 to get the actual + // length of this data. + buildPRDDTA (prddta); + + + // the typdefnam parameter specifies the name of the data type to data representation + // mappings used when this driver sends command data objects. + buildTYPDEFNAM (typdef.getTypdefnam()); + + if (crrtkn == null) + netAgent_.netConnection_.constructCrrtkn(); + + buildCRRTKN(netAgent_.netConnection_.crrtkn_); + + // This specifies the single-byte, double-byte + // and mixed-byte CCSIDs of the Scalar Data Arrays (SDAs) in the identified + // data type to the data representation mapping definitions. This can + // contain 3 CCSIDs. The driver will only send the ones which were set. + buildTYPDEFOVR (typdef.isCcsidSbcSet(), + typdef.getCcsidSbc(), + typdef.isCcsidDbcSet(), + typdef.getCcsidDbc(), + typdef.isCcsidMbcSet(), + typdef.getCcsidMbc()); + + // RDB allow update is an optional parameter which indicates + // whether the RDB allows the requester to perform update operations + // in the RDB. If update operations are not allowed, this connection + // is limited to read-only access of the RDB resources. + buildRDBALWUPD (readOnly); + + + + // the Statement Decimal Delimiter (STTDECDEL), + // Statement String Delimiter (STTSTRDEL), + // and Target Default Value Return (TRGDFTRT) are all optional + // instance variables which will not be sent to the server. + + // the command and the dss are complete so make the call to notify + // the request object. + updateLengthBytes(); + } + + + void buildSYNCCTLMigrate() throws SqlException + { + } + + void buildSYNCCTLCommit (int xaFlags, Xid xid) throws SqlException + { + } + + void buildSYNCCTLRollback (int xaFlags) throws SqlException + { + } + + + // The External Name is the name of the job, task, or process on a + // system for which a DDM server is active. + private void buildEXTNAM (String extnam) throws SqlException + { + int extnamTruncateLength = Utils.min (extnam.length(), + NetConfiguration.EXTNAM_MAXSIZE); + + writeScalarString (CodePoint.EXTNAM, + extnam.substring (0, extnamTruncateLength)); + } + + // Server Name is the name of the DDM server. + private void buildSRVNAM (String srvnam) throws SqlException + { + int srvnamTruncateLength = Utils.min (srvnam.length(), + NetConfiguration.SRVNAM_MAXSIZE); + writeScalarString (CodePoint.SRVNAM, + srvnam.substring (0,srvnamTruncateLength)); + } + + // Server Product Release Level String specifies the product + // release level of a DDM server. + private void buildSRVRLSLV () throws SqlException + { + // Hard-coded to ClientDNC 1.0 for dnc 1.0. + writeScalarString (CodePoint.SRVRLSLV, NetConfiguration.SRVRLSLV); + } + + private void buildSRVCLSNM () throws SqlException + { + // Server class name is hard-coded to QDERBY/JVM for dnc. + writeScalarString (CodePoint.SRVCLSNM, NetConfiguration.SRVCLSNM_JVM); + } + + // Precondition: valid secmec is assumed. + private void buildSECMEC (int secmec) throws SqlException + { + writeScalar2Bytes (CodePoint.SECMEC, secmec); + } + + // Relational Database Name specifies the name of a relational database + // of the server. + // if length of RDB name <= 18 characters, there is not change to the format + // of the RDB name. The length of the RDBNAM remains fixed at 18 which includes + // any right bland padding if necessary. + // if length of the RDB name is > 18 characters, the length of the RDB name is + // identical to the length of the RDB name. No right blank padding is required. + private void buildRDBNAM (String rdbnam) throws SqlException + { + // since this gets built more than once on the connect flow, + // see if we can optimize + + int rdbnamLength = rdbnam.length(); + if (rdbnamLength <= NetConfiguration.PKG_IDENTIFIER_FIXED_LEN ) { + writeScalarPaddedString (CodePoint.RDBNAM, + rdbnam, + NetConfiguration.PKG_IDENTIFIER_FIXED_LEN); // minimum length of RDBNAM + } + else { + if (rdbnamLength <= NetConfiguration.PKG_IDENTIFIER_MAX_LEN) + writeScalarString (CodePoint.RDBNAM, rdbnam); + else + throw new SqlException (netAgent_.logWriter_, "Length of the Relational Database Name, " + + rdbnam + + ", exceeds maximum size allowed for PROTOCOL Connection.");// + + //"at SQLAM level " + netAgent_.targetSqlam_); + } + } + + private void buildSECTKN (byte[] sectkn) throws SqlException + { + if (sectkn.length > NetConfiguration.SECTKN_MAXSIZE) + throw new SqlException (netAgent_.logWriter_, "bug check: sectkn too long"); + writeScalarBytes (CodePoint.SECTKN, sectkn); + } + + private void buildUSRID (String usrid) throws SqlException + { + int usridLength = usrid.length(); + if ((usridLength == 0) || (usridLength > NetConfiguration.USRID_MAXSIZE)) + throw new SqlException (netAgent_.logWriter_, "userid length, " + usridLength + ", is not allowed."); + + writeScalarString (CodePoint.USRID, usrid); + } + + private void buildPASSWORD (String password) throws SqlException + { + int passwordLength = password.length(); + if ((passwordLength == 0) || (passwordLength > NetConfiguration.PASSWORD_MAXSIZE)) + throw new SqlException (netAgent_.logWriter_, "password length, " + passwordLength + ", is not allowed."); + if (netAgent_.logWriter_ != null) { + // remember the position of password in order to + // mask it out in trace (see Request.sendBytes()). + passwordIncluded_ = true; + passwordStart_ = offset_ + 4; + passwordLength_ = passwordLength; + } + writeScalarString (CodePoint.PASSWORD, password); + } + + private void buildRDBACCCL() throws SqlException + { + writeScalar2Bytes (CodePoint.RDBACCCL, CodePoint.SQLAM); + } + + + private void buildPRDID () throws SqlException + { + writeScalarString (CodePoint.PRDID, NetConfiguration.PRDID); // product id is hard-coded to DNC01000 for dnc 1.0. + } + + private void buildPRDDTA (byte[] prddta) throws SqlException + { + int prddtaLength = (prddta[NetConfiguration.PRDDTA_LEN_BYTE] & 0xff) + 1; + writeScalarBytes (CodePoint.PRDDTA, prddta, 0, prddtaLength); + } + + private void buildTYPDEFNAM (String typdefnam) throws SqlException + { + writeScalarString (CodePoint.TYPDEFNAM, typdefnam); + } + + void buildTYPDEFOVR (boolean sendCcsidSbc, + int ccsidSbc, + boolean sendCcsidDbc, + int ccsidDbc, + boolean sendCcsidMbc, + int ccsidMbc + ) throws SqlException + { + markLengthBytes (CodePoint.TYPDEFOVR); + // write the single-byte ccsid used by this driver. + if (sendCcsidSbc) writeScalar2Bytes (CodePoint.CCSIDSBC, ccsidSbc); + + // write the double-byte ccsid used by this driver. + if (sendCcsidDbc) writeScalar2Bytes (CodePoint.CCSIDDBC, ccsidDbc); + + // write the mixed-byte ccsid used by this driver + if (sendCcsidMbc) writeScalar2Bytes (CodePoint.CCSIDMBC, ccsidMbc); + + updateLengthBytes(); + + } + + private void buildMGRLVLLS (int agent, + int sqlam, + int rdb, + int secmgr, + int xamgr, + int syncptmgr, + int rsyncmgr) throws SqlException + + { + markLengthBytes(CodePoint.MGRLVLLS); + + // place the managers and their levels in the buffer + writeCodePoint4Bytes (CodePoint.AGENT, agent); + writeCodePoint4Bytes (CodePoint.SQLAM, sqlam); + writeCodePoint4Bytes (CodePoint.RDB, rdb); + writeCodePoint4Bytes (CodePoint.SECMGR, secmgr); + + if (netAgent_.netConnection_.isXAConnection()) + { + if (xamgr != NetConfiguration.MGRLVL_NA) writeCodePoint4Bytes (CodePoint.XAMGR, xamgr); + if (syncptmgr != NetConfiguration.MGRLVL_NA) writeCodePoint4Bytes (CodePoint.SYNCPTMGR, syncptmgr); + if (rsyncmgr != NetConfiguration.MGRLVL_NA) writeCodePoint4Bytes (CodePoint.RSYNCMGR, rsyncmgr); + } + updateLengthBytes(); + } + + private void buildCRRTKN (byte[] crrtkn) throws SqlException + { + writeScalarBytes (CodePoint.CRRTKN, crrtkn); + } + + private void buildRDBALWUPD (boolean readOnly) throws SqlException + { + if (readOnly) writeScalar1Byte (CodePoint.RDBALWUPD, CodePoint.FALSE); + } + +} + + + Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnectionRequest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,1066 @@ +/* + + Derby - Class org.apache.derby.client.net.NetCursor + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.net; + +import org.apache.derby.client.am.SqlException; +import org.apache.derby.client.am.SqlWarning; +import org.apache.derby.client.am.SignedBinary; +import org.apache.derby.client.am.DisconnectException; +import org.apache.derby.client.am.Blob; +import org.apache.derby.client.am.Clob; +import org.apache.derby.client.am.Agent; +import org.apache.derby.client.am.Types; + +public class NetCursor extends org.apache.derby.client.am.Cursor +{ + + NetResultSet netResultSet_; + NetAgent netAgent_; + + Typdef qrydscTypdef_; + + int targetSqlamForTypdef_; + + + // override column meta data + int numMddOverrides_; + int maximumRowSize_; + boolean blocking_; // if true, multiple rows may be "blocked" in a single reply + + // Raw fdoca column meta data. + int[] typeToUseForComputingDataLength_; + boolean[] isGraphic_; + + // key = column position, value = index into extdtaData_ + java.util.HashMap extdtaPositions_; + java.util.ArrayList extdtaData_; // queue to hold EXTDTA data that hasn't been correlated to its column # + + + boolean rtnextrow_ = true; + + //-----------------------------constants-------------------------------------- + + //---------------------constructors/finalizer--------------------------------- + + NetCursor (NetAgent netAgent) + { + super (netAgent); + netAgent_ = netAgent; + numMddOverrides_ = 0; + maximumRowSize_ = 0; + extdtaPositions_ = new java.util.HashMap(); + extdtaData_ = new java.util.ArrayList (); + } + + NetCursor (NetAgent netAgent, + int qryprctyp) //protocolType, CodePoint.FIXROWPRC | CodePoint.LMTBLKPRC + { + this (netAgent); + if (qryprctyp == CodePoint.FIXROWPRC) + blocking_ = false; + else if (qryprctyp == CodePoint.LMTBLKPRC) + blocking_ = true; + } + //-----------------------------parsing the data buffer------------------------ + + // Pseudo-code: + // parse thru the current row in dataBuffer computing column offsets + // if (we hit the super.lastValidBytePosition, ie. encounter partial row) { + // shift partial row bytes to beginning of dataBuffer (this.shiftPartialRowToBeginning()) + // reset current row position (also done by this.shiftPartialRowToBeginning()) + // send and recv continue-query into commBuffer (rs.flowContinueQuery()) + // parse commBuffer up to QRYDTA (rs.flowContinueQuery()) + // copy query data from reply's commBuffer to our dataBuffer (this.copyQrydta()) + // } + // Returns true if the current row position is a valid row position. + // rename this to parse*() + protected boolean calculateColumnOffsetsForRow_ (int rowIndex) throws SqlException, org.apache.derby.client.am.DisconnectException + { + int daNullIndicator = CodePoint.NULLDATA; + int colNullIndicator = CodePoint.NULLDATA; + int length; + + if (hasLobs_) + extdtaPositions_.clear(); // reset positions for this row + + int[] columnDataPosition = null; + int[] columnDataComputedLength = null; + boolean[] columnDataIsNull = null; + + if ((position_ == lastValidBytePosition_) && + (netResultSet_ != null) && (netResultSet_.scrollable_)) + return false; + + NetSqlca netSqlca = this.parseSQLCARD (qrydscTypdef_); + + if (netSqlca != null) { + int sqlcode = netSqlca.getSqlCode(); + if (sqlcode < 0) { + throw new SqlException (netAgent_.logWriter_, netSqlca); + } + else { + if (sqlcode > 0) { + if (sqlcode == 100) { + allRowsReceivedFromServer_ = true; + if (netResultSet_ != null && netSqlca.containsSqlcax()) + netResultSet_.setRowCountEvent (netSqlca.getRowCount(qrydscTypdef_)); + } + else if (netResultSet_ != null) + netResultSet_.accumulateWarning (new SqlWarning (agent_.logWriter_, netSqlca)); + } + } + } + + // If we don't have at least one byte in the buffer for the DA null indicator, + // then we need to send a CNTQRY request to fetch the next block of data. + // Read the DA null indicator. + daNullIndicator = readFdocaOneByte (); + + // In the case for held cursors, the +100 comes back as part of the QRYDTA, and as + // we are parsing through the row that contains the SQLCA with +100, we mark the + // nextRowPosition_ which is the lastValidBytePosition_, but we don't mark the + // currentRowPosition_ until the next time next() is called causing the check + // cursor_.currentRowPositionIsEqualToNextRowPosition () to fail in getRow() and thus + // not returning 0 when it should. So we need to mark the current row position immediately + // in order for getRow() to be able to pick it up. + + // markNextRowPosition() is called again once this method returns, but it is ok + // since it's only resetting nextRowPosition_ to position_ and position_ will + // not change again from this point. + + if (allRowsReceivedFromServer_ && (position_ == lastValidBytePosition_)) { + markNextRowPosition (); + makeNextRowPositionCurrent (); + return false; + } + + // If data flows.... + if (daNullIndicator == 0x0) { + + incrementRowsReadEvent(); + + // netResultSet_ is null if this method is invoked from Lob.position() + // If row has exceeded the size of the ArrayList, new up a new int[] and add it to the + // ArrayList, otherwise just reuse the int[]. + if (netResultSet_ != null && netResultSet_.scrollable_) { + columnDataPosition = allocateColumnDataPositionArray (rowIndex); + columnDataComputedLength = allocateColumnDataComputedLengthArray (rowIndex); + columnDataIsNull = allocateColumnDataIsNullArray (rowIndex); + // Since we are no longer setting the int[]'s to null for a delete/update hole, we need + // another way of keeping track of the delete/update holes. + setIsUpdataDeleteHole (rowIndex, false); + } + else { + // Use the arrays defined on the Cursor for forward-only cursors. + // can they ever be null + if (columnDataPosition_ == null || columnDataComputedLength_ == null || isNull_ == null) + allocateColumnOffsetAndLengthArrays (); + columnDataPosition = columnDataPosition_; + columnDataComputedLength = columnDataComputedLength_; + columnDataIsNull = isNull_; + } + + // Loop through the columns + for (int index = 0; index < columns_; index++) { + // If column is nullable, read the 1-byte null indicator. + if (nullable_[index]) + // Need to pass the column index so all previously calculated offsets can be + // readjusted if the query block splits on a column null indicator. + + // null indicators from FD:OCA data + // 0 to 127: a data value will flow. + // -1 to -128: no data value will flow. + colNullIndicator = readFdocaOneByte (index); + + // If non-null column data + if (!nullable_[index] || (colNullIndicator >= 0 && colNullIndicator <= 127)) { + + // Set the isNull indicator to false + columnDataIsNull[index] = false; + + switch (typeToUseForComputingDataLength_[index]) { + // for fixed length data + case Typdef.FIXEDLENGTH: + columnDataPosition[index] = position_; + if (isGraphic_[index]) + columnDataComputedLength[index] = skipFdocaBytes (fdocaLength_[index]*2, index); + else + columnDataComputedLength[index] = skipFdocaBytes (fdocaLength_[index], index); + break; + + // for variable character string and variable byte string, + // there are 2-byte of length in front of the data + case Typdef.TWOBYTELENGTH: + columnDataPosition[index] = position_; + length = readFdocaTwoByteLength (index); + // skip length + the 2-byte length field + if (isGraphic_[index]) + columnDataComputedLength[index] = skipFdocaBytes (length*2, index) + 2; + else + columnDataComputedLength[index] = skipFdocaBytes (length, index) + 2; + break; + + // For decimal columns, determine the precision, scale, and the representation + case Typdef.DECIMALLENGTH: + columnDataPosition[index] = position_; + columnDataComputedLength[index] = skipFdocaBytes (getDecimalLength(index), index); + break; + + case Typdef.LOBLENGTH: + columnDataPosition[index] = position_; + columnDataComputedLength[index] = this.skipFdocaBytes (fdocaLength_[index] & 0x7fff, index); + break; + + // for short variable character string and short variable byte string, + // there is a 1-byte length in front of the data + case Typdef.ONEBYTELENGTH: + columnDataPosition[index] = position_; + length = readFdocaOneByte (index); + // skip length + the 1-byte length field + if (isGraphic_[index]) + columnDataComputedLength[index] = skipFdocaBytes (length*2, index) + 1; + else + columnDataComputedLength[index] = skipFdocaBytes (length, index) + 1; + break; + + default: + columnDataPosition[index] = position_; + if (isGraphic_[index]) + columnDataComputedLength[index] = skipFdocaBytes (fdocaLength_[index]*2, index); + else + columnDataComputedLength[index] = skipFdocaBytes (fdocaLength_[index], index); + break; + } + } + else if ((colNullIndicator & 0x80) == 0x80) { + // Null data. Set the isNull indicator to true. + columnDataIsNull[index] = true; + } + } + + // set column offsets for the current row. + columnDataPosition_ = columnDataPosition; + columnDataComputedLength_ = columnDataComputedLength; + isNull_ = columnDataIsNull; + + if (!allRowsReceivedFromServer_) { + calculateLobColumnPositionsForRow(); + // Flow another CNTQRY if we are blocking, are using rtnextrow, and expect + // non-trivial EXTDTAs for forward only cursors. Note we do not support + // EXTDTA retrieval for scrollable cursors. + // if qryrowset was sent on excsqlstt for a sp call, which is only the case + if (blocking_ && rtnextrow_ && + extdtaPositions_.size () > 0 && !netResultSet_.scrollable_) + if (!extdtaPositions_.isEmpty()) + netResultSet_.flowFetch (); + } + } + + // Else if this row is null, only add to the isRowNullCache_ if the cursor is scrollable. + else { + if (netResultSet_ != null && netResultSet_.scrollable_) setIsUpdataDeleteHole (rowIndex, true); + } + + // If blocking protocol is used, we could have already received an ENDQRYRM, + // which sets allRowsReceivedFromServer_ to true. It's safe to assume that all of + // our QRYDTA's have been successfully copied to the dataBuffer. And even though + // the flag for allRowsReceivedFromServer_ is set, we still want to continue to parse through + // the data in the dataBuffer. + // But in the case where fixed row protocol is used, + if (!blocking_ && allRowsReceivedFromServer_ && daNullIndicator == 0xFF) + return false; + else + return true; + } + + protected boolean isDataBufferNull () + { + if (dataBuffer_ == null) + return true; + else + return false; + } + + protected void allocateDataBuffer () + { + int length; + if (maximumRowSize_ > DssConstants.MAX_DSS_LEN) + length = maximumRowSize_; + else + length = DssConstants.MAX_DSS_LEN; + + dataBuffer_ = new byte[length]; + position_ = 0; + lastValidBytePosition_ = 0; + } + + protected void allocateDataBuffer (int length) + { + dataBuffer_ = new byte[length]; + } + + + private int readFdocaInt () throws org.apache.derby.client.am.DisconnectException, SqlException + { + if ((position_ + 4) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + + int i = SignedBinary.getInt (dataBuffer_, position_); + position_ += 4; + return i; + } + + // Reads 1-byte from the dataBuffer from the current position. + // If position is already at the end of the buffer, send CNTQRY to get more data. + private int readFdocaOneByte () throws org.apache.derby.client.am.DisconnectException, SqlException + { + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if (position_ == lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + return dataBuffer_[position_++] & 0xff; + } + + // Reads 1-byte from the dataBuffer from the current position. + // If position is already at the end of the buffer, send CNTQRY to get more data. + private int readFdocaOneByte (int index) throws org.apache.derby.client.am.DisconnectException, SqlException + { + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if (position_ == lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (index); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + return dataBuffer_[position_++] & 0xff; + } + + // Reads <i>length</i> number of bytes from the dataBuffer starting from the + // current position. Returns a new byte array which contains the bytes read. + // If current position plus length goes past the lastValidBytePosition, send + // CNTQRY to get more data. + private byte[] readFdocaBytes (int length) throws org.apache.derby.client.am.DisconnectException, SqlException + { + byte[] b = new byte[length];; + + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if ((position_ + length) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + + for (int i = 0; i < length; i++) + b[i] = dataBuffer_[position_++]; + + return b; + } + + // Reads 2-bytes from the dataBuffer starting from the current position, and + // returns an integer constructed from the 2-bytes. If current position plus + // 2 bytes goes past the lastValidBytePosition, send CNTQRY to get more data. + private int readFdocaTwoByteLength () throws org.apache.derby.client.am.DisconnectException, SqlException + { + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if ((position_ + 2) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + + return + ((dataBuffer_[position_++] & 0xff) << 8) + + ((dataBuffer_[position_++] & 0xff) << 0); + } + + private int readFdocaTwoByteLength (int index) throws org.apache.derby.client.am.DisconnectException, SqlException + { + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if ((position_ + 2) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (index); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + + return + ((dataBuffer_[position_++] & 0xff) << 8) + + ((dataBuffer_[position_++] & 0xff) << 0); + } + + // Check if position plus length goes past the lastValidBytePosition. + // If so, send CNTQRY to get more data. + // length - number of bytes to skip + // returns the number of bytes skipped + private int skipFdocaBytes (int length) throws org.apache.derby.client.am.DisconnectException, SqlException + { + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if ((position_ + length) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + position_ += length; + return length; + } + + private int skipFdocaBytes (int length, int index) throws org.apache.derby.client.am.DisconnectException, SqlException + { + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if ((position_ + length) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (index); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + + position_ += length; + return length; + } + + // Shift partial row bytes to beginning of dataBuffer, + // and resets current row position, and lastValidBytePosition. + // When we shift partial row, we'll have to recalculate column offsets + // up to this column. + private void shiftPartialRowToBeginning () + { + // Get the length to shift from the beginning of the partial row. + int length = lastValidBytePosition_ - currentRowPosition_; + + // shift the data in the dataBufferStream + dataBufferStream_.reset (); + if (dataBuffer_ != null) + dataBufferStream_.write (dataBuffer_, currentRowPosition_, length); + + for (int i = 0; i < length; i++) + dataBuffer_[i] = dataBuffer_[currentRowPosition_+i]; + + position_ = length - (lastValidBytePosition_ - position_); + lastValidBytePosition_ = length; + } + + private void adjustColumnOffsetsForColumnsPreviouslyCalculated (int index) + { + for (int j = 0; j <= index; j++) { + columnDataPosition_[j] -= currentRowPosition_; + } + } + + private void resetCurrentRowPosition () + { + currentRowPosition_ = 0; + } + + // Calculates the column index for Lob objects constructed from EXTDTA data. + // Describe information isn't sufficient because we have to check + // for trivial values (nulls or zero-length) and exclude them. + void calculateLobColumnPositionsForRow () + { + int currentPosition = 0; + + for (int i = 0; i < columns_; i++) { + if ( isNonTrivialDataLob (i) ) + // key = column position, data = index to corresponding data in extdtaData_ + // ASSERT: the server always returns the EXTDTA objects in ascending order + extdtaPositions_.put(new Integer(i + 1), new Integer (currentPosition++)); + } + } + + // prereq: the base data for the cursor has been processed for offsets and lengths + boolean isNonTrivialDataLob (int index) + { + long length = 0L; + + if (isNull_[index] || + (jdbcTypes_[index] != Types.BLOB && + jdbcTypes_[index] != Types.CLOB) ) + return false; + + int position = columnDataPosition_[index]; + + // if the high-order bit is set, length is unknown -> set value to x'FF..FF' + if (((dataBuffer_[position])&0x80) == 0x80) + length = -1; + else { + + byte[] lengthBytes = new byte[columnDataComputedLength_[index]]; + byte[] longBytes = new byte[8]; + + System.arraycopy (dataBuffer_, + position, + lengthBytes, + 0, + columnDataComputedLength_[index] ); + + // right-justify for BIG ENDIAN + int j = 0; + for (int i = 8 - columnDataComputedLength_[index]; i < 8; i++) { + longBytes[i] = lengthBytes[j]; + j++; + } + length = SignedBinary.getLong (longBytes, 0); + } + return (length != 0L)?true:false; + } + + protected void clearLobData_() + { + extdtaData_.clear (); + extdtaPositions_.clear (); + } + + // SQLCARD : FDOCA EARLY ROW + // SQL Communications Area Row Description + // + // FORMAT FOR ALL SQLAM LEVELS + // SQLCAGRP; GROUP LID 0x54; ELEMENT TAKEN 0(all); REP FACTOR 1 + NetSqlca parseSQLCARD (Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException + { + return parseSQLCAGRP (typdef); + } + + // SQLCAGRP : FDOCA EARLY GROUP + // SQL Communcations Area Group Description + // + // FORMAT FOR SQLAM <= 6 + // SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5 + // SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8 + // SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0 + // + // FORMAT FOR SQLAM >= 7 + // SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5 + // SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8 + // SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0 + // SQLDIAGGRP; PROTOCOL TYPE N-GDA; ENVLID 0x56; Length Override 0 + private NetSqlca parseSQLCAGRP (Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException + { + if (readFdocaOneByte() == CodePoint.NULLDATA) + return null; + int sqlcode = readFdocaInt(); + byte[] sqlstate = readFdocaBytes (5); + byte[] sqlerrproc = readFdocaBytes (8); + NetSqlca netSqlca = new NetSqlca (netAgent_.netConnection_, sqlcode, sqlstate, sqlerrproc, typdef.getCcsidSbc()); + + parseSQLCAXGRP (typdef, netSqlca); + + parseSQLDIAGGRP (); + + return netSqlca; + } + + // SQLCAXGRP : EARLY FDOCA GROUP + // SQL Communications Area Exceptions Group Description + // + // FORMAT FOR SQLAM <= 6 + // SQLRDBNME; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 18 + // SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70 + // SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70 + // + // FORMAT FOR SQLAM >= 7 + // SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + // SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + // SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255 + // SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70 + // SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70 + private void parseSQLCAXGRP (Typdef typdef, NetSqlca netSqlca) throws DisconnectException, SqlException + { + if (readFdocaOneByte() == CodePoint.NULLDATA) { + netSqlca.setContainsSqlcax (false); + return; + } + + + // SQLERRD1 to SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4 + int[] sqlerrd = new int[6]; + for (int i = 0; i < sqlerrd.length; i++) + sqlerrd[i] = readFdocaInt (); + + // SQLWARN0 to SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1 + byte[] sqlwarn = readFdocaBytes (11); + + // skip over the rdbnam for now + // SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255 + parseVCS (typdef); + + // SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70 + // SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70 + int varcharLength = readFdocaTwoByteLength(); // mixed length + byte[] sqlerrmc = null; + int sqlerrmcCcsid = 0; + if (varcharLength != 0) { // if mixed + sqlerrmc = readFdocaBytes(varcharLength); // read mixed bytes + sqlerrmcCcsid = typdef.getCcsidMbc(); + skipFdocaBytes(2); // skip single length + } + else { + varcharLength = readFdocaTwoByteLength(); // read single length + sqlerrmc = readFdocaBytes (varcharLength); // read single bytes + sqlerrmcCcsid = typdef.getCcsidSbc(); + } + + netSqlca.setSqlerrd (sqlerrd); + netSqlca.setSqlwarnBytes (sqlwarn); + netSqlca.setSqlerrmcBytes (sqlerrmc, sqlerrmcCcsid); + } + + // SQLDIAGGRP : FDOCA EARLY GROUP + private void parseSQLDIAGGRP () throws DisconnectException, SqlException + { + if (readFdocaOneByte() == CodePoint.NULLDATA) + return; + + netAgent_.accumulateChainBreakingReadExceptionAndThrow (new DisconnectException ( + netAgent_, + "parseSQLDIAGGRP not yet implemented")); + } + + private String parseVCS (Typdef typdefInEffect) throws DisconnectException, SqlException + { + return readFdocaString(readFdocaTwoByteLength(), + typdefInEffect.getCcsidSbcEncoding()); + } + + // This is not used for column data. + private String readFdocaString (int length, String encoding) throws DisconnectException, SqlException + { + if (length == 0) + return null; + + // For singleton select, the complete row always comes back, even if multiple query blocks are required, + // so there is no need to drive a flowFetch (continue query) request for singleton select. + if ((position_ + length) > lastValidBytePosition_) { + // Check for ENDQRYRM, throw SqlException if already received one. + checkAndThrowReceivedEndqryrm (); + + // Send CNTQRY to complete the row/rowset. + int lastValidByteBeforeFetch = completeSplitRow (); + + // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received, + // throw a SqlException for the ENDQRYRM. + checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch); + } + + String s = null; + + try { + s = new String (dataBuffer_, position_, length, encoding); + } + catch (java.io.UnsupportedEncodingException e) { + netAgent_.accumulateChainBreakingReadExceptionAndThrow ( + new org.apache.derby.client.am.DisconnectException ( + e, + netAgent_, + "encoding not supported!!")); + } + + position_ += length; + return s; + } + + void allocateColumnOffsetAndLengthArrays () + { + columnDataPosition_ = new int[columns_]; + columnDataComputedLength_ = new int[columns_]; + isNull_ = new boolean[columns_]; + } + + void setBlocking (int queryProtocolType) + { + if (queryProtocolType == CodePoint.LMTBLKPRC) + blocking_ = true; + else + blocking_ = false; + } + + protected byte[] findExtdtaData (int column) + { + byte[] data = null; + + // locate the EXTDTA bytes, if any + Integer key = new Integer(column); + + if (extdtaPositions_.containsKey (key)) { + // found, get the data + int extdtaQueuePosition = ((Integer) extdtaPositions_.get(key)).intValue(); + data = (byte[]) (extdtaData_.get(extdtaQueuePosition)); + } + + return data; + } + + public Blob getBlobColumn_ (int column, Agent agent) throws SqlException + { + int index = column - 1; + int dataOffset; + byte[] data; + Blob blob = null; + + // locate the EXTDTA bytes, if any + data = findExtdtaData (column); + + if (data != null) { + // data found + // set data offset based on the presence of a null indicator + if (!nullable_[index]) + dataOffset = 0; + else + dataOffset = 1; + + blob = new Blob ( data, agent, dataOffset); + } + else { + blob = new Blob (new byte[0], agent, 0); + } + + return blob; + } + + + public Clob getClobColumn_ (int column, Agent agent) throws SqlException + { + int index = column - 1; + int dataOffset; + byte[] data; + Clob clob = null; + + // locate the EXTDTA bytes, if any + data = findExtdtaData (column); + + if (data != null) { + // data found + // set data offset based on the presence of a null indicator + if (! nullable_[index]) + dataOffset = 0; + else + dataOffset = 1; + clob = new Clob (agent, data, charsetName_[index], dataOffset); + } + else { + // the locator is not valid, it is a zero-length LOB + clob = new Clob (agent, ""); + } + + return clob; + } + + public byte[] getClobBytes_ (int column, int[] dataOffset /*output*/) throws SqlException + { + int index = column - 1; + byte[] data = null; + + // locate the EXTDTA bytes, if any + data = findExtdtaData (column); + + if (data != null) { + // data found + // set data offset based on the presence of a null indicator + if (! nullable_[index]) + dataOffset[0] = 0; + else + dataOffset[0] = 1; + } + + return data; + } + + // this is really an event-callback from NetStatementReply.parseSQLDTARDarray() + void initializeColumnInfoArrays (Typdef typdef, + int columnCount, int targetSqlamForTypdef) throws DisconnectException + { + qrydscTypdef_ = typdef; + + // Allocate arrays to hold the descriptor information. + setNumberOfColumns (columnCount); + fdocaLength_ = new int[columnCount]; + isGraphic_ = new boolean[columnCount]; + typeToUseForComputingDataLength_ = new int[columnCount]; + targetSqlamForTypdef_ = targetSqlamForTypdef; + } + + + int ensureSpaceForDataBuffer (int ddmLength) + { + if (dataBuffer_ == null) { + allocateDataBuffer(); + } + //super.resultSet.cursor.clearColumnDataOffsetsCache(); + // Need to know how many bytes to ask from the Reply object, + // and handle the case where buffer is not big enough for all the bytes. + // Get the length in front of the code point first. + + int bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_; + + // Make sure the buffer has at least ddmLength amount of room left. + // If not, expand the buffer before calling the getQrydtaData() method. + if (bytesAvailableInDataBuffer < ddmLength) { + + // Get a new buffer that is twice the size of the current buffer. + // Copy the contents from the old buffer to the new buffer. + int newBufferSize = 2 * dataBuffer_.length; + + while (newBufferSize < ddmLength) { + newBufferSize = 2 * newBufferSize; + } + + byte[] tempBuffer = new byte[newBufferSize]; + + System.arraycopy (dataBuffer_, + 0, + tempBuffer, + 0, + lastValidBytePosition_); + + // Make the new buffer the dataBuffer. + dataBuffer_ = tempBuffer; + + // Recalculate bytesAvailableInDataBuffer + bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_; + } + return bytesAvailableInDataBuffer; + } + + protected void getMoreData_ () throws SqlException + { + // reset the dataBuffer_ before getting more data if cursor is foward-only. + // getMoreData() is only called in Cursor.next() when current position is + // equal to lastValidBytePosition_. + if (netResultSet_.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) + resetDataBuffer(); + netResultSet_.flowFetch (); + } + + public void nullDataForGC () // memory leak fix + { + super.nullDataForGC(); + qrydscTypdef_ = null; + typeToUseForComputingDataLength_ = null; + isGraphic_ = null; + + if (extdtaPositions_ != null) extdtaPositions_.clear(); + extdtaPositions_ = null; + + if (extdtaData_ != null) extdtaData_.clear(); + extdtaData_ = null; + } + + // It is possible for the driver to have received an QRYDTA(with incomplete row)+ENDQRYRM+SQLCARD. + // This means some error has occurred on the server and the server is terminating the query. + // Before sending a CNTQRY to retrieve the rest of the split row, check if an ENDQRYRM has already + // been received. If so, do not send CNTQRY because the cursor is already closed on the server. + // Instead, throw a SqlException. Since we did not receive a complete row, it is not safe to + // allow the application to continue to access the ResultSet, so we close it. + private void checkAndThrowReceivedEndqryrm () throws SqlException + { + // If we are in a split row, and before sending CNTQRY, check whether an ENDQRYRM + // has been received. + if (!netResultSet_.openOnServer_) { + SqlException sqlException = null; + int sqlcode = org.apache.derby.client.am.Utils.getSqlcodeFromSqlca (netResultSet_.queryTerminatingSqlca_); + if (sqlcode < 0) + sqlException = new SqlException (agent_.logWriter_, netResultSet_.queryTerminatingSqlca_); + else + sqlException = new SqlException (agent_.logWriter_, "Query processing has been terminated due to error on the server."); + try { + netResultSet_.closeX(); // the auto commit logic is in closeX() + } + catch (SqlException e) { + sqlException.setNextException (e); + } + throw sqlException; + } + } + + private void checkAndThrowReceivedEndqryrm (int lastValidBytePositionBeforeFetch) throws SqlException + { + // if we have received more data in the dataBuffer_, just return. + if (lastValidBytePosition_ > lastValidBytePositionBeforeFetch) + return; + checkAndThrowReceivedEndqryrm (); + } + + private int completeSplitRow () throws DisconnectException, SqlException + { + int lastValidBytePositionBeforeFetch = 0; + if (netResultSet_ != null && netResultSet_.scrollable_) { + lastValidBytePositionBeforeFetch = lastValidBytePosition_; + netResultSet_.flowFetchToCompleteRowset (); + } + else { + // Shift partial row to the beginning of the dataBuffer + shiftPartialRowToBeginning (); + resetCurrentRowPosition (); + lastValidBytePositionBeforeFetch = lastValidBytePosition_; + netResultSet_.flowFetch (); + } + return lastValidBytePositionBeforeFetch; + } + + private int completeSplitRow (int index) throws DisconnectException, SqlException + { + int lastValidBytePositionBeforeFetch = 0; + if (netResultSet_ != null && netResultSet_.scrollable_) { + lastValidBytePositionBeforeFetch = lastValidBytePosition_; + netResultSet_.flowFetchToCompleteRowset (); + } + else { + // Shift partial row to the beginning of the dataBuffer + shiftPartialRowToBeginning (); + adjustColumnOffsetsForColumnsPreviouslyCalculated (index); + resetCurrentRowPosition (); + lastValidBytePositionBeforeFetch = lastValidBytePosition_; + netResultSet_.flowFetch (); + } + return lastValidBytePositionBeforeFetch; + } + + private int[] allocateColumnDataPositionArray (int row) + { + int[] columnDataPosition; + if (columnDataPositionCache_.size() == row) { + columnDataPosition = new int[columns_]; + columnDataPositionCache_.add (columnDataPosition); + } + else + columnDataPosition = (int[])columnDataPositionCache_.get(row); + return columnDataPosition; + } + + private int[] allocateColumnDataComputedLengthArray (int row) + { + int[] columnDataComputedLength; + if (columnDataLengthCache_.size() == row) { + columnDataComputedLength = new int[columns_]; + columnDataLengthCache_.add (columnDataComputedLength); + } + else + columnDataComputedLength = (int[])columnDataLengthCache_.get(row); + return columnDataComputedLength; + } + + private boolean[] allocateColumnDataIsNullArray (int row) + { + boolean[] columnDataIsNull; + if (columnDataIsNullCache_.size() <= row) { + columnDataIsNull = new boolean[columns_]; + columnDataIsNullCache_.add(columnDataIsNull); + } + else + columnDataIsNull = (boolean[])columnDataIsNullCache_.get(row); + return columnDataIsNull; + } + + protected int getDecimalLength (int index) + { + return (((fdocaLength_[index] >> 8) & 0xff) + 2) / 2; + } + +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,80 @@ +/* + + Derby - Class org.apache.derby.client.net.NetDatabaseMetaData + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package org.apache.derby.client.net; + +import org.apache.derby.client.am.Configuration; +import org.apache.derby.client.am.ProductLevel; +import org.apache.derby.client.am.SqlException; + + +public class NetDatabaseMetaData extends org.apache.derby.client.am.DatabaseMetaData +{ + + private final NetAgent netAgent_; + + + public NetDatabaseMetaData (NetAgent netAgent, NetConnection netConnection) + { + // Consider setting product level during parse + super (netAgent, netConnection, new ProductLevel (netConnection.productID_, + netConnection.targetSrvclsnm_, + netConnection.targetSrvrlslv_)); + // Set up cheat-links + netAgent_ = netAgent; + } + + //---------------------------call-down methods-------------------------------- + + public String getURL_ () throws SqlException + { + String urlProtocol; + + urlProtocol = Configuration.jdbcDerbyNETProtocol; + + return + urlProtocol + + connection_.serverNameIP_+ + ":" + + connection_.portNumber_ + + "/" + + connection_.databaseName_; + } + + //-----------------------------helper methods--------------------------------- + + // Set flags describing the level of support for this connection. + // Flags will be set based on manager level and/or specific product identifiers. + // Support for a specific server version can be set as follows. For example + // if (productLevel_.greaterThanOrEqualTo(11,1,0)) + // supportsTheBestThingEver = true + protected void computeFeatureSet_ () + { + if (connection_.resultSetHoldability_ == 0) // property not set + setDefaultResultSetHoldability (); + + } + + + public void setDefaultResultSetHoldability () + { + connection_.resultSetHoldability_ = org.apache.derby.jdbc.ClientDataSource.HOLD_CURSORS_OVER_COMMIT; + } + +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetIndoubtTransaction.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetIndoubtTransaction.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetIndoubtTransaction.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetIndoubtTransaction.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,84 @@ +/* + + Derby - Class org.apache.derby.client.net.NetXACallInfo + + Copyright (c) 2002, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package org.apache.derby.client.net; + +import javax.transaction.xa.*; + +/** + * <p>Title: dnc Project</p> + * <p>Description: </p> + * @version 1.0 + */ + +public class NetIndoubtTransaction +{ + + Xid xid_; + byte[] uowid_; + byte[] cSyncLog_; + byte[] pSyncLog_; + String ipaddr_; + int port_; + + protected NetIndoubtTransaction(Xid xid, + byte[] uowid, + byte[] cSyncLog, + byte[] pSyncLog, + String ipaddr, + int port) + { + xid_ = xid; + uowid_ = uowid; + cSyncLog_ = cSyncLog; + pSyncLog_ = pSyncLog; + ipaddr_ = ipaddr; + port_ = port; + } + + protected Xid getXid() + { + return xid_; + } + + protected byte[] getUOWID() + { + return uowid_; + } + + protected byte[] getCSyncLog() + { + return cSyncLog_; + } + + protected byte[] getPSyncLog() + { + return pSyncLog_; + } + + protected String getIpAddr() + { + return ipaddr_; + } + + protected int getPort() + { + return port_; + } +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetIndoubtTransaction.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetLogWriter.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetLogWriter.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetLogWriter.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetLogWriter.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,416 @@ +/* + + Derby - Class org.apache.derby.client.net.NetLogWriter + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.net; + +// network traffic tracer. +// This class traces communication buffers for both sends and receives. +// The value of the hex bytes are traced along with the ascii and ebcdic translations. +public class NetLogWriter extends org.apache.derby.client.am.LogWriter +{ + + // The recevie constant is used to indicate that the bytes were read to a Stream. + // It indicates to this class that a receive header should be used. + public static final int TYPE_TRACE_RECEIVE = 2; + + // The send constant is used to indicate that the bytes were written to + // a Stream. It indicates to this class that a send header should be used. + public static final int TYPE_TRACE_SEND = 1; + + //------------------------------ internal constants -------------------------- + + // This class was implemented using character arrays to translate bytes + // into ascii and ebcdic. The goal was to be able to quickly index into the + // arrays to find the characters. Char arrays instead of strings were used as + // much as possible in an attempt to help speed up performance. + + // An array of characters used to translate bytes to ascii. + // The position in the array corresponds to the hex value of the character. + private static final char asciiChar__ [] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //0 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //1 + ' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/', //2 + '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?', //3 + '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O', //4 + 'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_', //5 + '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', //6 + 'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','.', //7 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //8 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //9 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //A + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //B + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //C + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //D + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //E + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.' //F + }; + + // This column position header is used to mark offsets into the trace. + private static final String colPosHeader__ = + " 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0123456789ABCDEF"; + + // An array of characters used to translate bytes to ebcdic. + // The position in the array corresponds to the hex value of the + // character. + private static final char ebcdicChar__[] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //0 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //1 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //2 + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //3 + ' ','.','.','.','.','.','.','.','.','.','.','.','<','(','+','|', //4 + '&','.','.','.','.','.','.','.','.','.','!','$','*',')',';','.', //5 + '-','/','.','.','.','.','.','.','.','.','|',',','%','_','>','?', //6 + '.','.','.','.','.','.','.','.','.','`',':','#','@','\'','=','"', //7 + '.','a','b','c','d','e','f','g','h','i','.','.','.','.','.','.', //8 + '.','j','k','l','m','n','o','p','q','r','.','.','.','.','.','.', //9 + '.','~','s','t','u','v','w','x','y','z','.','.','.','.','.','.', //A + '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.', //B + '{','A','B','C','D','E','F','G','H','I','.','.','.','.','.','.', //C + '}','J','K','L','M','N','O','P','Q','R','.','.','.','.','.','.', //D + '\\','.','S','T','U','V','W','X','Y','Z','.','.','.','.','.','.', //E + '0','1','2','3','4','5','6','7','8','9','.','.','.','.','.','.' //F + }; + + // An array of characters representing hex numbers. + private static final char hexDigit__ [] = { + '0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F' + }; + + // The receive header comes befor bytes which would be read from a stream. + private static final String receiveHeader__ = + " RECEIVE BUFFER: (ASCII) (EBCDIC)"; + + // The send header comes before bytes which would be written to a stream. + private static final String sendHeader__ = + " SEND BUFFER: (ASCII) (EBCDIC)"; + + private static final char spaceChar__ = ' '; + + private static final char zeroChar__ = '0'; + + // This mapping table associates a codepoint to a String describing the codepoint. + // This is needed because the trace prints the first codepoint in send and receive buffers. + // This is created lazily because there is no need to create the mapping if tracing isn't used. + // So this array will only be created when the com buffer trace is started. + private static CodePointNameTable codePointNameTable__ = null; + + //-----------------------------internal state--------------------------------- + + //-----------------------------constructors/finalizer------------------------- + + // One NetLogWriter object is created per data source, iff tracing is enabled. + public NetLogWriter (java.io.PrintWriter printWriter, int traceLevel) + { + super (printWriter, traceLevel); + + // Initialize the codepoint name table if not previously initialized. + // This is done lazily so that it is not created if the trace isn't used (save some init time). + if (codePointNameTable__ == null) { + codePointNameTable__ = new CodePointNameTable(); + } + } + + //------------------------------entry points---------------------------------- + + // Specialization of LogWriter.traceConnectsExit() + public void traceConnectsExit (org.apache.derby.client.am.Connection connection) + { + if (traceSuspended()) return; + NetConnection c = (NetConnection) connection; + synchronized (printWriter_) { + super.traceConnectsExit (c); + dncnetprint (" PROTOCOL manager levels: { "); + printWriter_.print ("SQLAM=" + c.getSQLAM() + ", "); + printWriter_.print ("AGENT=" + c.getAGENT() + ", "); + printWriter_.print ("CMNTCPIP=" + c.getCMNTCPIP() + ", "); + printWriter_.print ("RDB=" + c.getRDB() + ", "); + printWriter_.print ("SECMGR=" + c.getSECMGR() + ", "); + printWriter_.print ("XAMGR=" + c.getXAMGR() + ", "); + printWriter_.print ("SYNCPTMGR=" + c.getSYNCPTMGR() + ", "); + printWriter_.print ("RSYNCMGR=" + c.getRSYNCMGR()); + printWriter_.println (" }"); + printWriter_.flush(); + } + } + + public void traceConnectsResetExit (org.apache.derby.client.am.Connection connection) + { + if (traceSuspended()) return; + NetConnection c = (NetConnection) connection; + synchronized (printWriter_) { + super.traceConnectsResetExit (c); + dncnetprint (" PROTOCOL manager levels: { "); + printWriter_.print ("SQLAM=" + c.getSQLAM() + ", "); + printWriter_.print ("AGENT=" + c.getAGENT() + ", "); + printWriter_.print ("CMNTCPIP=" + c.getCMNTCPIP() + ", "); + printWriter_.print ("RDB=" + c.getRDB() + ", "); + printWriter_.print ("SECMGR=" + c.getSECMGR() + ", "); + printWriter_.print ("XAMGR=" + c.getXAMGR() + ", "); + printWriter_.print ("SYNCPTMGR=" + c.getSYNCPTMGR() + ", "); + printWriter_.print ("RSYNCMGR=" + c.getRSYNCMGR()); + printWriter_.println (" }"); + printWriter_.flush(); + } + } + + // Pass the connection handle and print it in the header + // What exactly is supposed to be passed, assume one complete DSS packet + // Write the communication buffer data to the trace. + // The data is passed in via a byte array. The start and length of the data is given. + // The type is needed to indicate if the data is part of the send or receive buffer. + // The class name, method name, and trcPt number are also written to the trace. + // Not much checking is performed on the parameters. This is done to help performance. + synchronized public void traceProtocolFlow (byte[] buff, + int offset, + int len, + int type, + String className, + String methodName, + int tracepoint) + { + if (traceSuspended()) return; + if (!loggingEnabled (org.apache.derby.jdbc.ClientDataSource.TRACE_PROTOCOL_FLOWS)) return; + synchronized (printWriter_) { + super.tracepoint ("[net]", tracepoint, className, methodName); + + int fullLen = len; + boolean printColPos = true; + while( fullLen >= 2 ) + { // format each DssHdr seperately + // get the length of this DssHdr + len = ((buff[offset] & 0xff) << 8) + ((buff[offset+1] & 0xff) << 0); + + // check for valid dss header or not all of dss block + if ((len < 10) || (len > fullLen)) + len = fullLen; + + // subtract that length from the full length + fullLen -= len; + // The data will only be written if there is a non-zero positive length. + if (len != 0) { + String codePointName = null; + // If the length <= 10, lookup the first codepoint so it's name can be printed + if (len >= 10) { + // Get the int value of the two byte unsigned codepoint. + int codePoint = getCodePoint (buff, offset+8); + codePointName = codePointNameTable__.lookup (codePoint); + + // if this is not a valid codepoint then format the entire buffer + // as one block. + if (codePointName == null) + { + len += fullLen; + fullLen = 0; + } + } + + if( !printColPos ) + { // not 1st Dss header of this buffer, write seperator + dncnetprintln( "" ); + } + + if (codePointName == null) { + // codePointName was still null so either < 10 bytes were given or + // the codepoint wasn't found in the table. Just print the plain send header. + dncnetprintln (getHeader (type)); + } + else { + // codePointName isn't null so the name of the codepoint will be printed. + printHeaderWithCodePointName (codePointName, type); + } + + // Print the col position header in the trace. + if( printColPos ) + { // first Dss header of buffer, need column position header + dncnetprintln (colPosHeader__); + printColPos = false; + } + + // A char array will be used to translate the bytes to their character + // representations along with ascii and ebcdic representations. + char trcDump[] = new char[77]; + + // bCounter, aCounter, eCounter are offsets used to help position the characters + short bCounter = 7; + short aCounter = 43; + short eCounter = 61; + + // The lines will be counted starting at zero. + // This is hard coded since we are at the beginning. + trcDump[0] = zeroChar__; + trcDump[1] = zeroChar__; + trcDump[2] = zeroChar__; + trcDump[3] = zeroChar__; + + // The 0's are already in the trace so bump the line counter up a row. + int lineCounter = 0x10; + + // Make sure the character array has all blanks in it. + // Some of these blanks will be replaced later with values. + // The 0's were not wrote over. + for (int j = 4; j < 77; j++) { + trcDump[j] = spaceChar__; + } + + // i will maintain the position in the byte array to be traced. + int i = 0; + + do { + // Get the unsigned value of the byte. + // int num = b[off++] & 0xff; + int num = (buff[offset] < 0)? buff[offset] + 256 : buff[offset]; + offset++; + i++; + // Place the characters representing the bytes in the array. + trcDump[bCounter++] = hexDigit__[((num >>> 4) & 0xf)]; + trcDump[bCounter++] = hexDigit__[(num & 0xf)]; + + // Place the ascii and ebcdc representations in the array. + trcDump[aCounter++] = asciiChar__[num]; + trcDump[eCounter++] = ebcdicChar__[num]; + + if (((i%8) == 0)) { + if (((i%16) == 0)) { + // Print the array each time 16 bytes are processed. + dncnetprintln (trcDump); + if (i != len) { + // Not yet at the end of the byte array. + if ((len - i) < 16) { + // This is the last line so blank it all out. + // This keeps the last line looking pretty in case + // < 16 bytes remain. + for (int j = 0; j < trcDump.length; j++) { + trcDump[j] = spaceChar__; + } + } + // Reset the counters. + bCounter = 0; + aCounter = 43; + eCounter = 61; + // Reset the lineCounter if it starts to get too large. + if (lineCounter == 0x100000) { + lineCounter = 0; + } + // Place the characters representing the line counter in the array. + trcDump[bCounter++] = hexDigit__[((lineCounter >>> 12) & 0xf)]; + trcDump[bCounter++] = hexDigit__[((lineCounter >>> 8) & 0xf)]; + trcDump[bCounter++] = hexDigit__[((lineCounter >>> 4) & 0xf)]; + trcDump[bCounter++] = hexDigit__[(lineCounter & 0xf)]; + bCounter += 3; + // Bump up the line counter. + lineCounter += 0x10; + } + } + else { + // 8 bytes were processed so move the counter to adjust for + // spaces between the columns of bytes. + bCounter += 2; + } + } + // do this until we all the data has been traced. + } + while (i < len); + + // print the last line and add some blank lines to make it easier to read. + if (len % 16 != 0) { + dncnetprintln (trcDump); + } + } + } + dncnetprintln (""); + } + } + + // Gets the int value of the two byte unsigned codepoint. + private static int getCodePoint (byte[] buff, int offset) + { + return ((buff[offset++] & 0xff) << 8) + + ((buff[offset] & 0xff) << 0); + } + + private static String getHeader (int type) + { + switch (type) { + case TYPE_TRACE_SEND: + return sendHeader__; + case TYPE_TRACE_RECEIVE: + return receiveHeader__; + default: + return null; + } + } + + private static int getStartPosition (int type) + { + switch (type) { + case TYPE_TRACE_SEND: + return 20; // This is right after 'SEND BUFFER: '. + case TYPE_TRACE_RECEIVE: + return 23; // This is right after 'RECEIVE BUFFER: '. + default: + return 0; + } + } + + private void printHeaderWithCodePointName (String codePointName, int type) + { + // Create a char array so some of the characters + // can be replaced with the name of the codepoint. + char headerArray[] = getHeader(type).toCharArray(); + + // At most, 16 character name will be used. This is so + // the headers on top of the ascii and ebcdic rows aren't shifted. + int replaceLen = (codePointName.length() < 17) ? codePointName.length() : 16; + + int offset = getStartPosition (type); + for (int i = 0; i < replaceLen; i++) { + headerArray[offset++] = codePointName.charAt (i); + } + dncnetprintln (headerArray); + } + + private void dncnetprint (String s) + { + synchronized (printWriter_) { + printWriter_.print ("[derby] " + s); + printWriter_.flush(); + } + } + + private void dncnetprintln (String s) + { + synchronized (printWriter_) { + printWriter_.println ("[derby] " + s); + printWriter_.flush(); + } + } + + private void dncnetprintln (char[] s) + { + synchronized (printWriter_) { + printWriter_.print ("[derby] "); + printWriter_.println (s); + printWriter_.flush(); + } + } +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetLogWriter.java ------------------------------------------------------------------------------ svn:eol-style = native