Exemple #1
0
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 );
}
Exemple #2
0
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 );
}