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; }
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; }
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; }
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; }
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; }