コード例 #1
0
bool
gcd_put_i8( GCD_RCB **rcb_ptr, u_i8 val )
{
    return( gcd_put_i8p( rcb_ptr, (u_i1 *)&val ) );
}
コード例 #2
0
static void
crsr_cols
( 
    GCD_CCB	*ccb, 
    GCD_SCB	*scb, 
    GCD_RCB	**rcb_ptr, 
    u_i2	row,
    bool	more_segments 
)
{
    IIAPI_DESCRIPTOR	*desc = (IIAPI_DESCRIPTOR *)scb->column.desc;
    IIAPI_DATAVALUE	*data = &((IIAPI_DATAVALUE *)scb->column.data)[ 
						row * scb->column.max_cols ];
    u_i2		end = scb->column.cur_col + scb->column.col_cnt;
    u_i2		col, len;

    for( col = scb->column.cur_col; col < end; col++ )
    {
	if ( desc[ col ].ds_nullable  &&  data[ col ].dv_null )
	{
	    gcd_put_i1( rcb_ptr, 0 );	/* No data - NULL value */
	    continue;
	}

	/*
	** Write the data indicator byte, for BLOBs this is
	** only done on the first segment (more_segments is
	** saved below once the segment has been processed,
	** so the saved value is FALSE on the first segment).
	*/
	if ( (desc[ col ].ds_dataType != IIAPI_LVCH_TYPE  &&
	      desc[ col ].ds_dataType != IIAPI_LNVCH_TYPE &&
	      desc[ col ].ds_dataType != IIAPI_LBYTE_TYPE)  ||
	     ! scb->column.more_segments )
	    gcd_put_i1( rcb_ptr, 1 );

	switch( desc[ col ].ds_dataType )
	{
	case IIAPI_INT_TYPE :
	    switch( desc[ col ].ds_length )
	    {
	    case 1 : gcd_put_i1p(rcb_ptr, (u_i1 *)data[col].dv_value); break;
	    case 2 : gcd_put_i2p(rcb_ptr, (u_i1 *)data[col].dv_value); break;
	    case 4 : gcd_put_i4p(rcb_ptr, (u_i1 *)data[col].dv_value); break;
	    case 8 : gcd_put_i8p(rcb_ptr, (u_i1 *)data[col].dv_value); break;
	    }
	    break;

	case IIAPI_FLT_TYPE :
	    switch( desc[ col ].ds_length )
	    {
	    case 4 : gcd_put_f4p(rcb_ptr, (u_i1 *)data[col].dv_value); break;
	    case 8 : gcd_put_f8p(rcb_ptr, (u_i1 *)data[col].dv_value); break;
	    }
	    break;

	case IIAPI_MNY_TYPE :
	    {
		IIAPI_DESCRIPTOR	idesc, ddesc;
		IIAPI_DATAVALUE		idata, ddata;
		STATUS			status;
		char			dbuff[ 130 ];	/* varchar(128) */
		char			dec[ 8 ];

		/*
		** It would be nice to convert directly to
		** varchar, but money formatting is nasty.  
		** So we first convert to decimal, then to 
		** varchar.
		*/
		idesc.ds_dataType = IIAPI_DEC_TYPE;
		idesc.ds_nullable = FALSE;
		idesc.ds_length = sizeof( dec );
		idesc.ds_precision = 15;
		idesc.ds_scale = 2;
		idata.dv_null = FALSE;
		idata.dv_length = sizeof( dec );
		idata.dv_value = (PTR)&dec;

		ddesc.ds_dataType = IIAPI_VCH_TYPE;
		ddesc.ds_nullable = FALSE;
		ddesc.ds_length = sizeof( dbuff );
		ddesc.ds_precision = 0;
		ddesc.ds_scale = 0;
		ddata.dv_null = FALSE;
		ddata.dv_length = sizeof( dbuff );
		ddata.dv_value = dbuff;

		if ( (status = gcd_api_format( ccb, &desc[ col ], &data[ col ],
						&idesc, &idata )) != OK  ||
		     (status = gcd_api_format( ccb, &idesc, &idata, 
						&ddesc, &ddata )) != OK )
		{
		    /*
		    ** Conversion error.  Send a zero-length 
		    ** string as error indication and log error.
		    */
		    gcd_put_i2( rcb_ptr, 0 );
		    gcu_erlog( 0, GCD_global.language, status, NULL, 0, NULL );
		}
		else
		{
		    MEcopy( (PTR)dbuff, 2, (PTR)&len );
		    gcd_put_i2( rcb_ptr, len );
		    gcd_put_bytes( rcb_ptr, len, (u_i1 *)&dbuff[2] );
		}
	    }
	    break;

	case IIAPI_BOOL_TYPE :
	    gcd_put_i1p( rcb_ptr, (u_i1 *)data[ col ].dv_value );
	    break;

	case IIAPI_DEC_TYPE :	/* These types are all sent in text format */
	case IIAPI_DTE_TYPE :
	case IIAPI_DATE_TYPE :
	case IIAPI_TIME_TYPE :
	case IIAPI_TMWO_TYPE :
	case IIAPI_TMTZ_TYPE :
	case IIAPI_TS_TYPE :
	case IIAPI_TSWO_TYPE :
	case IIAPI_TSTZ_TYPE :
	case IIAPI_INTYM_TYPE :
	case IIAPI_INTDS_TYPE :
	    {
		IIAPI_DESCRIPTOR	ddesc;
		IIAPI_DATAVALUE		ddata;
		STATUS			status;
		char			dbuff[ 130 ];	/* varchar(128) */

		ddesc.ds_dataType = IIAPI_VCH_TYPE;
		ddesc.ds_nullable = FALSE;
		ddesc.ds_length = sizeof( dbuff );
		ddesc.ds_precision = 0;
		ddesc.ds_scale = 0;
		ddata.dv_null = FALSE;
		ddata.dv_length = sizeof( dbuff );
		ddata.dv_value = dbuff;

		status = gcd_api_format( ccb, &desc[ col ], &data[ col ], 
					  &ddesc, &ddata );

		if ( status != OK )  
		{
		    /*
		    ** Conversion error.  Send a zero-length 
		    ** string as error indication and log error.
		    */
		    gcd_put_i2( rcb_ptr, 0 );
		    gcu_erlog( 0, GCD_global.language, status, NULL, 0, NULL );
		}
		else
		{
		    MEcopy( (PTR)dbuff, 2, (PTR)&len );
		    gcd_put_i2( rcb_ptr, len );
		    gcd_put_bytes( rcb_ptr, len, (u_i1 *)&dbuff[2] );
		}
	    }
	    break;

	case IIAPI_CHA_TYPE :
	case IIAPI_CHR_TYPE :
	case IIAPI_BYTE_TYPE :
	    gcd_put_bytes( rcb_ptr, desc[ col ].ds_length, 
			    (u_i1 *)data[ col ].dv_value );
	    break;

	case IIAPI_NCHA_TYPE :
	    gcd_put_ucs2( rcb_ptr, desc[ col ].ds_length / sizeof( UCS2 ),
			   (u_i1 *)data[ col ].dv_value );
	    break;

	case IIAPI_TXT_TYPE :
	case IIAPI_LTXT_TYPE :
	case IIAPI_VCH_TYPE :	
	case IIAPI_VBYTE_TYPE :
	    MEcopy( data[ col ].dv_value, 2, (PTR)&len );
	    gcd_put_i2( rcb_ptr, len );
	    gcd_put_bytes( rcb_ptr, len, (u_i1 *)data[ col ].dv_value + 2 );
	    break;

	case IIAPI_NVCH_TYPE :
	    MEcopy( data[ col ].dv_value, 2, (PTR)&len );
	    gcd_put_i2( rcb_ptr, len );
	    gcd_put_ucs2( rcb_ptr, len, (u_i1 *)data[ col ].dv_value + 2 );
	    break;

	case IIAPI_LCLOC_TYPE :
	case IIAPI_LNLOC_TYPE :
	case IIAPI_LBLOC_TYPE :
	    gcd_put_i4p( rcb_ptr, (u_i1 *)data[ col ].dv_value );
	    break;

	case IIAPI_LVCH_TYPE :
	case IIAPI_LNVCH_TYPE :
	case IIAPI_LBYTE_TYPE :
	    {
		u_i1	*ptr;
		u_i2	seg_len, chrs, char_size = sizeof( char );
		bool	ucs2 = FALSE;

		if ( desc[ col ].ds_dataType == IIAPI_LNVCH_TYPE )
		{
		    ucs2 = TRUE;
		    char_size = sizeof( UCS2 );
		}

		if ( data[ col ].dv_length < 2 )
		    seg_len = 0;
		else
		{
		    MEcopy( data[ col ].dv_value, 2, (PTR)&seg_len );
		    ptr = (u_i1 *)data[ col ].dv_value + 2;
		    seg_len *= char_size;  /* convert array len to byte len */
		}

		/*
		** Output data as long as there is sufficient
		** data to fill the current message.  Any data
		** remaining is saved until additional data is
		** received or the end of the BLOB is reached.
		**
		** We actually make sure that room for the
		** segment (length indicator and data) and an
		** end-of-segments indicator is left in the
		** message buffer.  This way the end-of-BLOB
		** processing below does not need to worry
		** about splitting the message.
		**
		** The test against the save buffer size is
		** redundent since the buffer should be at 
		** least as big as a message buffer, but we 
		** make the test just to be safe.
		*/
		while( (seg_len + scb->seg_len + 4) > RCB_AVAIL(*rcb_ptr)  ||
		       (seg_len + scb->seg_len) > scb->seg_max )
		{
		    /*
		    ** Can a valid data segment be placed in the buffer?
		    */
		    if ( RCB_AVAIL(*rcb_ptr) >= (2 + char_size)  &&  
			 (seg_len + scb->seg_len) >= char_size )
		    {
			len = min( seg_len + scb->seg_len, 
				   RCB_AVAIL( *rcb_ptr ) - 2 );
			chrs = len / char_size;
			len = chrs * char_size;

			gcd_put_i2( rcb_ptr, chrs );

			if ( GCD_global.gcd_trace_level >= 5 )
			    TRdisplay( "%4d    GCD send segment: %d (%d,%d)\n",
					ccb->id, len, scb->seg_len, seg_len );

			/*
			** First, send saved data.
			*/
			if ( scb->seg_len >= char_size )
			{
			    len = min( scb->seg_len, RCB_AVAIL( *rcb_ptr ) );
			    chrs = len / char_size;
			    len = chrs * char_size;

			    if ( ! ucs2 )
				gcd_put_bytes( rcb_ptr, len, scb->seg_buff );
			    else
				gcd_put_ucs2( rcb_ptr, chrs, scb->seg_buff );

			    scb->seg_len -= len;
			    if ( scb->seg_len ) 
				MEcopy( (PTR)(scb->seg_buff + len), 
					scb->seg_len, (PTR)scb->seg_buff );
			}

			/*
			** Now send data from current segment.
			*/
			if ( seg_len >= char_size  &&  
			     RCB_AVAIL( *rcb_ptr ) >= char_size )
			{
			    len = min( seg_len, RCB_AVAIL( *rcb_ptr ) );
			    chrs = len / char_size;
			    len = chrs * char_size;

			    if ( ! ucs2 )
				gcd_put_bytes( rcb_ptr, len, ptr );
			    else
				gcd_put_ucs2( rcb_ptr, chrs, ptr );

			    ptr += len;
			    seg_len -= len;
			}
		    }

		    gcd_msg_end( rcb_ptr, FALSE );
		    gcd_msg_begin( ccb, rcb_ptr, MSG_DATA, 0 );
		}

		/*
		** Save any data left in the current segment.
		** The preceding loop makes sure there is room
		** in the buffer for the remainder of the
		** current segment.
		*/
		if ( seg_len )
		{
		    if ( ! scb->seg_buff )
		    {
			scb->seg_buff = (u_i1 *)MEreqmem( 0, scb->seg_max,
							  FALSE, NULL );
			if ( ! scb->seg_buff )
			{
			    if ( GCD_global.gcd_trace_level >= 1 )
				TRdisplay( "%4d    GCD alloc fail seg: %d\n",
					   ccb->id, scb->seg_max );
			    gcu_erlog( 0, GCD_global.language, 
				       E_GC4808_NO_MEMORY, NULL, 0, NULL );
			    gcd_sess_abort( ccb, E_GC4808_NO_MEMORY );
			    return;
			}
		    }

		    if ( GCD_global.gcd_trace_level >= 5 )
			TRdisplay( "%4d    GCD save segment: %d (total %d) \n",
				    ccb->id, seg_len, scb->seg_len + seg_len );
		    MEcopy( (PTR)ptr, seg_len, 
			    (PTR)(scb->seg_buff + scb->seg_len) );
		    scb->seg_len += seg_len;
		}

		/*
		** When the BLOB is complete, write the last
		** segment and end-of-segments indicator.
		*/
		if ( ! (scb->column.more_segments = more_segments) )
		{
		    /*
		    ** The processing loop above makes sure there
		    ** is room for the last segment.
		    */
		    if ( scb->seg_len )
		    {
			if ( GCD_global.gcd_trace_level >= 5 )
			    TRdisplay( "%4d    GCD send segment: %d \n",
					ccb->id, scb->seg_len );

			chrs = scb->seg_len / char_size;
			len = chrs * char_size;
			scb->seg_len = 0;

			gcd_put_i2( rcb_ptr, chrs );

			if ( ! ucs2 )
			    gcd_put_bytes( rcb_ptr, len, scb->seg_buff );
			else
			    gcd_put_ucs2( rcb_ptr, chrs, scb->seg_buff );
		    }

		    if ( GCD_global.gcd_trace_level >= 5 )
			TRdisplay( "%4d    GCD send end-of-segments\n",
				    ccb->id );
		    gcd_put_i2( rcb_ptr, 0 );
		}
	    }
	    break;

	default :
	    /* Should not happen since checked in send_desc() */
	    if ( GCD_global.gcd_trace_level >= 1 )
		TRdisplay( "%4d    GCD invalid datatype: %d\n",
				    ccb->id, desc[ col ].ds_dataType );
	    gcd_sess_abort( ccb, E_GC4812_UNSUPP_SQL_TYPE );
	    return;
	}
    }

    return;
}