bool gcd_put_i8( GCD_RCB **rcb_ptr, u_i8 val ) { return( gcd_put_i8p( rcb_ptr, (u_i1 *)&val ) ); }
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; }