II_EXTERN IIAPI_MSG_BUFF * IIapi_createGCNOper( IIAPI_STMTHNDL *stmtHndl ) { IIAPI_MSG_BUFF *msgBuff; u_i1 *msg; char *str, temp[ 512 ]; i4 val; IIAPI_CONNHNDL *connHndl = IIapi_getConnHndl((IIAPI_HNDL *)stmtHndl); API_PARSE *parse = (API_PARSE *)stmtHndl->sh_queryText; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_createGCNOper: creating GCN Oper message\n" ); if ( ! connHndl ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_createGCNOper: can't get connHndl from stmtHnd\n" ); return( NULL ); } if ( ! (msgBuff = IIapi_allocMsgBuffer( (IIAPI_HNDL *)connHndl )) ) return( NULL ); msgBuff->msgType = GCN_NS_OPER; msg = msgBuff->data + msgBuff->length; /* ** Set the operations flags. ** ** Netutil always sets the merge flag when adding ** nodes, so we will too. ** ** The user ID flag is set if a username was given ** for IIapi_connect() but no password. The Name ** Server will reject the request if current user ** not authorized. ** ** The public flag is set for global values. ** ** The network database flag is set for non-server ** requests. ** ** We currently don't support the sole server flag. ** The merge flag is only marginally supported. ** These flags are mostly used for adding servers, ** which is currently only supported as an ** undocumented feature. */ val = GCN_DEF_FLAG; /* gcn_flag */ if ( parse->opcode == API_KW_ADD && ( parse->object == API_KW_NODE || parse->object == API_KW_ATTR ) ) val |= GCN_MRG_FLAG; if ( connHndl->ch_username && ! connHndl->ch_password ) val |= GCN_UID_FLAG; if ( parse->type == API_KW_GLOBAL ) val |= GCN_PUB_FLAG; if ( parse->object != API_KW_SERVER ) val |= GCN_NET_FLAG; I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); switch( parse->opcode ) /* gcn_opcode */ { case API_KW_ADD : val = GCN_ADD; break; case API_KW_DEL : val = GCN_DEL; break; case API_KW_GET : val = GCN_RET; break; default : /* This should not happen! */ IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_createGCNOper: invalid operations code.\n" ); val = GCN_RET; break; } I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); /* ** Installation ID is currently ignored. */ val = STlength( install_id ) + 1; /* gcn_install.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( install_id, val, msg ); /* gcn_install.gcn_value */ msg += val; msgBuff->length += val; val = 1; /* gcn_tup_cnt */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); /* ** Node and connection operations have fixed types ** defined by GCN. For server operations, the server ** class is used as provided by the application. */ switch( parse->object ) { case API_KW_NODE : str = GCN_NODE; break; case API_KW_LOGIN : str = GCN_LOGIN; break; case API_KW_ATTR : str = GCN_ATTR; break; case API_KW_SERVER : str = ns_resolve_param( parse, API_FIELD_OBJ, FALSE ); break; default : /* Should not happen! */ IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_createGCNOper: invalid object.\n" ); str = empty; break; } /* ** Build the GCN tuple. */ val = STlength( str ) + 1; /* gcn_type.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_type.gcn_value */ msg += val; msgBuff->length += val; /* ** Use username if specified. This will ** either be the username we are connected ** with (if password also provided) or it ** will be the username for the GCN_UID_FLAG ** which requires special privileges for the ** current user. Otherwise, we use the user ** ID of the current process. */ if ( connHndl->ch_username ) str = connHndl->ch_username; else { if ( ! uid[0] ) { IDname( &puid ); STzapblank( uid, uid ); } str = uid; } val = STlength( str ) + 1; /* gcn_uid.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_uid.gcn_value */ msg += val; msgBuff->length += val; str = ns_resolve_param( parse, API_FIELD_VNODE, (parse->opcode != API_KW_ADD) ); val = STlength( str ) + 1; /* gcn_obj.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_obj.gcn_value */ msg += val; msgBuff->length += val; /* ** The tuple value must be built up from various parameters ** and can be function and object dependent. Call appropriate ** function for the current request to process the parameters. ** ** Pass in our temp buffer. It will be used if large enough ** or a different buffer will be allocated and returned. Check ** for memory allocation failures and free the returned buffer ** if it is not the one passed in (after copying the value). */ if ( ! (str = (*parse->parms->parms)( parse, sizeof( temp ), temp )) ) { IIapi_freeMsgBuffer( msgBuff ); return( NULL ); } val = STlength( str ) + 1; /* gcn_val.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_val.gcn_value */ msgBuff->length += val; if ( str != temp ) MEfree( (PTR)str ); msgBuff->flags = IIAPI_MSG_EOD; return( msgBuff ); }
static II_BOOL sm_execute ( IIAPI_ACTION action, IIAPI_HNDL *ev_hndl, IIAPI_HNDL *sm_hndl, II_PTR parmBlock ) { IIAPI_TRANHNDL *tranHndl = (IIAPI_TRANHNDL *)sm_hndl; IIAPI_MSG_BUFF *msgBuff; IIAPI_STATUS status; II_BOOL success = TRUE; char queryText[ 64 ]; switch( action ) { case SQL_TA_REMC : /* ** Remember callback. */ tranHndl->th_callback = TRUE; tranHndl->th_parm = (IIAPI_GENPARM *)parmBlock; break; case SQL_TA_RECV : { /* ** Issue receive message request. */ IIAPI_MSG_BUFF *msgBuff = IIapi_allocMsgBuffer( sm_hndl ); if ( ! msgBuff ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIapi_rcvNormalGCA( sm_hndl, msgBuff, (II_LONG)(-1) ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_SCOM : /* ** Format and send GCA_COMMIT message. */ if ( ! (msgBuff = IIapi_allocMsgBuffer( sm_hndl )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } msgBuff->msgType = GCA_COMMIT; msgBuff->flags = IIAPI_MSG_EOD; status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SRB : /* ** Format and send GCA_ROLLBACK message. */ if ( ! (msgBuff = IIapi_allocMsgBuffer( sm_hndl )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } msgBuff->msgType = GCA_ROLLBACK; msgBuff->flags = IIAPI_MSG_EOD; status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SSP : { /* ** Create savepoint handle. Format and ** send GCA_QUERY message 'savepoint <sp>'. */ IIAPI_SAVEPTHNDL *savePtHndl; IIAPI_SAVEPTPARM *savePtParm = (IIAPI_SAVEPTPARM *)parmBlock; if ( ! IIapi_createSavePtHndl( savePtParm ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } savePtHndl = savePtParm->sp_savePointHandle; STprintf( queryText, "savepoint %s\n", savePtHndl->sp_savePtName ); if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, queryText )) ) { IIapi_deleteSavePtHndl( savePtHndl ); savePtParm->sp_savePointHandle = NULL; status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) { IIapi_deleteSavePtHndl( savePtHndl ); savePtParm->sp_savePointHandle = NULL; success = FALSE; } break; } case SQL_TA_SRBS : { /* ** Format and send GCA_QUERY message 'rollback to <savepoint>'. */ IIAPI_ROLLBACKPARM *rollParm = (IIAPI_ROLLBACKPARM *)parmBlock; IIAPI_SAVEPTHNDL *savePtHndl = rollParm->rb_savePointHandle; STprintf(queryText, "rollback to %s\n", savePtHndl->sp_savePtName); if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, queryText )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_SAON : /* ** Format and send GCA_QUERY message 'set autocommit on'. */ if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, "set autocommit on" )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SAOF : /* ** Format and send GCA_QUERY message 'set autocommit off'. */ if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, "set autocommit off" )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SSEC : /* ** Format and send GCA_SECURE message. */ if ( ! ( msgBuff = IIapi_createMsgSecure( tranHndl ) ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SXAS : { /* ** Send XA Start message. */ IIAPI_XASTARTPARM *startParm = (IIAPI_XASTARTPARM *)parmBlock; if ( ! (msgBuff = IIapi_createMsgXA( sm_hndl, GCA_XA_START, &startParm->xs_tranID.ti_value.xaXID, startParm->xs_flags )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_SXAE : { /* ** Send XA End message. */ IIAPI_XAENDPARM *endParm = (IIAPI_XAENDPARM *)parmBlock; if ( ! (msgBuff = IIapi_createMsgXA( sm_hndl, GCA_XA_END, &endParm->xe_tranID.ti_value.xaXID, endParm->xe_flags )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_PEND : /* ** Return transaction aborted to all pending operations. */ { IIAPI_STMTHNDL *stmtHndl; for( stmtHndl = (IIAPI_STMTHNDL *)tranHndl-> th_stmtHndlList.q_next; stmtHndl != (IIAPI_STMTHNDL *)&tranHndl->th_stmtHndlList; stmtHndl = (IIAPI_STMTHNDL *)stmtHndl-> sh_header.hd_id.hi_queue.q_next ) IIapi_abortStmtHndl( stmtHndl, E_AP0002_TRANSACTION_ABORTED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ); } break; case SQL_TA_DELH : /* ** Mark handle for deletion. */ QUremove( (QUEUE *)tranHndl ); sm_hndl->hd_delete = TRUE; /* ** If this was a distributed transaction, ** the associated distributed transaction ** name should be releasable during the ** callback. Since the transaction handle ** has not actually been deleted, it is ** still associated with the distributed ** transaction name. Normally, cases such ** as this are serialized by the dispatch ** operations queue, but IIapi_releaseXID() ** is not a dispatched request. So we need ** to drop the association prior to making ** the callback. */ if ( tranHndl->th_tranName ) { QUremove( &tranHndl->th_tranNameQue ); tranHndl->th_tranName = NULL; } break; case SQL_TA_DELX : /* ** Free associated transaction name handle. */ if ( tranHndl->th_tranName ) /* Should never be NULL */ { QUremove( &tranHndl->th_tranNameQue ); IIapi_deleteTranName( tranHndl->th_tranName ); tranHndl->th_tranName = NULL; } /* ** Mark handle for deletion. */ QUremove( (QUEUE *)tranHndl ); sm_hndl->hd_delete = TRUE; break; case SQL_TA_ERAB : /* ** Transaction Aborted. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s: Transaction aborted\n", sql_tran_sm.sm_id ); if ( ! IIapi_localError( sm_hndl, E_AP0002_TRANSACTION_ABORTED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; } break; case SQL_TA_ERCF : /* ** Commit failed. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s: transaction commit failed\n", sql_tran_sm.sm_id ); if ( ! IIapi_localError( sm_hndl, E_AP000B_COMMIT_FAILED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; } break; case SQL_TA_ERPC : /* ** Prepare-to-commit failed. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s: transaction prepare failed\n", sql_tran_sm.sm_id ); if ( ! IIapi_localError( sm_hndl, E_AP000C_2PC_REFUSED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; } break; case SQL_TA_RRSP : { /* ** Read response message. */ IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock; GCA_RE_DATA respData; if ( (status = IIapi_readMsgResponse( msgBuff, &respData, TRUE )) != IIAPI_ST_SUCCESS ) { success = FALSE; break; } /* ** Check for XA error */ if ( respData.gca_rqstatus & GCA_XA_ERROR_MASK && respData.gca_errd5 && ! IIapi_xaError( sm_hndl, respData.gca_errd5 ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } break; } case SQL_TA_RXAR : { /* ** Read XA response message. */ IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock; GCA_RE_DATA respData; if ( (status = IIapi_readMsgResponse( msgBuff, &respData, TRUE )) != IIAPI_ST_SUCCESS ) { success = FALSE; break; } /* ** If no XA error is returned, generate generic XA error. */ if ( ! (respData.gca_rqstatus & GCA_XA_ERROR_MASK) || ! respData.gca_errd5 ) respData.gca_errd5 = IIAPI_XAER_RMERR; if ( ! IIapi_xaError( sm_hndl, respData.gca_errd5 ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } break; } case SQL_TA_CBOK : /* ** Callback with success. Note that ** this will pick up the most severe ** status from the errors associated ** with the event handle. */ if ( tranHndl->th_callback ) { IIapi_appCallback(tranHndl->th_parm, sm_hndl, IIAPI_ST_SUCCESS); tranHndl->th_callback = FALSE; } break; case SQL_TA_CBFL : /* ** Callback with failure. */ if ( tranHndl->th_callback ) { IIapi_appCallback(tranHndl->th_parm, sm_hndl, IIAPI_ST_FAILURE); tranHndl->th_callback = FALSE; } break; case SQL_TA_CBIF : /* ** API function called in wrong state. */ if ( ! IIapi_localError( sm_hndl, E_AP0006_INVALID_SEQUENCE, II_SS5000R_RUN_TIME_LOGICAL_ERROR, IIAPI_ST_FAILURE ) ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIAPI_ST_FAILURE; /* ** This may not have been a transaction ** related function, and we may have a ** callback saved on the transaction ** handle, so we carefully make the ** callback to the caller making sure ** not to disturb the transaction handle. */ IIapi_appCallback( (IIAPI_GENPARM *)parmBlock, sm_hndl, status ); break; case SQL_TA_CBAB : /* ** Callback with transaction abort. */ if ( tranHndl->th_callback ) { if ( ! IIapi_localError( sm_hndl, E_AP0002_TRANSACTION_ABORTED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIAPI_ST_FAILURE; IIapi_appCallback( tranHndl->th_parm, sm_hndl, status ); tranHndl->th_callback = FALSE; } break; case SQL_TA_CBABX : /* ** Callback with XA transaction abort. */ if ( tranHndl->th_callback ) { if ( ! IIapi_xaError( sm_hndl, IIAPI_XA_RBROLLBACK ) ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIAPI_ST_FAILURE; IIapi_appCallback( tranHndl->th_parm, sm_hndl, status ); tranHndl->th_callback = FALSE; } break; case SQL_TA_RCVE : /* ** Receive error. ** ** We have received an invalid message. ** Since the connection state machine ** may ignore this particular message ** type, convert to a type which will ** ensure the proper handling in all ** state machines. */ IIapi_liDispatch( IIAPI_EV_UNEXPECTED_RCVD, sm_hndl, NULL, NULL ); break; case SQL_TA_HALT : /* ** Halt state machine execution. */ return( FALSE ); } /* ** If we couldn't complete the action, callback with failure. */ if ( ! success && tranHndl->th_callback ) { IIapi_appCallback( tranHndl->th_parm, sm_hndl, status ); tranHndl->th_callback = FALSE; } return( success ); }