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; }
bool gcd_api_relXID( GCD_CCB *ccb ) { IIAPI_RELXIDPARM parm; parm.rl_tranIdHandle = ccb->xact.distXID; ccb->xact.distXID = NULL; IIapi_releaseXID( &parm ); if ( API_ERROR( parm.rl_status ) && GCD_global.gcd_trace_level >= 1 ) TRdisplay( "%4d GCD IIapi_releaseXID() status: %s\n", ccb->id, gcu_lookup( apiMap, parm.rl_status ) ); return( API_ERROR( parm.rl_status ) ? FALSE : TRUE ); }
bool gcd_api_regXID( GCD_CCB *ccb, IIAPI_TRAN_ID *tranID ) { IIAPI_REGXIDPARM parm; bool success = FALSE; MEcopy( (PTR)tranID, sizeof( *tranID ), (PTR)&parm.rg_tranID ); IIapi_registerXID( &parm ); if ( ! API_ERROR( parm.rg_status ) ) { ccb->xact.distXID = parm.rg_tranIdHandle; success = TRUE; } else if ( GCD_global.gcd_trace_level >= 1 ) { TRdisplay( "%4d GCD IIapi_registerXID() status: %s\n", ccb->id, gcu_lookup( apiMap, parm.rg_status ) ); } return( success ); }
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; }
static STATUS gcd_api_status( char *func_name, IIAPI_GENPARM *genParm, GCD_CCB *ccb, GCD_RCB **rcb_ptr ) { IIAPI_STATUS api_status = genParm->gp_status; bool api_error = API_ERROR( genParm->gp_status ); bool dbms_error = FALSE; STATUS status = OK; if ( (api_error && GCD_global.gcd_trace_level >= 1) || GCD_global.gcd_trace_level >= 2 ) TRdisplay( "%4d GCD %s status: %s\n", ccb->id, func_name, gcu_lookup( apiMap, genParm->gp_status ) ); if ( genParm->gp_errorHandle ) { IIAPI_GETEINFOPARM get; get.ge_errorHandle = genParm->gp_errorHandle; IIapi_getErrorInfo( &get ); while( get.ge_status == IIAPI_ST_SUCCESS ) { u_i2 msg_len = get.ge_message ? (u_i2)STlength(get.ge_message) : 0; switch( get.ge_type ) { case IIAPI_GE_ERROR : switch( get.ge_errorCode ) { case E_AP0001_CONNECTION_ABORTED : ccb->cib->flags |= GCD_CONN_ABORT; break; case E_AP0002_TRANSACTION_ABORTED : ccb->cib->flags |= GCD_XACT_ABORT; break; case E_AP0003_ACTIVE_TRANSACTIONS : case E_AP0004_ACTIVE_QUERIES : case E_AP0006_INVALID_SEQUENCE : ccb->cib->flags |= GCD_LOGIC_ERR; break; } if ( ! dbms_error ) { status = get.ge_errorCode; dbms_error = TRUE; } if ( GCD_global.gcd_trace_level >= 2 ) TRdisplay( "%4d GCD Error 0x%x '%s'\n", ccb->id, get.ge_errorCode, get.ge_SQLSTATE ); if ( GCD_global.gcd_trace_level >= 3 && get.ge_message ) TRdisplay( "%4d GCD %s\n", ccb->id, get.ge_message ); if ( rcb_ptr ) gcd_send_error( ccb, rcb_ptr, MSG_ET_ERR, get.ge_errorCode, get.ge_SQLSTATE, msg_len, get.ge_message ); break; case IIAPI_GE_XAERR : if ( GCD_global.gcd_trace_level >= 2 ) TRdisplay( "%4d GCD XA Error %d\n", ccb->id, get.ge_errorCode ); if ( ! dbms_error ) { status = FAIL; dbms_error = TRUE; } if ( rcb_ptr ) gcd_send_error( ccb, rcb_ptr, MSG_ET_XA, get.ge_errorCode, get.ge_SQLSTATE, msg_len, get.ge_message ); break; case IIAPI_GE_WARNING : if ( GCD_global.gcd_trace_level >= 2 ) TRdisplay( "%4d GCD Warning 0x%x '%s'\n", ccb->id, get.ge_errorCode, get.ge_SQLSTATE ); if ( GCD_global.gcd_trace_level >= 3 && get.ge_message ) TRdisplay( "%4d GCD %s\n", ccb->id, get.ge_message ); if ( rcb_ptr ) gcd_send_error( ccb, rcb_ptr, MSG_ET_WRN, get.ge_errorCode, get.ge_SQLSTATE, msg_len, get.ge_message ); break; default : if ( GCD_global.gcd_trace_level >= 2 ) TRdisplay( "%4d GCD User Message 0x%x\n", ccb->id, get.ge_errorCode ); if ( GCD_global.gcd_trace_level >= 3 && get.ge_message ) TRdisplay( "%4d GCD %s\n", ccb->id, get.ge_message ); if ( rcb_ptr ) gcd_send_error( ccb, rcb_ptr, MSG_ET_MSG, get.ge_errorCode, get.ge_SQLSTATE, msg_len, get.ge_message ); break; } IIapi_getErrorInfo( &get ); } } if ( dbms_error && ! status ) status = E_GC4809_INTERNAL_ERROR; else if ( api_error && ! dbms_error ) { status = (api_status == IIAPI_ST_OUT_OF_MEMORY) ? E_GC4808_NO_MEMORY : E_GC4809_INTERNAL_ERROR; if ( rcb_ptr ) gcd_sess_error( ccb, rcb_ptr, status ); } return( status ); }
STATUS gcd_api_init( u_i2 api_ver, PTR *env ) { IIAPI_INITPARM init; IIAPI_SETENVPRMPARM set; bool done; STATUS status = OK; init.in_timeout = -1; init.in_version = api_ver; IIapi_initialize( &init ); if ( init.in_status != IIAPI_ST_SUCCESS && GCD_global.gcd_trace_level >= 1 ) TRdisplay( "%4d GCD Error initializing API: %s\n", -1, gcu_lookup( apiMap, init.in_status ) ); switch( init.in_status ) { case IIAPI_ST_SUCCESS : *env = init.in_envHandle; break; case IIAPI_ST_OUT_OF_MEMORY : status = E_GC4808_NO_MEMORY; break; default : status = E_GC4809_INTERNAL_ERROR; break; } for( done = (status != OK); ! done; done = TRUE ) { II_LONG value; set.se_envHandle = *env; set.se_paramID = IIAPI_EP_TRACE_FUNC; set.se_paramValue = (II_PTR)gcd_api_trace; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; if( api_ver >= IIAPI_VERSION_6 ) { set.se_paramID = IIAPI_EP_DATE_ALIAS; set.se_paramValue = IIAPI_EPV_INGDATE; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; } set.se_paramID = IIAPI_EP_DATE_FORMAT; value = IIAPI_EPV_DFRMT_FINNISH; set.se_paramValue = (II_PTR)&value; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; set.se_paramID = IIAPI_EP_TIMEZONE; set.se_paramValue = "gmt"; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; set.se_paramID = IIAPI_EP_MAX_SEGMENT_LEN; value = 8192; set.se_paramValue = (II_PTR)&value; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; set.se_paramID = IIAPI_EP_DECIMAL_CHAR; set.se_paramValue = "."; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; set.se_paramID = IIAPI_EP_MONEY_SIGN ; set.se_paramValue = "$"; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; set.se_paramID = IIAPI_EP_MONEY_LORT ; value = IIAPI_EPV_MONEY_LEAD_SIGN; set.se_paramValue = (II_PTR)&value; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; set.se_paramID = IIAPI_EP_MONEY_PRECISION ; value = 2; set.se_paramValue = (II_PTR)&value; IIapi_setEnvParam( &set ); if ( (status = set.se_status) != OK ) break; } if ( status != OK ) gcu_erlog( 0, GCD_global.language, status, NULL, 0, NULL ); return( status ); }
void jdbc_xact_check( JDBC_PCB *pcb, u_i1 xqop ) { JDBC_CCB *ccb = pcb->ccb; if ( JDBC_global.trace_level >= 4 ) TRdisplay( "%4d JDBC %s %s %s\n", ccb->id, ccb->cib->autocommit ? "Autocommit" : (ccb->xact.xacm_multi ? "Multi-cursor" : "Transaction"), ccb->cib->tran ? "active" : "inactive", ccb->cib->autocommit ? gcu_lookup( modeMap, ccb->xact.auto_mode ) : "" ); /* ** Non-autocommit transactions are handled entirely ** through the DBMS, so there is nothing to do if ** autocommit is disabled (watch out for multi-cursor ** simulated autocommit mode which temporarily disables ** autocommit). */ if ( ! ccb->cib->autocommit && ! ccb->xact.xacm_multi ) { jdbc_pop_callback( pcb ); return; } switch( ccb->xact.auto_mode ) { case JDBC_XACM_DBMS : /* ** Autocommit is being handled by the DBMS, but ** autocommit may not yet have been enabled. ** Start autocommit transaction if not yet started ** (jdbc_api_autocommit() will make callback when ** completed). Otherwise, nothing to do. */ if ( ! ccb->cib->tran ) jdbc_api_autocommit( pcb, TRUE ); else jdbc_pop_callback( pcb ); break; case JDBC_XACM_SINGLE : /* ** Autocommit is being handled by the DBMS and ** only a single cursor is permitted to be open. ** An open cursor will be closed if an open ** cursor or non-cursor request is made to avoid ** an error when sending the request to the DBMS. ** ** The autocommit enable optimization is also ** done for this mode, so turn on autocommit if ** not enabled. */ if ( ! ccb->cib->tran ) jdbc_api_autocommit( pcb, TRUE ); else switch( xqop ) { case JDBC_XQOP_NON_CURSOR : case JDBC_XQOP_CURSOR_OPEN : jdbc_purge_stmt( pcb ); break; case JDBC_XQOP_CURSOR_UPDATE : case JDBC_XQOP_CURSOR_CLOSE : default : jdbc_pop_callback( pcb ); break; } break; case JDBC_XACM_MULTI : /* ** Autocommit handled by DBMS only when cursors are ** not open. A normal transaction is used while ** cursors are open and commited once all cursors ** are closed. */ switch( xqop ) { case JDBC_XQOP_NON_CURSOR : case JDBC_XQOP_CURSOR_UPDATE : /* ** Turn on autocommit if not enabled. */ if ( ccb->cib->autocommit && ! ccb->cib->tran ) jdbc_api_autocommit( pcb, TRUE ); else jdbc_pop_callback( pcb ); break; case JDBC_XQOP_CURSOR_OPEN : /* ** Turn off autocommit to prepare for a normal ** transaction activated by the cursor open. */ if ( ccb->xact.xacm_multi ) jdbc_pop_callback( pcb ); else { ccb->cib->autocommit = FALSE; ccb->xact.xacm_multi = TRUE; if ( ccb->cib->tran ) jdbc_api_autocommit( pcb, FALSE ); else jdbc_pop_callback( pcb ); } break; case JDBC_XQOP_CURSOR_CLOSE : /* ** If no cursors are open, commit the ** normal transaction activated by the ** open cursor request and return our ** state to autocommit. ** ** We should not reach this point if ** autocommit is actually enabled ** (should be simulated autocommit), ** but handle this condition just to ** be safe. */ if ( ccb->cib->autocommit ) { if ( ccb->cib->tran ) jdbc_pop_callback( pcb ); else jdbc_api_autocommit( pcb, TRUE ); } else if ( jdbc_active_stmt( ccb ) ) jdbc_pop_callback( pcb ); else { ccb->xact.xacm_multi = FALSE; ccb->cib->autocommit = TRUE; if ( ccb->cib->tran ) jdbc_api_commit( pcb ); else jdbc_pop_callback( pcb ); } break; default : /* ** Should not happen. */ jdbc_pop_callback( pcb ); break; } break; default : if ( JDBC_global.trace_level >= 1 ) TRdisplay( "%4d JDBC invalid xact autocommit mode: %d\n", ccb->id, ccb->xact.auto_mode ); jdbc_pop_callback( pcb ); break; } return; }
static void msg_xact_sm( PTR arg ) { JDBC_PCB *pcb = (JDBC_PCB *)arg; JDBC_CCB *ccb = pcb->ccb; /* ** If not yet allocated, allocate the RCB. */ if ( ! pcb->rcb && ! (pcb->rcb = jdbc_new_rcb( ccb )) ) { jdbc_del_pcb( pcb ); jdbc_gcc_abort( ccb, E_JD0108_NO_MEMORY ); return; } top: if ( JDBC_global.trace_level >= 4 ) TRdisplay( "%4d JDBC xact process seq %s\n", ccb->id, gcu_lookup( xactSeqMap, ccb->sequence ) ); switch( ccb->sequence++ ) { case XACT_COMMIT : /* Commit */ ccb->sequence = XACT_NEW_ID; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_commit( pcb ); return; case XACT_ROLLBACK : /* Rollback */ ccb->sequence = XACT_NEW_ID; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_rollback( pcb ); return; case XACT_AC_ON : /* Enable autocommit */ /* ** We don't actually turn on autocommit here, ** rather we just flag autocommit requested ** (see jdbc_xact_check()). ** ** We need to commit the existing standard ** transaction (which requires a new ID). */ ccb->cib->autocommit = TRUE; ccb->sequence = XACT_NEW_ID; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_commit( pcb ); return; case XACT_AC_OFF : /* Disable autocommit */ ccb->cib->autocommit = FALSE; ccb->sequence = XACT_DONE; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_autocommit( pcb, FALSE ); return; case XACT_BEGIN : /* Begin Distributed */ /* ** Register the distributed transaction ID. */ if ( ! jdbc_api_regXID( pcb->ccb, &pcb->data.tran.distXID ) ) { jdbc_sess_error( ccb, &pcb->rcb, E_JD0116_XACT_REG_XID ); ccb->sequence = XACT_DONE; break; } /* ** Issue a query to associate DBMS transaction with ** the XID. This also has the effect of translating ** the OpenAPI Transaction Name Handle into an OpenAPI ** Transaction Handle for the distributed transaction. */ ccb->cib->tran = ccb->xact.distXID; pcb->data.query.type = IIAPI_QT_QUERY; pcb->data.query.params = FALSE; pcb->data.query.text = ccb->qry.qtxt; ccb->sequence = XACT_GQI; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_query( pcb ); return; case XACT_PREPARE : /* Prepare (2PC) */ ccb->sequence = XACT_DONE; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_prepare( pcb ); return; case XACT_GQI : /* Get query info */ if ( pcb->api_error ) { /* ** The distributed XID is placed in the transaction ** handle to start a distributed transaction. A real ** real transaction handle should be returned. If ** not, clear the transaction handle. */ if ( ccb->cib->tran == ccb->xact.distXID ) ccb->cib->tran = NULL; ccb->sequence = XACT_CANCEL; break; } ccb->sequence = XACT_CLOSE; jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_gqi( pcb ); return; case XACT_NEW_ID : /* New Transaction ID */ ccb->sequence = XACT_DONE; ccb->xact.tran_id++; ccb->stmt.stmt_id = 0; break; case XACT_CANCEL : /* Cancel query */ jdbc_flush_msg( ccb ); jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_cancel( pcb ); return; case XACT_CLOSE : /* Close query */ jdbc_push_callback( pcb, msg_xact_sm ); jdbc_api_close( pcb, NULL ); return; case XACT_DONE : /* Processing completed */ jdbc_send_done( ccb, &pcb->rcb, pcb ); jdbc_del_pcb( pcb ); jdbc_msg_pause( ccb, TRUE ); return; default : if ( JDBC_global.trace_level >= 1 ) TRdisplay( "%4d JDBC invalid xact processing sequence: %d\n", ccb->id, --ccb->sequence ); jdbc_del_pcb( pcb ); jdbc_gcc_abort( ccb, E_JD0109_INTERNAL_ERROR); return; } goto top; }
void jdbc_msg_xact( JDBC_CCB *ccb ) { JDBC_PCB *pcb; IIAPI_II_TRAN_ID iid; IIAPI_XA_TRAN_ID xid; u_i2 *p_req = p_req_xa; u_i2 req_id, p_rec = 0; bool done = FALSE; bool incomplete = FALSE; if ( ! jdbc_get_i2( ccb, (u_i1 *)&req_id ) ) { if ( JDBC_global.trace_level >= 1 ) TRdisplay( "%4d JDBC invalid XACT message format\n", ccb->id ); jdbc_gcc_abort( ccb, E_JD010A_PROTOCOL_ERROR ); return; } if ( JDBC_global.trace_level >= 3 ) TRdisplay( "%4d JDBC Transaction request: %s\n", ccb->id, gcu_lookup( xactMap, req_id ) ); if ( JDBC_global.trace_level >= 4 ) TRdisplay( "%4d JDBC %s %s %s\n", ccb->id, ccb->cib->autocommit ? "Autocommit" : (ccb->xact.xacm_multi ? "Multi-cursor" : "Transaction"), ccb->cib->tran ? "active" : "inactive", ccb->cib->autocommit ? gcu_lookup( modeMap, ccb->xact.auto_mode ) : "" ); MEfill( sizeof( xid ), 0, (PTR)&xid ); /* ** Read the request parameters. */ while( ccb->msg.msg_len ) { JDBC_MSG_PM xp; incomplete = TRUE; if ( ! jdbc_get_i2( ccb, (u_i1 *)&xp.param_id ) ) break; if ( ! jdbc_get_i2( ccb, (u_i1 *)&xp.val_len ) ) break; switch( xp.param_id ) { case JDBC_XP_II_XID : if ( xp.val_len != (CV_N_I4_SZ * 2) || ! jdbc_get_i4( ccb, (u_i1 *)&iid.it_lowTran ) || ! jdbc_get_i4( ccb, (u_i1 *)&iid.it_highTran ) ) break; p_rec |= XP_II_XID; incomplete = FALSE; p_req = p_req_ing; break; case JDBC_XP_XA_FRMT : if ( xp.val_len != CV_N_I4_SZ || ! jdbc_get_i4( ccb, (u_i1 *)&xid.xt_formatID ) ) break; p_rec |= XP_FRMT; incomplete = FALSE; break; case JDBC_XP_XA_GTID : if ( xid.xt_bqualLength && xp.val_len <= IIAPI_XA_MAXGTRIDSIZE ) { /* BQUAL follows GTRID in data array */ int i; for( i = xid.xt_bqualLength - 1; i >= 0; i-- ) xid.xt_data[ xp.val_len + i ] = xid.xt_data[ i ]; } if ( xp.val_len > IIAPI_XA_MAXGTRIDSIZE || ! jdbc_get_bytes( ccb, xp.val_len, (u_i1 *)&xid.xt_data[0] ) ) break; xid.xt_gtridLength = xp.val_len; p_rec |= XP_GTID; incomplete = FALSE; break; case JDBC_XP_XA_BQUAL : if ( xp.val_len > IIAPI_XA_MAXBQUALSIZE || ! jdbc_get_bytes( ccb, xp.val_len, (u_i1 *)&xid.xt_data[xid.xt_gtridLength] ) ) break; xid.xt_bqualLength = xp.val_len; p_rec |= XP_BQUAL; incomplete = FALSE; break; default : if ( JDBC_global.trace_level >= 1 ) TRdisplay( "%4d JDBC unkown parameter ID %d\n", ccb->id, xp.param_id ); break; } if ( incomplete ) break; } if ( incomplete || (p_rec & p_req[ req_id ]) != p_req[ req_id ] || (p_rec & ~(p_req[ req_id ] | p_opt[ req_id ])) ) { if ( JDBC_global.trace_level >= 1 ) if ( incomplete ) TRdisplay( "%4d JDBC unable to read all request params %d\n", ccb->id ); else TRdisplay( "%4d JDBC invalid or missing request params %d\n", ccb->id ); jdbc_gcc_abort( ccb, E_JD010A_PROTOCOL_ERROR ); return; } /* ** Don't allocate the RCB at this time so that there ** is no client error message produced when purging ** statements. */ if ( ! (pcb = jdbc_new_pcb( ccb, FALSE )) ) { jdbc_gcc_abort( ccb, E_JD0108_NO_MEMORY ); return; } switch( req_id ) { case JDBC_XACT_COMMIT : if ( ccb->cib->autocommit || /* Autocommit enabled */ ccb->xact.xacm_multi || /* Simulated autocommit */ ! ccb->cib->tran /* No active transaction */ ) done = TRUE; else ccb->sequence = XACT_COMMIT; break; case JDBC_XACT_ROLLBACK : if ( ccb->cib->autocommit || /* Autocommit enabled */ ccb->xact.xacm_multi || /* Simulated autocommit */ ! ccb->cib->tran /* No active transaction */ ) done = TRUE; else ccb->sequence = XACT_ROLLBACK; break; case JDBC_XACT_AC_ENABLE : if ( ccb->cib->autocommit || ccb->xact.xacm_multi ) done = TRUE; /* Already enabled */ else if ( ! ccb->cib->tran ) { /* ** We don't actually turn on autocommit here, ** rather we just flag autocommit requested ** (see jdbc_xact_check()). */ ccb->cib->autocommit = TRUE; done = TRUE; } else if ( ccb->xact.distXID ) { jdbc_sess_error( ccb, &pcb->rcb, E_JD0110_XACT_AC_STATE ); done = TRUE; } else { /* ** A standard transaction is active: close all ** active statements and commit the transaction. */ ccb->sequence = XACT_AC_ON; } break; case JDBC_XACT_AC_DISABLE : if ( ! ccb->cib->tran ) { ccb->cib->autocommit = FALSE; ccb->xact.xacm_multi = FALSE; done = TRUE; } else if ( ccb->cib->autocommit ) ccb->sequence = XACT_AC_OFF; /* Disable autocommit */ else if ( ccb->xact.distXID ) { jdbc_sess_error( ccb, &pcb->rcb, E_JD0110_XACT_AC_STATE ); done = TRUE; } else { /* ** There is a standard transaction active. ** (possibly for autocommit simulation). ** Commit the transaction (and disable ** autocommit simulation). */ ccb->xact.xacm_multi = FALSE; ccb->sequence = XACT_COMMIT; } break; case JDBC_XACT_BEGIN : if ( ccb->cib->tran || ccb->xact.distXID || ccb->cib->autocommit || ccb->xact.xacm_multi ) { jdbc_sess_error( ccb, &pcb->rcb, E_JD0114_XACT_BEGIN_STATE ); done = TRUE; } else { char xid_str[ 512 ]; ccb->sequence = XACT_BEGIN; if ( p_req == p_req_ing ) { pcb->data.tran.distXID.ti_type = IIAPI_TI_IIXID; STcopy( JDBC_XID_NAME, xid_str ); STcopy( xid_str, pcb->data.tran.distXID.ti_value.iiXID.ii_tranName ); pcb->data.tran.distXID.ti_value.iiXID.ii_tranID.it_highTran = iid.it_highTran; pcb->data.tran.distXID.ti_value.iiXID.ii_tranID.it_lowTran = iid.it_lowTran; if ( ! jdbc_expand_qtxt( ccb, STlength( beginII ) + STlength( xid_str ), FALSE ) ) { jdbc_del_pcb( pcb ); jdbc_gcc_abort( ccb, E_JD0108_NO_MEMORY ); return; } STprintf( ccb->qry.qtxt, beginII, xid_str ); } else { pcb->data.tran.distXID.ti_type = IIAPI_TI_XAXID; pcb->data.tran.distXID.ti_value.xaXID.xa_branchSeqnum = JDBC_XID_SEQNUM; pcb->data.tran.distXID.ti_value.xaXID.xa_branchFlag = JDBC_XID_FLAGS; MEcopy( (PTR)&xid, sizeof( xid ), (PTR)&pcb->data.tran.distXID.ti_value.xaXID.xa_tranID ); formatXID( &pcb->data.tran.distXID.ti_value.xaXID, xid_str ); if ( ! jdbc_expand_qtxt( ccb, STlength( beginXA ) + STlength( xid_str ), FALSE ) ) { jdbc_del_pcb( pcb ); jdbc_gcc_abort( ccb, E_JD0108_NO_MEMORY ); return; } STprintf( ccb->qry.qtxt, beginXA, xid_str ); } } break; case JDBC_XACT_PREPARE : if ( ! ccb->cib->tran || ! ccb->xact.distXID ) { jdbc_sess_error( ccb, &pcb->rcb, E_JD0115_XACT_PREP_STATE ); done = TRUE; } else ccb->sequence = XACT_PREPARE; break; default : if ( JDBC_global.trace_level >= 1 ) TRdisplay( "%4d JDBC invalid XACT operation: %d\n", ccb->id, req_id ); jdbc_del_pcb( pcb ); jdbc_gcc_abort( ccb, E_JD010A_PROTOCOL_ERROR ); return; } if ( done ) { jdbc_send_done( ccb, &pcb->rcb, NULL ); jdbc_del_pcb( pcb ); jdbc_msg_pause( ccb, TRUE ); } else { /* ** Before changing the transaction state, ** make sure all statements have been closed. */ jdbc_push_callback( pcb, msg_xact_sm ); jdbc_purge_stmt( pcb ); } return; }