/* ** Name: streamClosed ** ** Description: ** Stream closure notification method for the IStreamListener ** interface. ** ** Only one active stream is permitted and it resulted in an ** interrupt of column processing an a partial row load. ** Continue processing columns now that the stream has been ** cleared from the data message queue. ** ** Input: ** stream SQL Stream which closed. ** ** Output: ** None. ** ** Returns: ** void. ** ** History: ** 31-Oct-02 (gordy) ** Created. ** 22-Sep-03 (gordy) ** Renamed to implemented SQL stream interface. ** Replaced BLOB indicator with stream reference. */ public void streamClosed( SqlStream stream ) { /* ** The only active stream should be the last column loaded, ** but make sure this is indeed the case before continueing ** with column processing. */ if ( activeStream == null || activeStream != stream ) { if ( trace.enabled( 1 ) ) // Should not happen! trace.write( tr_id + ": invalid BLOB stream closure!" ); return; } if ( trace.enabled( 4 ) ) trace.write( tr_id + ": BLOB stream closed" ); try { /* ** Clear stream state and continue column processing. */ activeStream = null; resume(); /* ** Close the cursor when end-of-data detected. ** If EOD was just received, then there shouldn't ** be an active stream, but correctness dictates ** that we check and wait to close the cursor ** when the fetch has completed. */ if ( (rslt_flags & MSG_RF_EOD) != 0 && activeStream == null ) try { closeCursor(); } catch( SqlEx ) {} } catch( SqlEx ex ) { /* ** The caller of the Stream.Listener interface does ** not care about errors we may hit, so we can only ** trace the exception and close the result-set. ** Errors aren't expected except in catastrophic ** circumstances, so the following should be OK. */ if ( trace.enabled( 1 ) ) { trace.log( tr_id + ": error loading remainder of row" ); ex.trace( trace ); } try { shut(); } catch( SqlEx ) {} } return; }
/* ** Name: addStreamListener ** ** Description: ** Add a IStreamListener. Only a single listener is supported. ** ** Input: ** listener SqlStream listener. ** stream SqlStream associated with source/listener. ** ** Output: ** None. ** ** Returns: ** void. ** ** History: ** 22-Sep-03 (gordy) ** Created. */ public void addStreamListener( SqlStream.IStreamListener listener, SqlStream stream ) { this.listener = listener; this.stream = stream; return; }
/* ** Name: readColumns ** ** Description: ** Read column data from server. Assumes that the column counter, ** column_count, indicates the last column read. Reads the next ** column in the row and continues until message is empty , a BLOB ** column is read or the last column in the row is reached. ** ** Input: ** rsmd Row-set Meta-data ** row Column data array. ** ** Output: ** None. ** ** Returns: ** boolean BLOB column interrupted processing. ** ** History: ** 14-May-99 (gordy) ** Created. ** 29-Sep-99 (gordy) ** Implemented BLOB data support. Changed return type ** to permit BLOB stream to interrupt message processing. ** 12-Nov-99 (gordy) ** Use configured date formatter. ** 23-Nov-99 (gordy) ** Ingres allows for 'empty' dates which format to zero length ** strings. If such a beast is received, create an 'epoch' ** timestamp and generate a data truncation warning. ** 30-May-00 (gordy & rajus01) ** Fixed the behaviour of select date('today') query. ** (Bug #s 101677, 101678). ** 31-Jan-01 (gordy) ** Don't throw protocol exceptions for invalid date formats. ** AdvanRslt now handles these as conversion errors. ** 4-Apr-01 (gordy) ** Can't create a DataTruncation warning for empty dates here ** because row pre-fetching causes warnings for all rows to be ** returned on the first row. Also, a preceding BLOB will ** cause the warning to be generated at some unexpected point. ** 18-Apr-01 (gordy) ** Use readBytes() method which reads length from input message. ** 10-May-01 (gordy) ** The character datatypes (CHAR, VARCHAR, LONGVARCHAR) may now ** be sent as UCS2 character arrays in addition to the existing ** Ingres Character Set strings. The DBMS datatype is used to ** distinguish the transport format. ** 31-Oct-02 (gordy) ** Adapted for generic GCF driver. ** 20-Mar-02 (gordy) ** Added BOOLEAN data type, treated same as BIT. ** 4-Aug-03 (gordy) ** Extracted from readData() to separate row and column processing. ** 22-Sep-03 (gordy) ** Changed to use SQL Data objects to hold column values. ** Extracted column data object allocation to allocateRowBuffer(). ** 6-Jan-04 (thoda04) ** Added BigInt support. ** 16-Jun-06 (gordy) ** ANSI Date/Time data type support. ** 7-Dec-09 (gordy, ported by thoda04) ** Support BOOLEAN columns. */ private bool readColumns( AdvanRSMD rsmd, SqlData[] row ) { /* ** Begin processing columns after last read. ** Processing ends after last column in row ** is read, or if an interrupt is requested. ** Note that the column count (1 based index) ** references the next column to load (0 based ** index). */ for( ; column_count < rsmd.count; column_count++ ) { int col = column_count; /* ** We only require individual column values, with the ** exception of BLOB segments, to not be split across ** messages. If the next column is not available, ** return without interrupt to allow caller to handle ** the partial row. */ if ( ! msg.moreData() ) return( false ); switch( rsmd.desc[ col ].sql_type ) { case ProviderType.DBNull : msg.readSqlData( (SqlNull)row[ col ] ); break; case ProviderType.TinyInt : msg.readSqlData( (SqlTinyInt)row[ col ] ); break; case ProviderType.SmallInt : msg.readSqlData( (SqlSmallInt)row[ col ] ); break; case ProviderType.Integer : msg.readSqlData( (SqlInt)row[ col ] ); break; case ProviderType.BigInt : msg.readSqlData( (SqlBigInt)row[ col ] ); break; case ProviderType.Single : msg.readSqlData( (SqlReal)row[ col ] ); break; case ProviderType.Double : msg.readSqlData( (SqlDouble)row[ col ] ); break; case ProviderType.Decimal : msg.readSqlData( (SqlDecimal)row[ col ] ); // TODO: setWarning( new DataTruncation(col + 1, false, true, -1, 0) ); break; case ProviderType.Boolean: msg.readSqlData((SqlBool)row[col]); break; case ProviderType.Date: msg.readSqlData((SqlDate)row[col]); break; case ProviderType.Time: msg.readSqlData((SqlTime)row[col]); break; case ProviderType.Interval: case ProviderType.IntervalDayToSecond: case ProviderType.IntervalYearToMonth: msg.readSqlData((SqlInterval)row[col]); break; case ProviderType.DateTime: switch (rsmd.desc[col].dbms_type) { case DBMS_TYPE_IDATE: bool isBlankDateNull = (conn != null)?conn.isBlankDateNull : false; msg.readSqlData((IngresDate)row[col], isBlankDateNull); break; default: msg.readSqlData((SqlTimestamp)row[col]); break; } break; case ProviderType.Binary : msg.readSqlData( (SqlByte)row[ col ] ); break; case ProviderType.VarBinary : msg.readSqlData( (SqlVarByte)row[ col ] ); break; case ProviderType.Char : if ( rsmd.desc[ col ].dbms_type != DBMS_TYPE_NCHAR ) msg.readSqlData( (SqlChar)row[ col ] ); else msg.readSqlData( (SqlNChar)row[ col ] ); break; case ProviderType.VarChar : if ( rsmd.desc[ col ].dbms_type != DBMS_TYPE_NVARCHAR ) msg.readSqlData( (SqlVarChar)row[ col ] ); else msg.readSqlData( (SqlNVarChar)row[ col ] ); break; case ProviderType.LongVarBinary : /* ** Initialize BLOB stream. */ msg.readSqlData( (SqlLongByte)row[ col ] ); /* ** NULL BLOBs don't require special handling. ** Non-NULL BLOBs interrupt column processing. */ if ( ! row[ col ].isNull() ) { activeStream = (SqlStream)row[ col ]; // Stream reference column_count++; // Column is done return( true ); // Interrupt. } break; case ProviderType.LongVarChar : /* ** Initialize BLOB stream. */ if ( rsmd.desc[ col ].dbms_type != DBMS_TYPE_LONG_NCHAR ) msg.readSqlData( (SqlLongChar)row[ col ] ); else msg.readSqlData( (SqlLongNChar)row[ col ] ); /* ** NULL BLOBs don't require special handling. ** Non-NULL BLOBs interrupt column processing. */ if ( ! row[ col ].isNull() ) { activeStream = (SqlStream)row[ col ]; // Stream reference column_count++; // Column is done return( true ); // Interrupt. } break; default : if ( trace.enabled( 1 ) ) trace.write( tr_id + ": unexpected SQL type " + rsmd.desc[ col ].sql_type ); throw SqlEx.get( ERR_GC4002_PROTOCOL_ERR ); } } return( false ); }