Example #1
0
static void
crsr_close_sm( PTR arg )
{
    GCD_PCB	*pcb = (GCD_PCB *)arg;
    GCD_CCB	*ccb = pcb->ccb;
    GCD_SCB	*scb = pcb->scb;

  top:

    if ( GCD_global.gcd_trace_level >= 4 )
	TRdisplay( "%4d    GCD Close: %s\n", 
		    ccb->id, gcu_lookup( closeMap, ccb->sequence ) );

    switch( ccb->sequence++ )
    {
    case CLOSE_CURSOR :
	pcb->scb = NULL;
	gcd_push_callback( pcb, crsr_close_sm );
	gcd_del_stmt( pcb, scb );
	return;

    case CLOSE_XACT : 
	pcb->result.flags |= PCB_RSLT_CLOSED;

	if ( ccb->cib->flags & (GCD_CONN_ABORT | GCD_LOGIC_ERR) )  
	    break;	/* Handled below */

	gcd_push_callback( pcb, crsr_close_sm );

	if ( ccb->cib->flags & GCD_XACT_ABORT )
	    gcd_xact_abort( pcb );
	else
	    gcd_xact_check( pcb, GCD_XQOP_CURSOR_CLOSE );
	return;
    
    case CLOSE_DONE :
	gcd_send_done( ccb, &pcb->rcb, pcb );
	gcd_del_pcb( pcb );

	if ( ccb->cib->flags & GCD_CONN_ABORT )
	    gcd_sess_abort( ccb, FAIL );
	else  if ( ccb->cib->flags & GCD_LOGIC_ERR )
	    gcd_sess_abort( ccb, E_GC4809_INTERNAL_ERROR );
	else
	    gcd_msg_pause( ccb, TRUE );
	return;

    default :
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD invalid close sequence: %d\n", 
			ccb->id, --ccb->sequence );
	gcd_del_pcb( pcb );
	gcd_sess_abort( ccb, E_GC480A_PROTOCOL_ERROR );
	return;
    }

    goto top;
}
Example #2
0
void
gcd_pop_callback( GCD_PCB *pcb )
{
    GCD_PCB_CALLBACK	callback = NULL;

    if ( pcb->callbacks )  callback = pcb->callback[ --pcb->callbacks ];

    if ( callback )
	(*callback)( (PTR)pcb );
    else
	gcd_del_pcb( pcb );
    
    return;
}
Example #3
0
void
gcd_del_ccb( GCD_CCB *ccb )
{
    if ( ccb->use_cnt )  ccb->use_cnt--;

    if ( ccb->use_cnt )
    {
	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD del CCB (use count %d)\n", 
		       ccb->id, ccb->use_cnt );
    }
    else
    {
	GCD_RCB *rcb;
	GCD_SCB *scb;
	QUEUE	 *q;

	QUremove( &ccb->q );
	GCD_global.ccb_active--;
	if ( ccb->qry.crsr_name )  MEfree( (PTR)ccb->qry.crsr_name );
	if ( ccb->qry.schema_name )  MEfree( (PTR)ccb->qry.schema_name );
	if ( ccb->qry.proc_name )  MEfree( (PTR)ccb->qry.proc_name );
	if ( ccb->qry.qtxt_max )  MEfree( (PTR)ccb->qry.qtxt );
	if ( ccb->rqst.rqst_id0 )  MEfree( (PTR)ccb->rqst.rqst_id0 );
	if ( ccb->rqst.rqst_id1 )  MEfree( (PTR)ccb->rqst.rqst_id1 );
	if ( ccb->client_user )  MEfree( (PTR)ccb->client_user );
	if ( ccb->client_host )  MEfree( (PTR)ccb->client_host );
	if ( ccb->client_addr )  MEfree( (PTR)ccb->client_addr );
	gcd_free_qdata( &ccb->qry.svc_parms );
	gcd_free_qdata( &ccb->qry.qry_parms );
	gcd_free_qdata( &ccb->qry.all_parms );

	/*
	** Free control blocks and request queues.
	*/
	if ( ccb->cib )  gcd_del_cib( ccb->cib );

	if ( ccb->xact.savepoints )  gcd_release_sp( ccb, NULL );

	if ( ccb->msg.xoff_pcb )
	    gcd_del_pcb( (GCD_PCB *)ccb->msg.xoff_pcb );

	if ( ccb->gcc.abort_rcb )
	    gcd_del_rcb( (GCD_RCB *)ccb->gcc.abort_rcb );

	while( (scb = (GCD_SCB *)QUremove( ccb->stmt.stmt_q.q_next )) )
	{
	    gcd_free_qdata( &scb->column );
	    MEfree( (PTR)scb );
	}

	while( (rcb = (GCD_RCB *)QUremove( ccb->gcc.send_q.q_next )) )
	    gcd_del_rcb( rcb );

	while( (rcb = (GCD_RCB *)QUremove( ccb->msg.msg_q.q_next )) )
	    gcd_del_rcb( rcb );

	while( (rcb = (GCD_RCB *)QUremove( ccb->msg.info_q.q_next )) )
	    gcd_del_rcb( rcb );

	/* Free RCB must be physically freed */
	while( (rcb = (GCD_RCB *)QUremove( ccb->rcb_q.q_next )) )
	    gcd_free_rcb( rcb );

	while( (q = QUremove( ccb->rqst.rqst_q.q_next )) )
	    MEfree( (PTR)q );

	/*
	** Save CCB on free queue.
	*/
	QUinsert( &ccb->q, GCD_global.ccb_free.q_prev );

	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD del CCB (%d)\n", ccb->id, ccb->id );
    }

    return;
}
Example #4
0
static void
crsr_fetch_sm( PTR arg )
{
    GCD_PCB	*pcb = (GCD_PCB *)arg;
    GCD_CCB	*ccb = pcb->ccb;
    GCD_SCB	*scb = pcb->scb;

  top:

    if ( GCD_global.gcd_trace_level >= 4 )
	TRdisplay( "%4d    GCD Fetch: %s\n", 
		    ccb->id, gcu_lookup( fetchMap, ccb->sequence ) );

    switch( ccb->sequence++ )
    {
    case FETCH_INIT :
	/*
	** Validate current fetch state.
	*/
	if ( scb->column.cur_col != 0  ||  scb->column.more_segments )
	{
	    if ( GCD_global.gcd_trace_level >= 1 )
		TRdisplay("%4d    GCD previous fetch not complete: (%d,%d)\n",
			  ccb->id, scb->column.cur_col, scb->column.max_cols);
	    gcd_del_pcb( pcb );
	    gcd_sess_abort( ccb, E_GC480A_PROTOCOL_ERROR );
	    return;
	}

	/*
	** Allocate row/column buffers, if needed.
	** Note: for BYREF procedure parameters we
	** force at least two rows even though only
	** one is expected.  This allows detection
	** of end-of-data during row processing so
	** that the statement can be easily closed.
	*/
	if ( scb->flags & GCD_STMT_BYREF )  pcb->data.data.max_row = 2;

	if ( pcb->data.data.max_row > scb->column.max_rows  && 
	     ! gcd_alloc_qdata( &scb->column, pcb->data.data.max_row ) )
	{
	    gcd_del_pcb( pcb );
	    gcd_sess_abort( ccb, E_GC4808_NO_MEMORY );
	    return;
	}

	/*
	** Skip column set-up if only positioning.
	*/
	if ( ! pcb->data.data.max_row )  ccb->sequence = FETCH_POS;
        break;

    case FETCH_COLS :
    {
	IIAPI_DESCRIPTOR	*desc = (IIAPI_DESCRIPTOR *)scb->column.desc;
	u_i2			column;

	/*
	** If there is a BLOB column in the data set,
	** only fetch upto and including the BLOB (for
	** the first segment).  Additional segments will 
	** be fetched individually.  Remaining columns 
	** will be fetched once the BLOB is done.
	*/
	for( 
	     column = scb->column.cur_col; 
	     column < scb->column.max_cols; 
	     column++ 
	   )
	    if ( desc[ column ].ds_dataType == IIAPI_LVCH_TYPE  ||
		 desc[ column ].ds_dataType == IIAPI_LNVCH_TYPE ||
		 desc[ column ].ds_dataType == IIAPI_LBYTE_TYPE )
	    {
		/* Include BLOB and stop */
		column++;
		pcb->data.data.max_row = 1; 	/* BLOBs force single row */
		break;
	    }

	/*
	** Only one row allowed if partial row.  Preceding loop 
	** checked last column, need to check first column.
	*/
	if ( scb->column.cur_col )  pcb->data.data.max_row = 1;
	scb->column.col_cnt = column - scb->column.cur_col;
	pcb->data.data.col_cnt = scb->column.col_cnt;
	pcb->data.data.data = 
	    &((IIAPI_DATAVALUE *)scb->column.data)[ scb->column.cur_col ];

	/*
	** Skip positioning if doing simple NEXT.
	*/
	if ( pcb->data.data.reference == MSG_POS_CURRENT  &&
	     pcb->data.data.offset == 1 )
	    ccb->sequence = FETCH_FETCH;
	break;
    }

    case FETCH_POS :
	/*
	** Skip row processing if no rows are requested.
	*/
	if ( ! pcb->data.data.max_row )  ccb->sequence = FETCH_QINFO;
	gcd_push_callback( pcb, crsr_fetch_sm );
	gcd_api_position( pcb );
	return;

    case FETCH_FETCH :
	/*
	** Subsequent fetch (if any) will be simple NEXT.
	*/
	pcb->data.data.reference = MSG_POS_CURRENT;
	pcb->data.data.offset = 1;

	gcd_push_callback( pcb, crsr_fetch_sm );

	if ( ccb->msg.flags & GCD_MSG_XOFF )
	{
	    if ( GCD_global.gcd_trace_level >= 4 )
		TRdisplay( "%4d    GCD fetch pending OB XON\n", ccb->id );
	    ccb->msg.xoff_pcb = (PTR)pcb;
	    return;
	}

	gcd_api_getCol( pcb );
	return;

    case FETCH_ROWS :
	/*
	** Send row/column data to client.  
	**
	** Fetching continues if partial row received.
	** End-of-data if didn't receive all requested rows.
	** Non-cursor queries remain active (except at EOD).
	*/
	if ( pcb->api_error )
	    ccb->sequence = FETCH_CLEAR;
	else  if ( ! crsr_rows( ccb, scb, pcb ) )
	    ccb->sequence = FETCH_COLS;			/* partial row */
	else  if ( pcb->data.data.row_cnt < pcb->data.data.max_row )
	{
	    /*
	    ** For scrollable, sensitive cursor, several reasons
	    ** exist for receiving fewer than expected rows.  EOD
	    ** is never returned for a scrollable cursors.  The
	    ** DBMS returns the EOD indication for forward-only
	    ** cursors.  For all others, EOD must be generated.
	    */
	    if ( ! (scb->flags & GCD_STMT_CURSOR) )  
		pcb->result.flags |= PCB_RSLT_EOD;	/* end-of-data */
	}
	else  if ( ! (scb->flags & GCD_STMT_CURSOR) )  
	    ccb->sequence = FETCH_DONE;			/* keep active */
	break;

    case FETCH_QINFO : 
	gcd_push_callback( pcb, crsr_fetch_sm );
	gcd_api_gqi( pcb );
	return;

    case FETCH_CLEAR :
	ccb->api.stmt = NULL;	/* Statement is now dormant. */
	if ( pcb->api_error )  ccb->sequence = FETCH_CHECK;
	break;

    case FETCH_DONE :
	/*
	** Close statement if end-of-data and 
	** AUTO_CLOSE has been requested.
	*/
	if ( pcb->result.flags & PCB_RSLT_EOD  &&
	     scb->flags & GCD_STMT_AUTO_CLOSE )
	{
	    if ( GCD_global.gcd_trace_level >= 4 )
		TRdisplay( "%4d    GCD closing statement at EOD\n", ccb->id );
	    ccb->sequence = CLOSE_CURSOR;
	    crsr_close_sm( (PTR)pcb );
	    return;
	}

	/*
	** Continue fetching rows if requested
	** and not end-of-data.
	*/
	if ( scb->flags & GCD_STMT_FETCH_ALL  &&
	     ! (pcb->result.flags & PCB_RSLT_EOD) )
	{
	    if ( GCD_global.gcd_trace_level >= 4 )
		TRdisplay( "%4d    GCD fetch next block of rows\n", ccb->id );
	    ccb->sequence = FETCH_COLS;
	    ccb->api.stmt = scb->handle;	/* May have cleared above */
	}
	break;

    case FETCH_CHECK :
	if ( ccb->cib->flags & (GCD_CONN_ABORT | GCD_LOGIC_ERR) )  
	    break;	/* Handled below */

	if ( ccb->cib->flags & GCD_XACT_ABORT )
	{
	    gcd_push_callback( pcb, crsr_fetch_sm );
	    gcd_xact_abort( pcb );
	    return;
	}
	break;

    case FETCH_EXIT :
	gcd_send_done( ccb, &pcb->rcb, pcb );
	gcd_del_pcb( pcb );

	if ( ccb->cib->flags & GCD_CONN_ABORT )
	    gcd_sess_abort( ccb, FAIL );
	else  if ( ccb->cib->flags & GCD_LOGIC_ERR )
	    gcd_sess_abort( ccb, E_GC4809_INTERNAL_ERROR );
	else
	    gcd_msg_pause( ccb, TRUE );
	return;

    default :
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD invalid fetch sequence: %d\n", 
			ccb->id, --ccb->sequence );
	gcd_del_pcb( pcb );
	gcd_sess_abort( ccb, E_GC480A_PROTOCOL_ERROR );
	return;
    }

    goto top;
}
Example #5
0
void
gcd_msg_cursor( GCD_CCB *ccb )
{
    DAM_ML_CUR	cursor;
    STMT_ID	stmt_id;
    GCD_SCB	*scb;
    GCD_PCB	*pcb;
    STATUS	status;
    u_i2	pos_anchor = MSG_POS_CURRENT;	/* Default to NEXT */
    i4		pos_offset = 1;
    u_i4	pre_fetch = 1;
    bool	incomplete = FALSE;
    bool	got_id = FALSE;

    if ( ! gcd_get_i2( ccb, (u_i1 *)&cursor.cursor_op ) )
    {
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD no cursor op specified\n", ccb->id );
	gcd_sess_abort( ccb, E_GC480A_PROTOCOL_ERROR );
	return;
    }

    if ( GCD_global.gcd_trace_level >= 3 )
	TRdisplay( "%4d    GCD Cursor operation: %s\n", 
		   ccb->id, gcu_lookup( curMap, cursor.cursor_op ) );

    if ( ! (pcb = gcd_new_pcb( ccb ))  ||
         ! (pcb->rcb = gcd_new_rcb( ccb, -1 )) )
    {
	if ( pcb )  gcd_del_pcb( pcb );
	gcd_sess_abort( ccb, E_GC4808_NO_MEMORY );
	return;
    }

    while( ccb->msg.msg_len )
    {
	DAM_ML_PM	cp;
	u_i1		u_i1_val;
	u_i2		u_i2_val;
	u_i4		u_i4_val;

	incomplete = TRUE;
	if ( ! gcd_get_i2( ccb, (u_i1 *)&cp.param_id ) )  break;
	if ( ! gcd_get_i2( ccb, (u_i1 *)&cp.val_len ) )  break;

	switch( cp.param_id )
	{
	case MSG_CUR_STMT_ID :
	    if ( cp.val_len != (CV_N_I4_SZ * 2)  ||
	         ! gcd_get_i4( ccb, (u_i1 *)&stmt_id.id_high )  ||
		 ! gcd_get_i4( ccb, (u_i1 *)&stmt_id.id_low ) )
		break;

	    incomplete = FALSE;
	    got_id = TRUE;
	    break;
	
	case MSG_CUR_PRE_FETCH :
	    switch( cp.val_len )
	    {
	    case 1 : 
		if ( gcd_get_i1( ccb, (u_i1 *)&u_i1_val ) )
		{
		    pre_fetch = max( pre_fetch, u_i1_val );
		    incomplete = FALSE;
		}
		break;

	    case 2 :
		if ( gcd_get_i2( ccb, (u_i1 *)&u_i2_val ) )
		{
		    pre_fetch = max( pre_fetch, u_i2_val );
		    incomplete = FALSE;
		}
		break;

	    case 4 :
		if ( gcd_get_i4( ccb, (u_i1 *)&u_i4_val ) )
		{
		    pre_fetch = max( pre_fetch, u_i4_val );
		    incomplete = FALSE;
		}
		break;
	    }
	    break;

	case MSG_CUR_POS_ANCHOR :
	    switch( cp.val_len )
	    {
	    case 1 : 
		if ( gcd_get_i1( ccb, (u_i1 *)&u_i1_val ) )
		{
		    pos_anchor = (u_i2)u_i1_val;
		    incomplete = FALSE;
		}
		break;

	    case 2 :
		if ( gcd_get_i2( ccb, (u_i1 *)&u_i2_val ) )
		{
		    pos_anchor = (u_i2)u_i2_val;
		    incomplete = FALSE;
		}
		break;

	    case 4 :
		if ( gcd_get_i4( ccb, (u_i1 *)&u_i4_val ) )
		{
		    pos_anchor = (u_i2)u_i2_val;
		    incomplete = FALSE;
		}
		break;
	    }
	    break;

	case MSG_CUR_POS_OFFSET :
	    if ( cp.val_len != CV_N_I4_SZ  ||
		 ! gcd_get_i4( ccb, (u_i1 *)&pos_offset ) )
		break;

	    incomplete = FALSE;
	    break;
	
	default :
	    if ( GCD_global.gcd_trace_level >= 3 )
		TRdisplay( "%4d    GCD     unkown parameter ID %d\n",
			   ccb->id, cp.param_id );
	    break;
	}

	if ( incomplete )  break;
    }

    if ( incomplete )
    {
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD unable to read all cursor parameters %d\n",
		       ccb->id );
	status = E_GC480A_PROTOCOL_ERROR;
    }
    else  if ( ! got_id )
    {
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD no cursor ID for cursor message\n", 
			ccb->id );
	status = E_GC480A_PROTOCOL_ERROR;
    }
    else
	status = OK;

    if ( status != OK )
    {
	gcd_del_pcb( pcb );
	gcd_sess_abort( ccb, status );
	return;
    }

    if ( ! (scb = gcd_find_stmt( ccb, &stmt_id )) )
    {
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD no active statement for cursor ID\n", 
			ccb->id );
	gcd_sess_error( ccb, &pcb->rcb, E_GC4811_NO_STMT );
	gcd_send_done( ccb, &pcb->rcb, pcb );
	gcd_del_pcb( pcb );
	gcd_msg_pause( ccb, TRUE );
	return;
    }

    switch( cursor.cursor_op )
    {
    case MSG_CUR_CLOSE :
	ccb->sequence = CLOSE_CURSOR;
	pcb->scb = scb;
	crsr_close_sm( (PTR)pcb );
	break;
    
    case MSG_CUR_FETCH :
	ccb->sequence = FETCH_INIT;
	ccb->api.stmt = scb->handle;		/* Activate statement */
	pcb->scb = scb;
	pcb->data.data.reference = pos_anchor;
	pcb->data.data.offset = pos_offset;
	pcb->data.data.max_row = pre_fetch;

	crsr_fetch_sm( (PTR)pcb );
	break;

    default :
	if ( GCD_global.gcd_trace_level >= 1 )
	    TRdisplay( "%4d    GCD invalid cursor op: %d\n", 
			ccb->id, cursor.cursor_op );
	gcd_del_pcb( pcb );
	gcd_sess_abort( ccb, E_GC480A_PROTOCOL_ERROR );
    }

    return;
}