Ejemplo n.º 1
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_getDescriptor( IIAPI_GETDESCRPARM II_FAR *getDescrParm )
{
    IIAPI_HNDL	*handle;
    
    IIAPI_TRACE( IIAPI_TR_TRACE )
	( "IIapi_getDescriptor: retrieving columns from server\n" );
    
    /*
    ** Validate Input parameters
    */
    if ( ! getDescrParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getDescriptor: null getDescriptor parameters\n" );
	return;
    }
    
    getDescrParm->gd_genParm.gp_completed = FALSE;
    getDescrParm->gd_genParm.gp_status = IIAPI_ST_SUCCESS;
    getDescrParm->gd_genParm.gp_errorHandle = NULL;
    getDescrParm->gd_descriptorCount = 0;
    getDescrParm->gd_descriptor = NULL;
    handle = (IIAPI_HNDL *)getDescrParm->gd_stmtHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getDescriptor: API is not initialized\n" );
	IIapi_appCallback( &getDescrParm->gd_genParm, NULL, 
			   IIAPI_ST_NOT_INITIALIZED );
	return;
    }
    
    if ( ( ! IIapi_isStmtHndl( (IIAPI_STMTHNDL *)handle )  &&  
           ! IIapi_isDbevHndl( (IIAPI_DBEVHNDL *)handle ) )  ||
	 IIAPI_STALE_HANDLE( handle ) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getDescriptor: invalid handle\n" );
	IIapi_appCallback( &getDescrParm->gd_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }
    
    IIAPI_TRACE( IIAPI_TR_INFO )
	( "IIapi_getDescriptor: handle = %p\n", handle );
    
    IIapi_clearAllErrors( handle );
    IIapi_uiDispatch( IIAPI_EV_GETDESCR_FUNC, handle, (II_PTR)getDescrParm );

    return;
}
Ejemplo n.º 2
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_getCopyMap( IIAPI_GETCOPYMAPPARM II_FAR *getCopyMapParm )
{
    IIAPI_STMTHNDL	*stmtHndl;
    
    IIAPI_TRACE( IIAPI_TR_TRACE )
	( "IIapi_getCopyMap: retrieving copy information from server\n" );
    
    /*
    ** Validate Input parameters
    */
    if ( ! getCopyMapParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getCopyMap: null getCopyMap parameters\n" );
	return;
    }
    
    getCopyMapParm->gm_genParm.gp_completed = FALSE;
    getCopyMapParm->gm_genParm.gp_status = IIAPI_ST_SUCCESS;
    getCopyMapParm->gm_genParm.gp_errorHandle = NULL;
    stmtHndl = (IIAPI_STMTHNDL *)getCopyMapParm->gm_stmtHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getCopyMap: API is not initialized\n" );
	IIapi_appCallback( &getCopyMapParm->gm_genParm, NULL, 
			   IIAPI_ST_NOT_INITIALIZED );
	return;
    }
    
    if ( ! IIapi_isStmtHndl( stmtHndl )  ||  IIAPI_STALE_HANDLE( stmtHndl ) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getCopyMap: invalid statement handle\n" );
	IIapi_appCallback( &getCopyMapParm->gm_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }
    
    IIAPI_TRACE( IIAPI_TR_INFO ) 
	( "IIapi_getCopyMap: stmtHndl = %p\n", stmtHndl );
    
    IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl );
    
    IIapi_uiDispatch( IIAPI_EV_GETCOPYMAP_FUNC, 
		      (IIAPI_HNDL *)stmtHndl, (II_PTR)getCopyMapParm );

    return;
}
Ejemplo n.º 3
0
II_EXTERN II_VOID
IIapi_appCallback
(
    IIAPI_GENPARM	*genParm,
    IIAPI_HNDL		*handle,
    IIAPI_STATUS	status
)
{
    IIAPI_STATUS	err_status;

    if ( handle )
	if ( ( err_status = IIapi_errorStatus( handle ) ) != IIAPI_ST_SUCCESS )
	    status = IIAPI_WORST_STATUS( status, err_status );
	else
	{
	    /*
	    ** There are no errors on the handle, don't 
	    ** return an error handle to the application.
	    */
	    handle = NULL;
	}

    genParm->gp_completed = TRUE;
    genParm->gp_status = status;
    genParm->gp_errorHandle = (II_PTR)handle;

    IIAPI_TRACE( IIAPI_TR_TRACE )
	( "IIapi_appCallback: request completed, status = %s\n",
	  IIAPI_PRINTSTATUS( status ) );

    if ( handle )
    {
	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ( "IIapi_appCallback: error handle %p\n", handle );
    }

    if ( genParm->gp_callback )
    {
	IIAPI_TRACE( IIAPI_TR_INFO )
	    ( "IIapi_appCallback: application callback\n" );

	(*genParm->gp_callback)( genParm->gp_closure, (II_PTR)genParm );
    }
    else  if ( handle  &&  handle->hd_delete )
    {
	genParm->gp_errorHandle = (II_PTR)IIapi_saveErrors( handle );
    }

    return;
}
Ejemplo n.º 4
0
static char *
ns_login( API_PARSE *parse, i4 buflen, char *buffer )
{
    char	*user, *pwd, *value;
    i4		usrlen, pwdlen, len;
    STATUS	status;

    if ( parse->opcode == API_KW_ADD )
    {
	/*
	** Password required and must be sent encrypted.
	*/
	user = ns_resolve_param( parse, API_FIELD_PARM, FALSE );
	usrlen = STlength( user );
	pwd  = ns_resolve_param( parse, API_FIELD_PARM + 1, FALSE );
	pwdlen = (STlength( pwd ) + 8) * 2;	/* estimate encrypted length */
    }
    else
    {
	/*
	** Use GCN wild card format for password.
	*/
	user = ns_resolve_param( parse, API_FIELD_PARM, TRUE );
	usrlen = STlength( user );
	pwd = empty;
	pwdlen = 0;
    }

    /* Allow room for EOS and separating ',' */
    len = usrlen + pwdlen + 2;

    /*
    ** Allocate storage for the final value
    ** and build it from the parameters
    ** retrieved above.
    */
    value = (len <= buflen) ? buffer
    			    : (char *)MEreqmem( 0, len, FALSE, &status );
    if ( ! value )
    {
	IIAPI_TRACE( IIAPI_TR_FATAL )
	    ( "ns_login: can't allocate value buffer\n" );
	return( NULL );
    }

    if ( parse->opcode != API_KW_ADD )
	STpolycat( 3, user, ",", pwd, value );
    else
    {
	/*
	** Encrypt password directly into formatted output.
	*/
	STpolycat( 2, user, ",", value );
	gcu_encode( user, pwd, &value[ usrlen + 1 ] );
    }

    return( value );
}
Ejemplo n.º 5
0
static char *
ns_value( API_PARSE *parse, i4 buflen, char *buffer )
{
    char	*parms[ API_FIELD_MAX ];
    char	*value;
    i4		len, fld, fld_cnt;
    STATUS	status;

    /*
    ** Get each (possibly optional) parameter
    ** and determine the size of the final
    ** combined value.
    */
    fld_cnt = max( 0, parse->parms->parm_max - API_FIELD_PARM );

    for( fld = len = 0; fld < fld_cnt; fld++ )
    {
	parms[ fld ] = ns_resolve_param( parse, fld + API_FIELD_PARM, 
					 (parse->opcode != API_KW_ADD) );
	len += STlength( parms[ fld ] );
    }

    len += fld_cnt;		/* Allow room for EOS and separating ',' */
    if ( ! len )  len++;

    /*
    ** Use passed in buffer if large enough.
    ** Otherwise, allocate temp buffer.
    */
    value = (len <= buflen) ? buffer
			    : (char *)MEreqmem( 0, len, FALSE, &status );
    if ( ! value )
    {
	IIAPI_TRACE( IIAPI_TR_FATAL )
	    ( "ns_value: can't allocate value buffer\n" );
	return( NULL );
    }

    /*
    ** Build the comma separated list of parameters.
    */
    if ( fld_cnt )
	STcopy( parms[ 0 ], value );
    else
	*value = EOS;

    for( fld = 1; fld < fld_cnt; fld++ )
    {
	STcat( value, "," );
	STcat( value, parms[ fld ] );
    }

    return( value );
}
Ejemplo n.º 6
0
II_EXTERN IIAPI_THREAD *
IIapi_thread( II_VOID )
{
    IIAPI_THREAD	*thread;
    STATUS		status;
    i4		tid = PCtid();

    IIAPI_TRACE( IIAPI_TR_VERBOSE )
	( "IIapi_thread(%d): retrieving local storage\n", tid );

    status = MEtls_get( &IIapi_static->api_thread, (PTR *)&thread );

    if ( status != OK )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_thread: error retrieving local storage: 0x%x\n", status );
	
	return( NULL );
    }

    if ( ! thread )
    {
	thread = (IIAPI_THREAD *)MEreqmem( 0, sizeof( IIAPI_THREAD ),
					   TRUE, &status );
	
	if ( ! thread )
	{
	    IIAPI_TRACE( IIAPI_TR_FATAL )
		( "IIapi_thread: error allocating local storage 0x%x\n",
		  status );
	}
	else
	{
	    IIAPI_TRACE( IIAPI_TR_INFO )
		("IIapi_thread(%d): allocated local storage %p\n",tid,thread);
	
	    QUinit( &thread->api_op_q );

	    status = MEtls_set( &IIapi_static->api_thread, (PTR)thread );

	    if ( status != OK )
	    {
		IIAPI_TRACE( IIAPI_TR_ERROR )
		    ( "IIapi_thread: error saving local storage 0x%x\n",
		      status );
	    
		MEfree( (PTR)thread );
		thread = NULL;
	    }
	}
    }

    IIAPI_TRACE( IIAPI_TR_DETAIL )
	( "IIapi_thread(%d): retrieved local storage %p\n", tid, thread );

    return( thread );
}
Ejemplo n.º 7
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_batch( IIAPI_BATCHPARM II_FAR *batchParm )
{
    IIAPI_CONNHNDL	*connHndl;
    IIAPI_TRANHNDL	*tranHndl;
    IIAPI_STMTHNDL	*stmtHndl;
    IIAPI_HNDL		*handle;
    
    IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_batch: adding a batch query\n" );
    
    /*
    ** Validate Input parameters
    */
    if ( ! batchParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: null batch parameters\n" );
	return;
    }
    
    batchParm->ba_genParm.gp_completed = FALSE;
    batchParm->ba_genParm.gp_status = IIAPI_ST_SUCCESS;
    batchParm->ba_genParm.gp_errorHandle = NULL;
    connHndl = (IIAPI_CONNHNDL *)batchParm->ba_connHandle;
    handle = (IIAPI_HNDL *)batchParm->ba_tranHandle;
    stmtHndl = (IIAPI_STMTHNDL *)batchParm->ba_stmtHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: API is not initialized\n" );
	IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			   IIAPI_ST_NOT_INITIALIZED );
	return;
    }
    
    /*
    ** Validate connection handle.
    */
    if ( ! IIapi_isConnHndl( connHndl )  ||  IIAPI_STALE_HANDLE( connHndl ) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: invalid connHndl %p\n", connHndl );
	IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }
    
    /*
    ** Validate transaction handle.
    */
    if ( handle  &&  ! IIapi_isTranName( (IIAPI_TRANNAME *)handle )  &&
                    (! IIapi_isTranHndl( (IIAPI_TRANHNDL *)handle )  ||
	             IIAPI_STALE_HANDLE( handle )) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: invalid tranHndl %p\n", handle );
	IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }

    /*
    ** Validate statement handle.
    */
    if ( stmtHndl )
    {
    	if ( ! IIapi_isStmtHndl( (IIAPI_STMTHNDL *)stmtHndl )  ||
	     IIAPI_STALE_HANDLE( stmtHndl ) )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_batch: invalid stmtHndl %p\n", stmtHndl );
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_INVALID_HANDLE );
	    return;
	}

	if ( ! handle  ||  IIapi_isTranName( (IIAPI_TRANNAME *)handle) )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_batch: transaction handle required\n" );
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_INVALID_HANDLE );
	    return;
	}

    	if ( handle != (IIAPI_HNDL *)stmtHndl->sh_tranHndl )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_batch: wrong tranHndl %p for stmtHndl %p\n",
		  handle, stmtHndl );
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_INVALID_HANDLE );
	    return;
	}

	if ( connHndl != IIapi_getConnHndl( (IIAPI_HNDL *)stmtHndl ) )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_batch: wrong connHndl %p for stmtHndl %p\n",
		  connHndl, stmtHndl );
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_INVALID_HANDLE );
	    return;
	}
    }

    IIAPI_TRACE( IIAPI_TR_INFO )
	( "IIapi_batch: connHndl = %p, tranHndl = %p, stmtHndl = %p, queryType = %d\n",
	  batchParm->ba_connHandle, batchParm->ba_tranHandle,
	  batchParm->ba_stmtHandle, batchParm->ba_queryType );
    
    IIAPI_TRACE( IIAPI_TR_INFO )
	( "IIapi_batch: queryText = %s\n",
	  batchParm->ba_queryText ? batchParm->ba_queryText : "<NULL>" );
    
    IIapi_clearAllErrors( stmtHndl ? (IIAPI_HNDL *)stmtHndl :
	( (handle && IIapi_isTranHndl( (IIAPI_TRANHNDL *)handle ))
	  ? handle : (IIAPI_HNDL *)connHndl ) );
    
    /*
    ** Check that batch processing is supported on the connection.
    */
    if ( connHndl->ch_partnerProtocol < GCA_PROTOCOL_LEVEL_68 )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: batch not supported at protocol level %d\n", 
	      connHndl->ch_partnerProtocol );

	if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, 
				 E_AP001F_BATCH_UNSUPPORTED, 
				 II_SS50008_UNSUPPORTED_STMT,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &batchParm->ba_genParm, 
			       (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE );
	return;
    }

    /*
    ** Check restrictions on query type and associated info.
    */
    if ( connHndl->ch_type != IIAPI_SMT_SQL  ||
	 (batchParm->ba_queryType != IIAPI_QT_QUERY  &&
	  batchParm->ba_queryType != IIAPI_QT_EXEC   &&
	  batchParm->ba_queryType != IIAPI_QT_EXEC_PROCEDURE) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: invalid query type %d for connection type %d\n", 
	      batchParm->ba_queryType, connHndl->ch_type );

	if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, 
				 E_AP0011_INVALID_PARAM_VALUE, 
				 II_SS50008_UNSUPPORTED_STMT,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &batchParm->ba_genParm, 
			       (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE );
	return;
    }

    if ( batchParm->ba_queryType != IIAPI_QT_EXEC_PROCEDURE  &&
         ! batchParm->ba_queryText )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: query requires query text\n" );

	if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, 
				 E_AP0011_INVALID_PARAM_VALUE, 
				 II_SS5000R_RUN_TIME_LOGICAL_ERROR,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &batchParm->ba_genParm, 
			       (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE );
	return;
    }

    if ( batchParm->ba_queryType == IIAPI_QT_EXEC_PROCEDURE  &&
         ! batchParm->ba_parameters )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: query requires parameters, none indicated\n" );

	if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, 
				 E_AP0011_INVALID_PARAM_VALUE, 
				 II_SS5000R_RUN_TIME_LOGICAL_ERROR,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &batchParm->ba_genParm, 
			       (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE );
	return;
    }

    /*
    ** Allocate a transaction handle if one was not provided.
    */
    if ( ! handle  ||  IIapi_isTranName( (IIAPI_TRANNAME *)handle ) )
    {
	/*
	** Check to see if there is an active transaction.
	*/
	if ( ! IIapi_isQueEmpty( (QUEUE *)&connHndl->ch_tranHndlList ) )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		("IIapi_batch: connection has active transaction.\n");

	    if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, 
				     E_AP0003_ACTIVE_TRANSACTIONS, 
				     II_SS25000_INV_XACT_STATE,
				     IIAPI_ST_FAILURE ) )
		IIapi_appCallback( &batchParm->ba_genParm, NULL, 
				   IIAPI_ST_OUT_OF_MEMORY );
	    else
		IIapi_appCallback( &batchParm->ba_genParm, 
				   (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE );
	    return;
	}

	if ( ! ( tranHndl = IIapi_createTranHndl(
				(IIAPI_TRANNAME *)batchParm->ba_tranHandle,
				(IIAPI_CONNHNDL *)batchParm->ba_connHandle ) ) )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_batch: createTranHndl failed\n" );
	    IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	    return;
	}
    }
    else
    {
	/*
	** Use existing transaction handle.
	*/
	tranHndl = (IIAPI_TRANHNDL *)handle;
	IIapi_clearAllErrors( (IIAPI_HNDL *)tranHndl );
    }
    
    /*
    ** Allocate a new statement handle or initialize existing handle.
    */
    if ( stmtHndl )
	initStmtHndl( stmtHndl );
    else  if ( ! (stmtHndl = IIapi_createStmtHndl( connHndl, tranHndl )) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_batch: createStmtHndl failed\n" );

	IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			   IIAPI_ST_OUT_OF_MEMORY );
	goto freeTranHandle;
    }

    /*
    ** Update statement handle with batch query information.
    */
    if ( batchParm->ba_queryText  &&
	 ! (stmtHndl->sh_queryText = STalloc( batchParm->ba_queryText )) )
    {
	IIAPI_TRACE( IIAPI_TR_FATAL )
	    ( "IIapi_batch: can't alloc query text\n" );

	IIapi_appCallback( &batchParm->ba_genParm, NULL, 
			   IIAPI_ST_OUT_OF_MEMORY );
	goto freeStmtHandle;
    }
    
    stmtHndl->sh_queryType = batchParm->ba_queryType;
    if ( batchParm->ba_parameters )  stmtHndl->sh_flags |= IIAPI_SH_PARAMETERS;

    /*
    ** The current set of external batch/query flags
    ** are not applicable to batch processing, but
    ** we pass them along anyway.
    */
    stmtHndl->sh_flags |= batchParm->ba_flags & IIAPI_QF_ALL_FLAGS;

    batchParm->ba_stmtHandle = (II_PTR)stmtHndl;
    batchParm->ba_tranHandle = (II_PTR)tranHndl;
    
    IIapi_uiDispatch( IIAPI_EV_BATCH_FUNC, 
		      (IIAPI_HNDL *)stmtHndl, (II_PTR)batchParm );
    return;

  freeStmtHandle:

    /*
    ** If the statement handle is not the input handle,
    ** then we allocated a new handle above and we must
    ** now delete it.
    */
    if ( stmtHndl != (IIAPI_STMTHNDL *)batchParm->ba_stmtHandle )
	IIapi_deleteStmtHndl( stmtHndl );

  freeTranHandle:

    /*
    ** If the transaction handle is not the input handle,
    ** then we allocated a new handle above and we must
    ** now delete it.
    */
    if ( tranHndl != (IIAPI_TRANHNDL *)batchParm->ba_tranHandle )
	IIapi_deleteTranHndl( tranHndl );

    return;
}
Ejemplo n.º 8
0
II_EXTERN IIAPI_ENVHNDL *
IIapi_initAPI( II_LONG version, II_LONG timeout )
{
    IIAPI_ENVHNDL	*envHndl;
    IIAPI_ENVHNDL	*defEnvHndl;
    II_BOOL		first_init = FALSE;
    STATUS		status;
    char		*env;

    if ( ! IIapi_static )
    {
	/*
	** Perform global initializations which are
	** environment independent.  
	*/
	first_init = TRUE;

	if ( ! ( IIapi_static = (IIAPI_STATIC *)
		 MEreqmem( 0, sizeof( IIAPI_STATIC ), TRUE, &status ) ) )
	    return( NULL );

	QUinit( &IIapi_static->api_env_q );

	if ( MUi_semaphore( &IIapi_static->api_semaphore ) != OK )
	    goto muiFail;

	if ( MEtls_create( &IIapi_static->api_thread ) != OK )
	    goto metFail;

	/*
	** Initialize sub-systems.
	*/
	IIAPI_INITTRACE();
	IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_initAPI: initializing API.\n" );

	/*
	** Make sure II_SYSTEM or similar is set to provide useful feedback
	** rather than just failing in one of following subsystems.
	*/
	NMgtAt( SYSTEM_LOCATION_VARIABLE, &env );
	if ( env == NULL || *env == EOS )
	{
	    IIAPI_TRACE( IIAPI_TR_FATAL )
		( "IIapi_initAPI: error - %s not set.\n",
		  SYSTEM_LOCATION_VARIABLE );
	    goto adfFail;
	}
	
	IIapi_init_mib();
	if ( ! IIapi_initADF() )	goto adfFail;
	if ( ! IIapi_initGCA(timeout) )	goto gcaFail;

	/* Initialize the unicode collation values */
	IIapi_static->api_unicol_init = FALSE;
	IIapi_static->api_ucode_ctbl = NULL; 
	IIapi_static->api_ucode_cvtbl = NULL;

	/*
	** Create the default environment.
	*/
	if ( ! (IIapi_static->api_env_default = 
				(PTR)IIapi_createEnvHndl( IIAPI_VERSION_1 )) )
	    goto defFail;

	/* Spoken Language to use */

    	if( ( status = ERlangcode( (char *)NULL, 
				   &IIapi_static->api_slang ) != OK) )
    	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_initAPI: error initializing lang 0x%x\n", status );

	    return( NULL );
    	}

	/*
	** The SQL state machines are used by default prior to
	** IIapi_connect() being called, so make sure they are
	** initialized.
	*/
	if ( IIapi_sm_init( IIAPI_SMT_SQL ) != IIAPI_ST_SUCCESS )
	    goto envFail;
    }

    /*
    ** Now do environment specific initialization.
    */
    defEnvHndl = IIapi_defaultEnvHndl();

    if ( version == IIAPI_VERSION_1 )
    {
	/*
	** Version 1 initializers share the default
	** environment.  Keep track of the number of
	** initializers so that IIapi_termAPI() can
	** determine when to do global shutdown.
	*/
	envHndl = defEnvHndl;

	MUp_semaphore( &defEnvHndl->en_semaphore );
	defEnvHndl->en_initCount++;
	MUv_semaphore( &defEnvHndl->en_semaphore );
    }
    else
    {
	/*
	** Create a new environment for the initializer.
	** These environments are saved on the global
	** environment queue.  The caller may also make
	** API calls using the default environment handle, 
	** so increment the default environment handle
	** initialization count.
	*/
	if ( (envHndl = IIapi_createEnvHndl( version )) )
	{
	    MUp_semaphore( &IIapi_static->api_semaphore );
	    QUinsert( (QUEUE *)envHndl, &IIapi_static->api_env_q );
	    MUv_semaphore( &IIapi_static->api_semaphore );

	    MUp_semaphore( &defEnvHndl->en_semaphore );
	    defEnvHndl->en_initCount++;
	    MUv_semaphore( &defEnvHndl->en_semaphore );
	}
	else
	{
	    /*
	    ** We may need to undo the global initialization.
	    ** If not, the NULL environment handle will simply
	    ** be returned.
	    */
	    if ( first_init )  goto envFail;
	}
    }

    return( envHndl );

  envFail:
    IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default );

  defFail:
    IIapi_termGCA();

  gcaFail:
    IIapi_termADF();

  adfFail:
    IIAPI_TERMTRACE();
    MEtls_destroy( &IIapi_static->api_thread, NULL );

  metFail:
    MUr_semaphore( &IIapi_static->api_semaphore );

  muiFail:
    MEfree( (PTR)IIapi_static );
    IIapi_static = NULL;

    return( NULL );
}
Ejemplo n.º 9
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_scroll( IIAPI_SCROLLPARM II_FAR *scrollParm )
{
    IIAPI_STMTHNDL	*stmtHndl;
    IIAPI_CONNHNDL	*connHndl;
    bool		valid;
    
    IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_scroll: scroll cursor\n" );
    
    /*
    ** Validate Input parameters
    */
    if ( ! scrollParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_scroll: null scrollParms parameters\n" );
	return;
    }
    
    scrollParm->sl_genParm.gp_completed = FALSE;
    scrollParm->sl_genParm.gp_status = IIAPI_ST_SUCCESS;
    scrollParm->sl_genParm.gp_errorHandle = NULL;
    stmtHndl = (IIAPI_STMTHNDL *)scrollParm->sl_stmtHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_scroll: API is not initialized\n" );
	IIapi_appCallback( &scrollParm->sl_genParm, 
			   NULL, IIAPI_ST_NOT_INITIALIZED );
	return;
    }
    
    if ( 
    	 ! IIapi_isStmtHndl( stmtHndl )  ||  
	 IIAPI_STALE_HANDLE( stmtHndl )  ||
	 ! (connHndl = IIapi_getConnHndl( (IIAPI_HNDL *)stmtHndl))
       )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_scroll: invalid handle %p\n", stmtHndl );
	IIapi_appCallback( &scrollParm->sl_genParm, 
			   NULL, IIAPI_ST_INVALID_HANDLE );
	return;
    }
    
    IIAPI_TRACE( IIAPI_TR_INFO ) 
	( "IIapi_scroll: handle = %p\n", stmtHndl );
    IIAPI_TRACE( IIAPI_TR_INFO ) 
	( "IIapi_scroll: orientation = %d, offset = %d\n", 
	    scrollParm->sl_orientation, scrollParm->sl_offset );
    
    IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl );
    
    /*
    ** Validate parameters.
    */
    switch( scrollParm->sl_orientation )
    {
    case IIAPI_SCROLL_NEXT :
	valid = TRUE;
	break;

    case IIAPI_SCROLL_BEFORE :
    case IIAPI_SCROLL_FIRST :
    case IIAPI_SCROLL_PRIOR :
    case IIAPI_SCROLL_CURRENT :
    case IIAPI_SCROLL_LAST :
    case IIAPI_SCROLL_AFTER :
    case IIAPI_SCROLL_ABSOLUTE :
    case IIAPI_SCROLL_RELATIVE :
	if ( connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67 )
	    valid = TRUE;
	else
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_scroll: scrolling not supported\n" );
	    valid = FALSE;
	}
    	break;

    default :
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_scroll: invalid orientation: %d\n",
	      (II_LONG)scrollParm->sl_orientation );
	valid = FALSE;
	break;
    }

    if ( ! valid )
    {
	if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, 
				 E_AP0011_INVALID_PARAM_VALUE, 
				 II_SS22003_NUM_VAL_OUT_OF_RANGE, 
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &scrollParm->sl_genParm, 
			       NULL, IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &scrollParm->sl_genParm, 
	    		       (IIAPI_HNDL *)stmtHndl, IIAPI_ST_FAILURE );
        return;
    }

    IIapi_uiDispatch( IIAPI_EV_SCROLL_FUNC, 
    		      (IIAPI_HNDL *)stmtHndl, (II_PTR)scrollParm );
    return;
}
Ejemplo n.º 10
0
II_EXTERN II_VOID
IIapi_loadNSColumns
( 
    IIAPI_STMTHNDL	*stmtHndl, 
    IIAPI_GETCOLPARM	*getColParm,
    IIAPI_GCN_REQ_TUPLE	*tuple 
)
{
    IIAPI_DESCRIPTOR	*descr;
    IIAPI_DATAVALUE	*value;
    API_PARSE		*parse = (API_PARSE *)stmtHndl->sh_queryText;
    char		buffer[ API_NS_MAX_LEN ];
    char		*str, *val[ 3 ];
    u_i2		len;

    IIAPI_TRACE( IIAPI_TR_VERBOSE )
	( "IIapi_loadNSColumns: %d columns starting at %d, %d total columns\n",
	  (II_LONG)stmtHndl->sh_colFetch,
	  (II_LONG)stmtHndl->sh_colIndex,
	  (II_LONG)stmtHndl->sh_colCount );

    /*
    ** Some columns are combined in the returned
    ** GCN value field.  Break out the combinded
    ** columns for reference below.  We don't
    ** expect to overflow the buffer, but just
    ** in case we truncate the input.
    */
    if ( tuple->gcn_val.gcn_l_item > (sizeof( buffer ) - 1) )
	tuple->gcn_val.gcn_value[ sizeof( buffer ) - 1 ] = EOS;
    gcu_words( tuple->gcn_val.gcn_value, buffer, val, ',', 3 );

    descr = &stmtHndl->sh_colDescriptor[ stmtHndl->sh_colIndex ];
    value = &getColParm->gc_columnData[ (getColParm->gc_rowsReturned *
					 getColParm->gc_columnCount) +
					 getColParm->gc_columnCount -
					 stmtHndl->sh_colFetch ];

    for( ; stmtHndl->sh_colFetch;
	 stmtHndl->sh_colFetch--, stmtHndl->sh_colIndex++, descr++, value++ )
    {
	/*
	** Figure out which piece of of the tuple
	** satisfies the current column depending
	** on which object type is being accessed.
	*/
	switch( parse->object )
	{
	    case API_KW_NODE :
		switch( stmtHndl->sh_colIndex )
		{
		    case 0 :		/* Type */
			str = (parse->type == API_KW_GLOBAL) ? glob_type 
							     : priv_type;	
			break;

		    case 1 :		/* Vnode */
			str = tuple->gcn_obj.gcn_value;	
			break;

		    case 2 :		/* Network address */
			str = val[0];
			break;

		    case 3 :		/* Protocol */
			str = val[1];
			break;

		    case 4 :		/* Listen address */
			str = val[2];
			break;
		}
		break;

	    case API_KW_LOGIN :
		switch( stmtHndl->sh_colIndex )
		{
		    case 0 :		/* Type */
			str = (parse->type == API_KW_GLOBAL) ? glob_type 
							     : priv_type;	
			break;

		    case 1 :		/* Vnode */
			str = tuple->gcn_obj.gcn_value;	
			break;

		    case 2 :		/* Login */
			str = val[0];
			break;
		}
		break;

	    case API_KW_ATTR :
		switch( stmtHndl->sh_colIndex )
		{
		    case 0 :		/* Type */
			str = (parse->type == API_KW_GLOBAL) ? glob_type 
							     : priv_type;	
			break;

		    case 1 :		/* Vnode */
			str = tuple->gcn_obj.gcn_value;	
			break;

		    case 2 :		/* Attribute Name */
			str = val[0];
			break;

		    case 3 :		/* Attribute Value */
			str = val[1];
			break;
		}
		break;

	    case API_KW_SERVER :
		switch( stmtHndl->sh_colIndex )
		{
		    case 0 :		/* Server type */
			str = tuple->gcn_type.gcn_value;	
			break;

		    case 1 :		/* Object */
			str = tuple->gcn_obj.gcn_value;	
			break;

		    case 2 :		/* Address */
			str = val[0];
			break;
		}
		break;
	}

	/*
	** We should always get a valid string,
	** but provide a default just in case.
	** Strings are silently truncated if too
	** long since we don't expect truncation
	** to occur (except for the type column,
	** in which case silent truncation is
	** desired).
	*/
	if ( ! str )  str = err_str;
	len = STlength( str );
	value->dv_null = FALSE;

	switch( descr->ds_dataType )
	{
	    case IIAPI_CHA_TYPE :
		len = min( len, descr->ds_length );
		value->dv_length = len;
		MEcopy( (PTR)str, len, value->dv_value );
		break;
	    
	    case IIAPI_VCH_TYPE :
		len = min( len, descr->ds_length - sizeof( len ) );
		value->dv_length = sizeof( len ) + len;
		MEcopy( (PTR)&len, sizeof( len ), value->dv_value );
		MEcopy( (PTR)str, len, 
			(PTR)((char *)value->dv_value + sizeof( len )) );
		break;

	    default :
		/*
		** Should not happen.
		*/
		value->dv_null = TRUE;
		value->dv_length = 0;
		break;
	}
    }

    return;
}
Ejemplo n.º 11
0
II_EXTERN IIAPI_STATUS
IIapi_parseNSQuery( IIAPI_STMTHNDL *stmtHndl, STATUS *func_status )
{
    API_PARSE	*parse;
    i4		keyword[ API_FIELD_MAX ];
    i4		fld, marker_index;
    STATUS	status;

    *func_status = OK;

    /*
    ** Allocate the parse info structure.
    */
    parse = (API_PARSE *)MEreqmem( 0, sizeof( API_PARSE ), TRUE, &status );

    if ( ! parse )  
    {
	IIAPI_TRACE( IIAPI_TR_FATAL )
	    ( "IIapi_parseNSQuery: couldn't allocate parser info.\n" );

	return( IIAPI_ST_OUT_OF_MEMORY );
    }

    /*
    ** Tokenize the query text for individual
    ** field validation and processing.
    */
    if ( (*func_status = ns_scanner( stmtHndl->sh_queryText, parse )) != OK )
    {
	MEfree( (PTR)parse );
	return( IIAPI_ST_FAILURE );
    }

    /*
    ** Check for keywords and parameter markers in fields.
    */
    for( fld = marker_index = 0; fld < parse->field_count; fld++ )
	if ( fld >= ARRAY_SIZE( keyword_tbl ) )
	    ns_param_marker( parse, fld, &marker_index );
	else
	{
	    keyword[ fld ] = ns_keyword(parse->fields[fld], keyword_tbl[fld]);

	    if ( keyword[ fld ] == INVALID_KEYWORD  &&
		 ns_param_marker( parse, fld, &marker_index ) )
		keyword[ fld ] = API_KW_PARAM;
	}

    if ( (*func_status = ns_validate( parse, keyword )) != OK )
    {
	MEfree( (PTR)parse );
	return( IIAPI_ST_FAILURE );
    }

    /*
    ** Finally, we replace the original query
    ** text with our parsed information.
    */
    MEfree( stmtHndl->sh_queryText );
    stmtHndl->sh_queryText = (char *)parse;

    return( IIAPI_ST_SUCCESS );
}
Ejemplo n.º 12
0
static II_BOOL
load_blob
(
    IIAPI_STMTHNDL	*stmtHndl,
    IIAPI_GETCOLPARM	*getColParm,
    IIAPI_DESCRIPTOR	*descriptor,
    IIAPI_MSG_BUFF	*msgBuff,
    IIAPI_DATAVALUE	*dataValue
)
{
    if ( ! (stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS ) )
    {
	/*
	** Process the BLOB segments in the input buffer
	** until we empty the input buffer, the end of
	** the BLOB is reached, or we fill the output
	** buffer.
	*/
	do
	{
	    if ( ! cnvtBLOB2DataValue(stmtHndl,descriptor,msgBuff,dataValue) )
		return( FALSE );

	    if ( ! (stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS) )
		return( TRUE );

	} while( dataValue->dv_length < descriptor->ds_length );

	/*
	** We have satisfied the request if this is the
	** last column of a single row request.  Other-
	** wise we must purge the rest of the BLOB before
	** processing the rest of the request.
	*/
	if ( stmtHndl->sh_colFetch <= 1  &&  getColParm->gc_rowCount <= 1 )
	{
	    /*
	    ** There is a (very small) chance that we
	    ** we filled the output buffer and read the
	    ** last input segment at the same time.  In
	    ** this case the end-of-segments indicator
	    ** has not been processed and may or may not
	    ** be in the input buffer.
	    **
	    ** Normally we would just return TRUE at this
	    ** point, but the special case complicates
	    ** things.  If the end-of-segments indicator
	    ** is in the input buffer, we want to process
	    ** it so that the application can be told
	    ** that this is the last segment.  The check
	    ** can be made by calling checkBLOBSegment(),
	    ** but some special conditions must be handled.
	    **
	    ** CheckBLOBSegment() requires the request to be 
	    ** complete and will change the column index if 
	    ** the end-of-segments indicator is processed.
	    ** The result of all this is that we must do the
	    ** work to finish the column processing and return
	    ** FALSE so that the caller will not duplicate the
	    ** work.
	    */
	    stmtHndl->sh_colFetch--;
	    checkBLOBSegment( stmtHndl, descriptor, msgBuff );
	    return( FALSE );
	}

	stmtHndl->sh_flags |= IIAPI_SH_PURGE_SEGMENTS;
	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ( "cnvtBLOB2DataValue: begin purging segments\n" );
    }

    /*
    ** Purge the input buffer of BLOB segments
    ** until we find the end of the blob or we
    ** empty the input buffer.
    */
    while( stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS )
	if ( ! cnvtBLOB2DataValue( stmtHndl, descriptor, msgBuff, dataValue ) )
	    return( FALSE );
    
    /*
    ** We must be done with the BLOB.
    */
    return( TRUE );
}
Ejemplo n.º 13
0
static IIAPI_SM_OUT *
sm_evaluate
(
    IIAPI_EVENT		event,
    IIAPI_STATE 	state,
    IIAPI_HNDL		*ev_hndl,
    IIAPI_HNDL		*sm_hndl,
    II_PTR		parmBlock,
    IIAPI_SM_OUT	*smo_buff
)
{
    IIAPI_TRANHNDL	*tranHndl = (IIAPI_TRANHNDL *)sm_hndl;
    IIAPI_SM_OUT	*smo = NULL;
    SM_TRANSITION	*smt;

    IIAPI_TRACE( IIAPI_TR_VERBOSE )
	( "%s evaluate: evaluating event %s in state %s\n",
	  sql_tran_sm.sm_id, IIAPI_PRINTEVENT( event ),
	  IIAPI_PRINT_ID( state, SQL_TS_CNT, sql_ts_id ) );

    /*
    ** Static evaluations depend solely on the current state and event.
    */
    if ( (smt = smt_array[ event ][ state ]) )
    {
	IIAPI_TRACE( IIAPI_TR_DETAIL )
	    ( "%s evaluate: static evaluation\n", sql_tran_sm.sm_id );

	smo = smo_buff;
	STRUCT_ASSIGN_MACRO( sql_act_seq[ smt->smt_action ], *smo );
	smo->smo_next_state = smt->smt_next;
    }
    else		/* Dynamic evaluations require additional predicates */
    switch( event )	/* to determine the correct state transition.	     */
    {
	/*
	** Rollback requests may be for savepoints
	** or the entire transaction.
	*/
	case IIAPI_EV_ROLLBACK_FUNC :
	    if ( ((IIAPI_ROLLBACKPARM *)parmBlock)->rb_savePointHandle )
	    {
		/*
		** Rollback to savepoint.
		*/
		switch( state )
		{
		    case SQL_TS_TRAN :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_12 ], *smo );
			smo->smo_next_state = SQL_TS_RBSP;
			break;

		    case SQL_TS_ABORT :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_21 ], *smo );
			smo->smo_next_state = state;
			break;
		}
	    }
	    else
	    {
		/*
		** Rollback transaction.
		*/
		switch( state )
		{
		    case SQL_TS_IDLE :
		    case SQL_TS_BEG :
		    case SQL_TS_ABORT :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_10 ], *smo );
			smo->smo_next_state = SQL_TS_IDLE;
			break;

		    case SQL_TS_TRAN :
		    case SQL_TS_PREP :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_13 ], *smo );
			smo->smo_next_state = SQL_TS_ROLL;
			break;

		    case SQL_TS_XA :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_13 ], *smo );
			smo->smo_next_state = SQL_TS_XAEND;
			break;
		}
	    }
	    break;

	/*
	** GCA_RESPONSE messages include the current DBMS 
	** transaction state, allowing detection of the 
	** start of a transaction and transaction aborts.
	** In some cases, the query status is also of
	** interest.
	*/
	case IIAPI_EV_RESPONSE_RCVD :
	{
	    /*
	    ** A fake GCA_RESPONSE message is generated for some cases 
	    ** of procedure execution.  The GCA message buffer will be 
	    ** NULL in this case and it is assumed that the procedure
	    ** executed successfully.
	    **
	    ** The RESPONSE message is not consumed during evaluation.
	    */
	    GCA_RE_DATA	respData;

	    if ( ! parmBlock  ||
	         IIapi_readMsgResponse((IIAPI_MSG_BUFF *)parmBlock,
					&respData, FALSE) != IIAPI_ST_SUCCESS )
		respData.gca_rqstatus = 0;

	    if ( respData.gca_rqstatus & GCA_LOG_TERM_MASK )
	    {
		/*
		** Transaction inactive (possibly aborted).
		*/
		switch( state )
		{
		    case SQL_TS_BEG :
		    case SQL_TS_ABORT :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo );
			smo->smo_next_state = state;
			break;

		    case SQL_TS_TRAN :
		    case SQL_TS_XA :
		    case SQL_TS_PREP :
		    case SQL_TS_WSPR :
		    case SQL_TS_WRSR :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_7 ], *smo );
			smo->smo_next_state = SQL_TS_ABORT;
			break;
		}
	    }
	    else
	    {
		/*
		** Transaction active.
		*/
		switch( state )
		{
		    case SQL_TS_BEG :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo );
			smo->smo_next_state = SQL_TS_TRAN;
			break;

		    case SQL_TS_TRAN :
		    case SQL_TS_XA :
		    case SQL_TS_PREP :
		    case SQL_TS_ABORT :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo );
			smo->smo_next_state = state;
			break;

		    case SQL_TS_WSPR :
		    case SQL_TS_WRSR :
			smo = smo_buff;

			if ( respData.gca_rqstatus & GCA_FAIL_MASK )
			    STRUCT_ASSIGN_MACRO(sql_act_seq[SQL_TAS_9], *smo);
			else
			    STRUCT_ASSIGN_MACRO(sql_act_seq[SQL_TAS_4], *smo);

			smo->smo_next_state = SQL_TS_TRAN;
			break;
		}
	    }

	    if ( respData.gca_rqstatus & GCA_FAIL_MASK )
	    {
		/*
		** Request failed.
		*/
		switch( state )
		{
		    case SQL_TS_WONR :
		    case SQL_TS_WOFR :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_18 ], *smo );
			smo->smo_next_state = SQL_TS_IDLE;
			break;
		}
	    }
	    else
	    {
		/*
		** Request succedded.
		*/
		switch( state )
		{
		    case SQL_TS_WONR :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_4 ], *smo);
			smo->smo_next_state = SQL_TS_AUTO;
			break;

		    case SQL_TS_WOFR :
			smo = smo_buff;
			STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_5 ], *smo);
			smo->smo_next_state = SQL_TS_IDLE;
			break;
		}
	    }
	    break;
	}
	/*
	** GCA_REJECT messages should only occur in
	** the connected state.  They are processed 
	** by the connection SM.  When significant, 
	** only handle when EOD.
	*/
	case IIAPI_EV_REJECT_RCVD :
	    switch( state )
	    {
	    case SQL_TS_CONN :
	    {
		IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock;
		smo = smo_buff;

		if ( msgBuff->flags & IIAPI_MSG_EOD )
		{
		    STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_6 ], *smo);
		    smo->smo_next_state = SQL_TS_IDLE;
		}
		else
		{
		    smo->smo_action_cnt = 0;
		    smo->smo_next_state = state;
		}
		break;
	    }
	    }
	    break;

	/*
	** GCA_RELEASE messages are mostly ignored.
	** They are processed by the connection SM.
	** When significant, only handle when EOD.
	*/
	case IIAPI_EV_RELEASE_RCVD :
	    switch( state )
	    {
	    case SQL_TS_IDLE :
	    case SQL_TS_CONN :
	    {
		IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock;
		smo = smo_buff;

		if ( msgBuff->flags & IIAPI_MSG_EOD )
		{
		    STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_6 ], *smo);
		    smo->smo_next_state = SQL_TS_IDLE;
		}
		else
		{
		    smo->smo_action_cnt = 0;
		    smo->smo_next_state = state;
		}
		break;
	    }
	    default :
		/*
		** Ignored in all other states.
		*/
		smo = smo_buff;
		smo->smo_next_state = state;
		smo->smo_action_cnt = 0;
		break;
	    }
	    break;

	/*
	** The following events are ignored at the
	** transaction level.  They will be processed
	** by the connection state machine.  Since
	** they are unconditionally ignored, it is
	** easier to handle them here than maintaining
	** static transitions for every state.
	*/
    	case IIAPI_EV_ERROR_RCVD :
    	case IIAPI_EV_EVENT_RCVD :
	case IIAPI_EV_NPINTERUPT_RCVD :
    	case IIAPI_EV_TRACE_RCVD :
    	case IIAPI_EV_PROMPT_RCVD :
    	case IIAPI_EV_UNEXPECTED_RCVD :
	case IIAPI_EV_RESUME :
    	case IIAPI_EV_RECV_ERROR :
    	case IIAPI_EV_SEND_ERROR :
	    smo = smo_buff;
	    smo->smo_next_state = state;
	    smo->smo_action_cnt = 0;
	    break;
    }

    /*
    ** If a specific response was not generated above,
    ** produce a generalized error response.
    */
    if ( ! smo )
    {
	smo = smo_buff;

	if ( event <= IIAPI_EVENT_FUNC_MAX )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "%s Evaluate: API function called in wrong state\n",
		  sql_tran_sm.sm_id );

	    STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_19 ], *smo );
	    smo->smo_next_state = state;
	}
        else  if ( event <= IIAPI_EVENT_MSG_MAX )
        {
            IIAPI_TRACE( IIAPI_TR_ERROR )
                ( "%s Evaluate: invalid message received\n",
                  sql_tran_sm.sm_id );

            STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_20 ], *smo );
            smo->smo_next_state = state;
        }
        else
        {
            IIAPI_TRACE( IIAPI_TR_ERROR )
                ( "%s Evaluate: unexpected I/O completion\n",
                  sql_tran_sm.sm_id );

            STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo );
            smo->smo_next_state = state;
        }
    }

    /*
    ** If the input resulted in no state change
    ** and no actions to be executed, we can
    ** just ignore the event.
    */
    if ( smo->smo_next_state == state  &&  ! smo->smo_action_cnt )
    {
        IIAPI_TRACE( IIAPI_TR_DETAIL )
            ( "%s evaluate: nothing to do, transition ignored\n",
              sql_tran_sm.sm_id );
        smo = NULL;
    }

    return( smo );
}
Ejemplo n.º 14
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 );
}
Ejemplo n.º 15
0
static IIAPI_SM_OUT *
sm_evaluate
(
    IIAPI_EVENT		event,
    IIAPI_STATE 	state,
    IIAPI_HNDL		*ev_hndl,
    IIAPI_HNDL		*sm_hndl,
    II_PTR		parmBlock,
    IIAPI_SM_OUT	*smo_buff
)
{
    IIAPI_TRANHNDL	*tranHndl = (IIAPI_TRANHNDL *)sm_hndl;
    IIAPI_SM_OUT	*smo = NULL;
    SM_TRANSITION	*smt;

    IIAPI_TRACE( IIAPI_TR_VERBOSE )
	( "%s evaluate: evaluating event %s in state %s\n",
	  ns_tran_sm.sm_id, IIAPI_PRINTEVENT( event ),
	  IIAPI_PRINT_ID( state, NS_TS_CNT, ns_ts_id ) );

    /*
    ** Static evaluations depend solely on the current state and event.
    */
    if ( (smt = smt_array[ event ][ state ]) )
    {
	IIAPI_TRACE( IIAPI_TR_DETAIL )
	    ( "%s evaluate: static evaluation\n", ns_tran_sm.sm_id );

	smo = smo_buff;
	STRUCT_ASSIGN_MACRO( ns_act_seq[ smt->smt_action ], *smo );
	smo->smo_next_state = smt->smt_next;
    }

    /*
    ** If a specific response was not generated above,
    ** produce a generalized error response.
    */
    if ( ! smo )
    {
	smo = smo_buff;

	if ( event <= IIAPI_EVENT_FUNC_MAX )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "%s Evaluate: API function called in wrong state\n",
		  ns_tran_sm.sm_id );

	    STRUCT_ASSIGN_MACRO( ns_act_seq[ NS_TAS_3 ], *smo );
	    smo->smo_next_state = state;
	}
        else  if ( event <= IIAPI_EVENT_MSG_MAX )
        {
            IIAPI_TRACE( IIAPI_TR_ERROR )
                ( "%s Evaluate: invalid message received\n",
                  ns_tran_sm.sm_id );

            STRUCT_ASSIGN_MACRO( ns_act_seq[ NS_TAS_4 ], *smo );
            smo->smo_next_state = state;
        }
        else
        {
            IIAPI_TRACE( IIAPI_TR_ERROR )
                ( "%s Evaluate: unexpected I/O completion\n",
                  ns_tran_sm.sm_id );

            STRUCT_ASSIGN_MACRO( ns_act_seq[ NS_TAS_0 ], *smo );
            smo->smo_next_state = state;
        }
    }

    /*
    ** If the input resulted in no state change
    ** and no actions to be executed, we can
    ** just ignore the event.
    */
    if ( smo->smo_next_state == state  &&  ! smo->smo_action_cnt )
    {
        IIAPI_TRACE( IIAPI_TR_DETAIL )
            ( "%s evaluate: nothing to do, transition ignored\n",
              ns_tran_sm.sm_id );
        smo = NULL;
    }

    return( smo );
}
Ejemplo n.º 16
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 );
}
Ejemplo n.º 17
0
static II_BOOL
cnvtGDV2DataValue
(
    IIAPI_STMTHNDL	*stmtHndl,
    IIAPI_DESCRIPTOR	*descriptor,
    IIAPI_MSG_BUFF	*msgBuff,
    IIAPI_DATAVALUE	*dataValue,
    II_BOOL		compressed
)
{
    i4 data_len, avail_len;

    /*
    ** Check that any minimum required length 
    ** is available and determine GCA data length.
    */
    switch( descriptor->ds_dataType )
    {
    case IIAPI_VCH_TYPE :
    case IIAPI_VBYTE_TYPE :
    case IIAPI_NVCH_TYPE :
    case IIAPI_TXT_TYPE :
    case IIAPI_LTXT_TYPE :
	if ( ! compressed )
	    data_len = descriptor->ds_length;
	else
	{
	    u_i2 len;

	    /*
	    ** The embeded length indicator is required.  It may
	    ** have been already loaded (dv_length > 0) or may
	    ** be available in the input buffer.  Otherwise, wait
	    ** until it is available.
	    */
	    if ( dataValue->dv_length )
		MEcopy( dataValue->dv_value, sizeof( len ), (PTR)&len );
	    else  if ( msgBuff->length >= sizeof( len ) )  
		MEcopy( (PTR)msgBuff->data, sizeof( len ), (PTR)&len );
	    else
	    {
		IIAPI_TRACE( IIAPI_TR_VERBOSE )
		    ( "cnvtGDV2DataValue: need embedded length (%d bytes, %d available)\n",
		      sizeof( len ), msgBuff->length );
		return( FALSE );
	    }

	    /*
	    ** Get the actual length of the compressed column.
	    */
	    data_len = sizeof( len ) + 
		       (IIapi_isUCS2(descriptor->ds_dataType) ? len * 2 : len);
	}
    	break;

    case IIAPI_LCLOC_TYPE :
    case IIAPI_LBLOC_TYPE :
    case IIAPI_LNLOC_TYPE :
    {
	i4	tag;
	u_i4	len0, len1;
	u_i1	*ptr = msgBuff->data;

	/*
	** The ADF PERIPHERAL header must be read along with
	** the ADP locator value.
	*/
	if ( msgBuff->length < (ADP_HDR_SIZE + sizeof(ADP_LOCATOR)) )
	{
	    IIAPI_TRACE( IIAPI_TR_VERBOSE )
		( "cnvtGDV2DataValue: need LOCATOR (%d bytes, %d available)\n",
		  ADP_HDR_SIZE + sizeof(ADP_LOCATOR), msgBuff->length );
	    return( FALSE );
	}

	/*
	** With the full ADP locator object available, read
	** the header and set remaining data length.  Column
	** info is availabe once the header is read.
	*/
	msgBuff->data += ADP_HDR_SIZE;
	msgBuff->length -= ADP_HDR_SIZE;
	stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= 
								IIAPI_CI_AVAIL;
	MECOPY_CONST_MACRO( ptr, sizeof( tag ), (PTR)&tag );

	if ( tag == ADP_P_LOCATOR )
	{
	    ptr += sizeof( tag );
	    MECOPY_CONST_MACRO( ptr, sizeof( len0 ), (PTR)&len0 );
	    ptr += sizeof( len0 );
	    MECOPY_CONST_MACRO( ptr, sizeof( len1 ), (PTR)&len1 );
	    stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |=
	    						IIAPI_CI_LOB_LENGTH;
	    stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_data.lob_length =
					((u_i8)len0 << 32) | (u_i8)len1;
	}

	data_len = sizeof( ADP_LOCATOR );
    	break;
    }
    default :
	data_len = descriptor->ds_length;
    	break;
    }

    /*
    ** Determine amount of data available to be loaded:
    ** smaller of amount in input buffer and amount not 
    ** yet loaded.
    */
    avail_len = min( msgBuff->length, data_len - dataValue->dv_length );

    IIAPI_TRACE( IIAPI_TR_VERBOSE )
	( "cnvtGDV2DataValue: loading %d of %d bytes (%d loaded)\n",
	  avail_len, data_len, (II_LONG)dataValue->dv_length );

    /*
    ** Load available data in input buffer.
    */
    if ( avail_len )
    {
	MEcopy( (PTR)msgBuff->data, avail_len, 
		(PTR)((char *)dataValue->dv_value + dataValue->dv_length) );
	msgBuff->data += avail_len;
	msgBuff->length -= avail_len;
	dataValue->dv_length += avail_len;
    }

    /*
    ** Check to see if all data has been loaded.
    */
    if ( dataValue->dv_length < data_len )
    {
	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ( "cnvtGDV2DataValue: insufficient data: need %d bytes\n",
	      data_len - dataValue->dv_length );
	return( FALSE );
    }

    /*
    ** For nullable columns, check the NULL byte.
    */
    if ( descriptor->ds_nullable )
    {
	/*
	** Check to see if NULL byte is in input buffer.
	*/
	if ( ! msgBuff->length )  
	{
	    IIAPI_TRACE( IIAPI_TR_VERBOSE )
		( "cnvtGDV2DataValue: need NULL byte (1 byte, 0 available\n" );
	    return( FALSE );
	}

	if ( ! (*msgBuff->data & ADF_NVL_BIT) )
	    dataValue->dv_null = FALSE;
	else
	{
	    dataValue->dv_null = TRUE;
	    dataValue->dv_length = 0;	/* Force to 0 since set above */
	}

	msgBuff->data++;	/* Remove NULL byte from input buffer */
	msgBuff->length--;
    }

    if ( IIapi_isVAR( descriptor->ds_dataType )  &&  ! dataValue->dv_null )
    {
	/*
	** Variable length types only return the length of
	** the actual data, not their fully padded length.
	*/
	u_i2 len;

	MEcopy( dataValue->dv_value, sizeof( len ), (PTR)&len );
	dataValue->dv_length = sizeof( len ) +
		    (IIapi_isUCS2( descriptor->ds_dataType ) ? len * 2 : len);
    }

    return( TRUE );
}
Ejemplo n.º 18
0
II_EXTERN IIAPI_STATUS
IIapi_getNSDescriptor( IIAPI_STMTHNDL *stmtHndl )
{
    API_PARSE		*parse = (API_PARSE *)stmtHndl->sh_queryText;
    IIAPI_DESCRIPTOR	*desc1, *desc2;
    STATUS		status;
    i4			count;

    switch( parse->object )
    {
	case API_KW_NODE :
	    desc1 = ns_node_desc;
	    count = ARRAY_SIZE( ns_node_desc );
	    break;

	case API_KW_LOGIN :
	    desc1 = ns_login_desc;
	    count = ARRAY_SIZE( ns_login_desc );
	    break;

	case API_KW_ATTR :
	    desc1 = ns_attr_desc;
	    count = ARRAY_SIZE( ns_attr_desc );
	    break;

	case API_KW_SERVER :
	    desc1 = ns_server_desc;
	    count = ARRAY_SIZE( ns_server_desc );
	    break;

	default :
	    /*
	    ** Should not happen!
	    */
	    IIAPI_TRACE( IIAPI_TR_TRACE )
		( "IIapi_getNSDescriptor: invalid object.\n" );
	    return( IIAPI_ST_FAILURE );
	    break;
    }

    stmtHndl->sh_colDescriptor = (IIAPI_DESCRIPTOR *)
	MEreqmem( 0, sizeof(IIAPI_DESCRIPTOR) * count, FALSE, &status );

    if ( ! stmtHndl->sh_colDescriptor )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_getNSDescriptor: error allocating descriptor.\n" );

	return( IIAPI_ST_OUT_OF_MEMORY );
    }

    for( 
	 stmtHndl->sh_colCount = 0, desc2 = stmtHndl->sh_colDescriptor; 
	 stmtHndl->sh_colCount < count; 
	 stmtHndl->sh_colCount++, desc1++, desc2++
       )
    {
	STRUCT_ASSIGN_MACRO( *desc1, *desc2 );
	desc2->ds_columnName = STalloc( desc1->ds_columnName );

	if ( ! desc2->ds_columnName )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_getNSDescriptor: error allocating column name.\n" );

	    /*
	    ** Since all the entries are valid
	    ** upto sh_colCount, we'll leave the
	    ** descriptor to be freed when the
	    ** statement handle is freed.
	    */
	    return( IIAPI_ST_OUT_OF_MEMORY );
	}
    }

    return( IIAPI_ST_SUCCESS );
}
Ejemplo n.º 19
0
static II_BOOL
cnvtBLOB2DataValue 
(
    IIAPI_STMTHNDL	*stmtHndl,
    IIAPI_DESCRIPTOR	*descriptor,
    IIAPI_MSG_BUFF	*msgBuff,
    IIAPI_DATAVALUE	*dataValue
)
{
    u_i2	char_size = IIapi_isUCS2( descriptor->ds_dataType ) ? 2 : 1;
    i4		indicator = 0;
    i4		length;
    u_i2	seg_len;

    /*
    ** The output buffer needs to be initialized with a 
    ** zero length segment.  Subsequent processing then 
    ** only needs to append input segments to the current 
    ** output segment.  The initial output data value 
    ** length is set to 0 (see IIapi_getColumns()) so 
    ** that we can detect when initialization is required.  
    ** Any non-zero value indicates an existing segment.
    */
    if ( ! dataValue->dv_length )
    {
	seg_len = 0;
	dataValue->dv_null = FALSE;
	dataValue->dv_length = sizeof( seg_len );
	MECOPY_CONST_MACRO( (PTR)&seg_len, 
			    sizeof( seg_len ), dataValue->dv_value );
    }

    /*
    ** The MORE_SEGMENTS flag gets set once the BLOB
    ** header is read.  If it is not set, we need to
    ** read the header.
    */
    if ( ! ( stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS ) )
    {
	i4	tag;
	u_i4	len0, len1;
	u_i1	*ptr = msgBuff->data;

	/*
	** BLOB processing assumes that if this is a NULL or
	** zero length BLOB, the entire BLOB is processed with
	** the header information.  In addition to the header,
	** we need to have access to the first segment indicator
	** and possibly the NULL byte.  Note that if the BLOB
	** is nullable but not NULL, the additional byte will
	** come from the segment length of the first segment.
	*/
	length = ADP_HDR_SIZE + sizeof( indicator ) + 
		 (descriptor->ds_nullable ? 1 : 0);

	if ( msgBuff->length < length )
	{
	    IIAPI_TRACE( IIAPI_TR_VERBOSE )
		( "cnvtBLOB2DataValue: need BLOB header for column %d\n",
		  (II_LONG)stmtHndl->sh_colIndex );
	    return( FALSE );
	}

	/*
	** Remove the header from the input buffer.  LOB 
	** column info is available once the header has 
	** been read.  Extract header data as column info.
	*/
	msgBuff->data += ADP_HDR_SIZE;
	msgBuff->length -= ADP_HDR_SIZE;
	stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= 
								IIAPI_CI_AVAIL;
	MECOPY_CONST_MACRO( ptr, sizeof( tag ), (PTR)&tag );

	if ( tag == ADP_P_GCA )
	{
	    ptr += sizeof( tag );
	    MECOPY_CONST_MACRO( ptr, sizeof( len0 ), (PTR)&len0 );
	    ptr += sizeof( len0 );
	    MECOPY_CONST_MACRO( ptr, sizeof( len1 ), (PTR)&len1 );
	    stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |=
	    						IIAPI_CI_LOB_LENGTH;
	    stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_data.lob_length =
					((u_i8)len0 << 32) | (u_i8)len1;
	}

	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ( "cnvtBLOB2DataValue: processed BLOB header for column %d\n",
	      (II_LONG)stmtHndl->sh_colIndex );

	/*
	** At this point we begin processing segments.
	*/
	stmtHndl->sh_flags |= IIAPI_SH_MORE_SEGMENTS;
    }

    /*
    ** Process the segment indicator.
    */
    length = sizeof( indicator );

    if ( msgBuff->length >= length )
    {
	/*
	** To consume the indicator, must have sufficient remaining
	** data to satisfy the request.  There are three cases:
	**
	** Indicator value	Nullable	Bytes Needed
	** ---------------	--------	------------
	**        0		   N		0 
	**        0		   Y		1 (NULL byte)
	**        1		  Y/N		3 (segment length + data)
	*/
	MECOPY_CONST_MACRO( msgBuff->data, length, (PTR)&indicator );
	length += indicator ? sizeof( seg_len ) + char_size
			    : (descriptor->ds_nullable ? 1 : 0);
    }

    if ( msgBuff->length < length )
    {
	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ("cnvtBLOB2DataValue: need segment indicator for column %d\n",
	     (II_LONG)stmtHndl->sh_colIndex);
	return( FALSE );
    }

    /*
    ** Remove the indicator from the input buffer.
    */
    msgBuff->data += sizeof( indicator );
    msgBuff->length -= sizeof( indicator );

    /*
    ** If the indicator is 0, this is the end of the
    ** data segments and the BLOB.  Otherwise a
    ** segment follows.
    */
    if ( ! indicator )
    {
	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ( "cnvtBLOB2DataValue: found end-of-segments indicator\n" );

	/*
	** During purging we ignore the NULL byte since
	** the data value was initialized when purging
	** started.
	*/
	if ( ! (stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS) )
	    dataValue->dv_null = 
		descriptor->ds_nullable 
		    ? IIAPI_ISNULL(-descriptor->ds_dataType, 1, msgBuff->data)
		    : FALSE;

	/*
	** Remove NULL byte from input buffer and
	** terminate BLOB segment processing.
	*/
	if ( descriptor->ds_nullable )
	{
	    msgBuff->data++;
	    msgBuff->length--;
	}

	stmtHndl->sh_flags &= ~(IIAPI_SH_MORE_SEGMENTS |
				IIAPI_SH_PURGE_SEGMENTS);
    }
    else
    {
	/*
	** Read the segment length.  Limit the length
	** to what is available in the input buffer.
	*/
	MECOPY_CONST_MACRO( msgBuff->data, sizeof( seg_len ), (PTR)&seg_len );
	msgBuff->data += sizeof( seg_len );
	msgBuff->length -= sizeof( seg_len );
	length = min( seg_len, msgBuff->length / char_size ) * char_size;

	if ( stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS )
	{
	    /*
	    ** Remove the available portion of
	    ** the segment from the input buffer.
	    */
	    msgBuff->data += length;
	    msgBuff->length -= length;
	    stmtHndl->sh_flags |= IIAPI_SH_LOST_SEGMENTS;

	    IIAPI_TRACE( IIAPI_TR_VERBOSE )
		( "cnvtBLOB2DataValue: discarding segment of %d bytes\n",
		  length );
	}
	else
	{
	    u_i2 new_len;

	    /*
	    ** We further limit the segment length to be
	    ** processed by the space available in the
	    ** output buffer.
	    */
	    length = min(length, descriptor->ds_length - dataValue->dv_length);
	    length -= length % char_size;	/* Whole characters only */

	    /*
	    ** Append input segment data to output segment.
	    */
	    MEcopy( msgBuff->data, length, 
		    (PTR)((char *)dataValue->dv_value + dataValue->dv_length) );
	    msgBuff->data += length;
	    msgBuff->length -= length;
	    dataValue->dv_length += length;

	    /*
	    ** Update the output embedded segment length.
	    */
	    new_len = (dataValue->dv_length - sizeof( new_len )) / char_size;
	    MECOPY_CONST_MACRO( (PTR)&new_len, 
				sizeof( new_len ), dataValue->dv_value );

	    IIAPI_TRACE( IIAPI_TR_VERBOSE )
		( "cnvtBLOB2DataValue: processed segment of %d bytes\n",
		  length );
	}

	/*
	** If the entire input segment was not consumed,
	** patch what remains to be a valid BLOB segment.
	** Create a segment indicator and segment length
	** to represent the remaining data.  There is 
	** room in the input buffer for this info to be 
	** pre-pended to what remains since the same 
	** info was removed from the input buffer above.
	*/
	if ( (length /= char_size) != seg_len )
	{
	    seg_len -= length;				/* Segment length */
	    msgBuff->data -= sizeof( seg_len );
	    msgBuff->length += sizeof( seg_len );
	    MECOPY_CONST_MACRO((PTR)&seg_len, sizeof(seg_len), msgBuff->data);

	    msgBuff->data -= sizeof( indicator );	/* Indicator */
	    msgBuff->length += sizeof( indicator );
	    MECOPY_CONST_MACRO( (PTR)&indicator, 
				sizeof( indicator ), msgBuff->data );

	    IIAPI_TRACE( IIAPI_TR_VERBOSE )
		( "cnvtBLOB2DataValue: split segment, %d bytes remain\n",
		  (II_LONG)seg_len );
	}
    }

    return( TRUE );
}
Ejemplo n.º 20
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_position( IIAPI_POSPARM II_FAR *posParm )
{
    IIAPI_STMTHNDL	*stmtHndl;
    IIAPI_CONNHNDL	*connHndl;
    bool		valid;
    
    IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_position: position cursor\n" );
    
    /*
    ** Validate Input parameters
    */
    if ( ! posParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_position: null posParms parameters\n" );
	return;
    }
    
    posParm->po_genParm.gp_completed = FALSE;
    posParm->po_genParm.gp_status = IIAPI_ST_SUCCESS;
    posParm->po_genParm.gp_errorHandle = NULL;
    stmtHndl = (IIAPI_STMTHNDL *)posParm->po_stmtHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_position: API is not initialized\n" );
	IIapi_appCallback( &posParm->po_genParm, 
			   NULL, IIAPI_ST_NOT_INITIALIZED );
	return;
    }
    
    if ( 
    	 ! IIapi_isStmtHndl( stmtHndl )  ||
	 IIAPI_STALE_HANDLE( stmtHndl )  ||
         ! (connHndl = IIapi_getConnHndl( (IIAPI_HNDL *)stmtHndl ))
       )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_position: invalid handle %p\n", stmtHndl );
	IIapi_appCallback( &posParm->po_genParm, 
			   NULL, IIAPI_ST_INVALID_HANDLE );
	return;
    }
    
    IIAPI_TRACE( IIAPI_TR_INFO ) 
	( "IIapi_position: handle = %p\n", stmtHndl );
    IIAPI_TRACE( IIAPI_TR_INFO ) 
	( "IIapi_position: reference = %d, offset = %d, rows = %d\n", 
	    posParm->po_reference, posParm->po_offset, posParm->po_rowCount );
    
    IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl );
    
    /*
    ** Validate parameters.
    */
    switch( posParm->po_reference )
    {
    case IIAPI_POS_BEGIN :
    case IIAPI_POS_END :
	if ( connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67 )
	    valid = TRUE;
	else
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_scroll: scrolling not supported\n" );
	    valid = FALSE;
	}
    	break;

    case IIAPI_POS_CURRENT :
	if ( connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67  ||
	     posParm->po_offset == 1 )
	    valid = TRUE;
	else
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_scroll: scrolling not supported\n" );
	    valid = FALSE;
	}
	break;

    default :
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_position: invalid reference: %d\n",
	      (II_LONG)posParm->po_reference );
	valid = FALSE;
	break;
    }

    if ( posParm->po_rowCount < 
         ((connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67) ? 0 : 1) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_position: invalid row count: %d\n",
	      (II_LONG)posParm->po_rowCount );
	valid = FALSE;
    }

    if ( ! valid )
    {
	if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, 
				 E_AP0011_INVALID_PARAM_VALUE, 
				 II_SS22003_NUM_VAL_OUT_OF_RANGE, 
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &posParm->po_genParm, 
			       NULL, IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &posParm->po_genParm, 
	    		       (IIAPI_HNDL *)stmtHndl, IIAPI_ST_FAILURE);
        return;
    }
    
    IIapi_uiDispatch( IIAPI_EV_POSITION_FUNC, 
    		      (IIAPI_HNDL *) stmtHndl, (II_PTR)posParm );
    return;
}
Ejemplo n.º 21
0
II_EXTERN II_VOID
IIapi_loadColumns
(
    IIAPI_STMTHNDL	*stmtHndl,
    IIAPI_GETCOLPARM	*getColParm,
    IIAPI_MSG_BUFF	*msgBuff
)
{
    /*
    ** If no data available or request complete, we be done!
    */
    if ( msgBuff->length < 1  ||  ! stmtHndl->sh_colFetch  ||
	 getColParm->gc_rowsReturned >= getColParm->gc_rowCount )
    {
	IIAPI_TRACE( IIAPI_TR_DETAIL )
	    ( "IIapi_loadColumns: nothing to do\n" );
	return;
    }

    IIAPI_TRACE( IIAPI_TR_DETAIL )
	( "IIapi_loadColumns: converting tuple data to API format\n" );
    
    /*
    ** Loop for each row in the request.
    */
    do
    {
	/*
	** Process columns in the current row.  The current
	** column request should not span rows, but may be
	** fewer than the remaining columns in the row.  If
	** this is a multi-row fetch, we will reset the
	** column request for the next row after processing
	** the current row.  The current row request will
	** either be satisfied, or the tuple data will be
	** exhausted.
	*/
	load_columns( stmtHndl, getColParm, msgBuff );

	/*
	** If there are still columns to be processed in
	** the current request, exit to get more data.
	*/
	if ( stmtHndl->sh_colFetch )  break;

	/*
	** We have completed the request for the current row.
	** We bump the number of rows returned since we either
	** completed a row or completed a partial fetch of a
	** row.  We will either exit at this point or move
	** on to the next row.
	*/
	getColParm->gc_rowsReturned++;

	/*
	** Check to see if we have completed a row.
	*/
	if ( stmtHndl->sh_colIndex >= stmtHndl->sh_colCount )
	{
	    /*
	    ** For cursors, decrement the remaining row count now
	    ** that a row has been completed.
	    */
	    if ( stmtHndl->sh_flags & IIAPI_SH_CURSOR )
		stmtHndl->sh_rowCount--;

	    /*
	    ** Set the column index for the start of the next row.
	    ** If there are more rows in the request, set the 
	    ** column fetch count for the next row.
	    */
	    stmtHndl->sh_colIndex = 0;

	    if ( getColParm->gc_rowsReturned < getColParm->gc_rowCount )
		stmtHndl->sh_colFetch = stmtHndl->sh_colCount;
	}

    } while( stmtHndl->sh_colFetch );

    return;
}
Ejemplo n.º 22
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_autocommit( IIAPI_AUTOPARM II_FAR *autoParm )
{
    IIAPI_TRANHNDL	*tranHndl;
    IIAPI_CONNHNDL	*connHndl;
    
    IIAPI_TRACE( IIAPI_TR_TRACE )("IIapi_autocommit: set autocommit state\n");
    
    /*
    ** Validate Input parameters
    */
    if ( ! autoParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_autocommit: null autocommit parameters\n" );
	return;
    }
    
    autoParm->ac_genParm.gp_completed = FALSE;
    autoParm->ac_genParm.gp_status = IIAPI_ST_SUCCESS;
    autoParm->ac_genParm.gp_errorHandle = NULL;
    connHndl = (IIAPI_CONNHNDL *)autoParm->ac_connHandle;
    tranHndl = (IIAPI_TRANHNDL *)autoParm->ac_tranHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_autocommit: API is not initialized\n" );
	IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			   IIAPI_ST_NOT_INITIALIZED );
	return;
    }
    
    if ( ! connHndl  &&  ! tranHndl )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_autocommit: no handle provided\n" );
	IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }

    if ( connHndl  &&  
	 (! IIapi_isConnHndl( connHndl )  ||  IIAPI_STALE_HANDLE( connHndl )) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_autocommit: invalid connection handle\n" );
	IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }

    if ( tranHndl  &&  
	 (! IIapi_isTranHndl( tranHndl )  ||  IIAPI_STALE_HANDLE( tranHndl )) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_autocommit: invalid transaction handle\n" );
	IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }

    IIAPI_TRACE( IIAPI_TR_INFO )
	( "IIapi_autocommit: connHndl = %p, tranHndl = %p\n",
	  autoParm->ac_connHandle, autoParm->ac_tranHandle );
    
    if ( connHndl )  IIapi_clearAllErrors( (IIAPI_HNDL *)connHndl );
    if ( tranHndl )  IIapi_clearAllErrors( (IIAPI_HNDL *)tranHndl );

    if ( ! tranHndl  &&  ! IIapi_isQueEmpty( &connHndl->ch_tranHndlList ) )
    {
	/*
	** Application is attempting to enable autocommit mode 
	** with an active transaction.
	*/
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_autocommit: can't enable autocommit in a transaction\n" );

	if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, 
				 E_AP0003_ACTIVE_TRANSACTIONS, 
				 II_SS25000_INV_XACT_STATE,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &autoParm->ac_genParm, 
			       (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE );
	return;
    }
	
    if ( tranHndl  &&  ! IIapi_isQueEmpty( &tranHndl->th_stmtHndlList ) )
    {
	/*
	** Application is attempting to disable autocommit mode
	** with active statements.
	*/
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ("IIapi_autocommit: can't disable autocommit with active statements\n");

	if ( ! IIapi_localError( (IIAPI_HNDL *)tranHndl, 
				 E_AP0004_ACTIVE_QUERIES, 
				 II_SS25000_INV_XACT_STATE,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &autoParm->ac_genParm, 
			       (IIAPI_HNDL *)tranHndl, IIAPI_ST_FAILURE );
	return;
    }
    
    if ( ! tranHndl )
    {
	/*
	** Enable autocommit mode.  Create a transaction handle
	** and return it to the application.
	*/
	if ( ! ( tranHndl = IIapi_createTranHndl( NULL, connHndl ) ) )
	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_autocommit: createTranHndl failed\n" );
	    IIapi_appCallback( &autoParm->ac_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	    return;
	}

	autoParm->ac_tranHandle = (II_PTR)tranHndl;
    }
    else
    {
	/*
	** Disable autocommit mode.  The transaction handle
	** will be deleted, so clear the output parameter.
	*/
	autoParm->ac_tranHandle = NULL;
    }
    
    IIapi_uiDispatch( IIAPI_EV_AUTO_FUNC, 
		      (IIAPI_HNDL *)tranHndl, (II_PTR)autoParm );

    return;
}
Ejemplo n.º 23
0
static II_VOID
load_columns
(
    IIAPI_STMTHNDL	*stmtHndl,
    IIAPI_GETCOLPARM	*getColParm,
    IIAPI_MSG_BUFF	*msgBuff
)
{
    IIAPI_DESCRIPTOR	*descr;
    IIAPI_DATAVALUE	*value;
    i4			length;
    u_i2		len;
    bool		done;

    IIAPI_TRACE( IIAPI_TR_VERBOSE )
	( "IIapi_loadColumns: %d columns starting with %d, %d total columns\n",
	  (II_LONG)stmtHndl->sh_colFetch, 
	  (II_LONG)stmtHndl->sh_colIndex, 
	  (II_LONG)stmtHndl->sh_colCount );

    descr = &stmtHndl->sh_colDescriptor[ stmtHndl->sh_colIndex ];
    value = &getColParm->gc_columnData[ (getColParm->gc_rowsReturned * 
					 getColParm->gc_columnCount) +
					 getColParm->gc_columnCount -
					 stmtHndl->sh_colFetch ];

    /*
    ** Process columns until all done or input buffer exhausted.
    */
    for( ; stmtHndl->sh_colFetch; 
	 stmtHndl->sh_colFetch--, stmtHndl->sh_colIndex++, descr++, value++ )
    {
	/*
	** Clear column info at start of row.  The more segments
	** flag must not be set otherwise the first column is a
	** LOB which has already been partially processed.  There
	** must also be at least some data available for the first
	** column, otherwise we may be clearing the info when the
	** last row has already been received.
	*/
	if ( 
	     stmtHndl->sh_colIndex == 0  &&
	     ! (stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS)  &&
	     msgBuff->length > 0 
	   )
	{
	    i2 i;

	    for( i = 0; i < stmtHndl->sh_colCount; i++ )
	        stmtHndl->sh_colInfo[ i ].ci_flags = 0;
	}

	/*
	** Blobs are broken into segments of variable lengths
	** and require special handling to load segments using 
	** internal data value info.
	*/
	if ( IIapi_isBLOB( descr->ds_dataType ) )
	    done = load_blob( stmtHndl, getColParm, descr, msgBuff, value );
	else
	    done = cnvtGDV2DataValue( stmtHndl, descr, msgBuff, value, 
		(stmtHndl->sh_flags & IIAPI_SH_COMP_VARCHAR) ? TRUE : FALSE );

	if ( ! done )  break;	/* Need more data for current column */

	stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |=
								IIAPI_CI_AVAIL;

	IIAPI_TRACE( IIAPI_TR_VERBOSE )
	    ( "IIapi_loadColumns: loaded data for column %d\n",
	      (II_LONG)stmtHndl->sh_colIndex );
    }

    return;
}
Ejemplo n.º 24
0
II_EXTERN II_BOOL
IIapi_termAPI( IIAPI_ENVHNDL *envHndl )
{
    IIAPI_ENVHNDL	*defEnvHndl;
    II_BOOL		last_term = FALSE;

    if ( ! IIapi_static )  return( TRUE );

    defEnvHndl = IIapi_defaultEnvHndl();

    if ( envHndl )  
    {
	/*
	** Free the environment handle.
	*/
	MUp_semaphore( &IIapi_static->api_semaphore );
	QUremove( (QUEUE *)envHndl );
	MUv_semaphore( &IIapi_static->api_semaphore );

	IIapi_deleteEnvHndl( envHndl );
    }
    else
    {
	/*
	** Decrement the usage counter in 
	** the default environment handle.
	*/
	MUp_semaphore( &defEnvHndl->en_semaphore );
	defEnvHndl->en_initCount = max( 0, defEnvHndl->en_initCount - 1 );
	MUv_semaphore( &defEnvHndl->en_semaphore );
    }

    /*
    ** Shutdown API when all version 1 initializers have terminated
    ** and there are no active version 2 environments.
    */
    if ( ! defEnvHndl->en_initCount  &&
         IIapi_isQueEmpty( &IIapi_static->api_env_q ) )
    {
	QUEUE		*q;

	IIAPI_TRACE( IIAPI_TR_TRACE )
	    ( "IIapi_termAPI: shutting down API completely.\n" );

	/*
	** Free the default environment.
	*/
	IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default );
	IIapi_static->api_env_default = NULL;

	/*
	** Shutdown sub-systems.
	*/
	IIapi_termGCA();
	IIapi_termADF();

	IIAPI_TRACE( IIAPI_TR_INFO )( "IIapi_termAPI: API shutdown.\n" );
	IIAPI_TERMTRACE();

	/*
	** Free the remaining global resources.
	*/
	if (IIapi_static->api_ucode_ctbl)
	  MEfree (IIapi_static->api_ucode_ctbl);
	if (IIapi_static->api_ucode_cvtbl)
	  MEfree (IIapi_static->api_ucode_cvtbl);

	MEtls_destroy( &IIapi_static->api_thread, MEfree );
	MUr_semaphore( &IIapi_static->api_semaphore );
	MEfree( (PTR)IIapi_static );
	IIapi_static = NULL;
	last_term = TRUE;
    }

    return( last_term );
}
Ejemplo n.º 25
0
static II_VOID
checkBLOBSegment
( 
    IIAPI_STMTHNDL	*stmtHndl, 
    IIAPI_DESCRIPTOR	*descriptor,
    IIAPI_MSG_BUFF	*msgBuff 
)
{
    i4  indicator;
    i4  length = sizeof( indicator );

    /*
    ** We only check when we know it is safe to do so.
    ** We must be reading segments, but not purging.
    ** and we require the request to be complete to
    ** avoid scenarios to complicated to explain or
    ** properly handle.
    */
    if ( stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS  &&
         ! ( stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS )  &&
	 ! stmtHndl->sh_colFetch  &&  msgBuff->length >= length )
    {
	/*
	** Peak at the indicator.
	*/
	MECOPY_CONST_MACRO( msgBuff->data, length, (PTR)&indicator );

	if ( ! indicator )
	{
	    /*
	    ** We have the end-of-segments indicator.
	    ** Only consume it if the (optional) null
	    ** byte is also available (if not nullable,
	    ** the test is redundant).  The null byte
	    ** value is ignored (see description).
	    */
	    if ( descriptor->ds_nullable )  length++;

	    if ( msgBuff->length >= length )
	    {
		IIAPI_TRACE( IIAPI_TR_VERBOSE )
		    ( "checkBLOBSegment: found end-of-segments\n" );

		msgBuff->data += length;
		msgBuff->length -= length;

		/*
		** Since we have now finished the BLOB,
		** advance the column index to the next
		** column (wrap if finished all columns).
		** Since we check for sh_colFetch to be 
		** 0, we assume the gc_rowsReturned is
		** set properly and we are not in the
		** midst of a multi-row fetch.
		*/
		stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |=
								IIAPI_CI_AVAIL;
		if ( ++stmtHndl->sh_colIndex >= stmtHndl->sh_colCount )
		{
		    /* SD issue 142188; Bug 123159.
		    ** Decrement the row count when the tuple is
		    ** completed.
		    */
		    if ( stmtHndl->sh_flags & IIAPI_SH_CURSOR )  
			stmtHndl->sh_rowCount--;
		    stmtHndl->sh_colIndex = 0;
		}
		stmtHndl->sh_flags &= ~IIAPI_SH_MORE_SEGMENTS;
	    }
	}
    }

    return;
}
Ejemplo n.º 26
0
static STATUS
ns_validate( API_PARSE *parse, i4  *keyword )
{
    i4  i;

    /*
    ** Validate keywords.  This is a little bit more
    ** complicated than Netutil since we support the
    ** SERVER object and parameter markers for type.
    ** Keywords (except for type) cannot be provided
    ** through parameters.
    **
    ** Field syntax and semantics:
    **
    ** <function> <type> <object> [<value>...]
    **
    ** Function, type and object must be provided.
    ** Function cannot be provided in a parameter.  
    ** Type can be provided in a parameter.  Values 
    ** may be parameters and do not contain keywords.
    **
    ** The SERVER keyword may replace type (but not in 
    ** a parameter), and object (server class) may then 
    ** be provided in a parameter.  Otherwise, object 
    ** cannot be provided in a parameter.
    */
    if ( parse->field_count < 3 )  return( E_AP0010_INVALID_COLUMN_COUNT );

    if ( keyword[ API_FIELD_FUNC ] == INVALID_KEYWORD  ||
	 keyword[ API_FIELD_FUNC ] == API_KW_PARAM )
	return( E_AP0011_INVALID_PARAM_VALUE );
    else
	parse->opcode = keyword[ API_FIELD_FUNC ];

    if ( keyword[ API_FIELD_TYPE ] == INVALID_KEYWORD )
	return( E_AP0011_INVALID_PARAM_VALUE );

    if ( keyword[ API_FIELD_TYPE ] == API_KW_SERVER )
	if ( keyword[ API_FIELD_OBJ ] != INVALID_KEYWORD  &&
	     keyword[ API_FIELD_OBJ ] != API_KW_PARAM )
	    return( E_AP0011_INVALID_PARAM_VALUE );
	else
	{
	    parse->type = API_KW_PRIVATE;	/* Default for servers */
	    parse->object = API_KW_SERVER;
	}
    else  if ( keyword[ API_FIELD_OBJ ] == INVALID_KEYWORD  ||
	       keyword[ API_FIELD_OBJ ] == API_KW_PARAM )
	return( E_AP0011_INVALID_PARAM_VALUE );
    else
    {
	parse->type = keyword[ API_FIELD_TYPE ];
	parse->object = keyword[ API_FIELD_OBJ ];
    }

    /*
    ** Make sure enough fields have been provided
    ** (or will be provided through query parameters).
    ** Parameter count dependent on the function and
    ** object.  Optional parameters supported.
    */
    for( i = 0; i < ARRAY_SIZE( ns_parms ); i++ )
	if ( ns_parms[ i ].opcode == parse->opcode  &&
	     ns_parms[ i ].object == parse->object )
	{
	    parse->parms = &ns_parms[ i ];

	    if ( parse->field_count < ns_parms[ i ].parm_min  ||
		 parse->field_count > ns_parms[ i ].parm_max )
	    {
		return( E_AP0010_INVALID_COLUMN_COUNT );
	    }

	    break;
	}

    if ( i >= ARRAY_SIZE( ns_parms ) )  
    {
	/*
	** This shouldn't happen.
	*/
	IIAPI_TRACE( IIAPI_TR_FATAL )
	    ( "ns_validate: couldn't find parameter info for request\n" );

        return( E_AP0011_INVALID_PARAM_VALUE );
    }

    return( OK );
}
Ejemplo n.º 27
0
II_EXTERN II_VOID II_FAR II_EXPORT
IIapi_putColumns( IIAPI_PUTCOLPARM II_FAR *putColParm )
{
    IIAPI_STMTHNDL	*stmtHndl;
    II_ULONG		err_code;
    
    IIAPI_TRACE( IIAPI_TR_TRACE ) 
	( "IIapi_putColumns: sending tuple to server\n" );
    
    /*
    ** Validate Input parameters
    */
    if ( ! putColParm )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_putColumns: null putColumns parameters\n" );
	return;
    }
    
    putColParm->pc_genParm.gp_completed = FALSE;
    putColParm->pc_genParm.gp_status = IIAPI_ST_SUCCESS;
    putColParm->pc_genParm.gp_errorHandle = NULL;
    stmtHndl = (IIAPI_STMTHNDL *)putColParm->pc_stmtHandle;
    
    /*
    ** Make sure API is initialized
    */
    if ( ! IIapi_initialized() )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_putColumns: API is not initialized\n" );
	IIapi_appCallback( &putColParm->pc_genParm, NULL, 
			   IIAPI_ST_NOT_INITIALIZED );
	return;
    }

    if ( ! IIapi_isStmtHndl( stmtHndl )  ||  IIAPI_STALE_HANDLE( stmtHndl ) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_putColumns: invalid statement handle\n" );
	IIapi_appCallback( &putColParm->pc_genParm, NULL, 
			   IIAPI_ST_INVALID_HANDLE );
	return;
    }
    
    IIAPI_TRACE( IIAPI_TR_INFO ) 
	( "IIapi_putColumns: stmtHndl = %p\n", stmtHndl );
    
    IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl );
    
    if ( ! IIapi_validPColCount( stmtHndl, putColParm ) )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ("IIapi_putColumns: invalid count: %d (actual %d, index %d)\n",
	     (II_LONG)putColParm->pc_columnCount, 
	     (II_LONG)stmtHndl->sh_colCount,
	     (II_LONG)stmtHndl->sh_colIndex );

	if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, 
				 E_AP0010_INVALID_COLUMN_COUNT, 
				 II_SS21000_CARD_VIOLATION,
				 IIAPI_ST_FAILURE ) )
	    IIapi_appCallback( &putColParm->pc_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	else
	    IIapi_appCallback( &putColParm->pc_genParm, 
			       (IIAPI_HNDL *)stmtHndl, IIAPI_ST_FAILURE );
	return;
    }
    
    if ( (err_code = IIapi_validDataValue( putColParm->pc_columnCount, 
    					   &stmtHndl->sh_colDescriptor[ 
						stmtHndl->sh_colIndex ],
					   putColParm->pc_columnData )) != OK )
    {
	IIAPI_TRACE( IIAPI_TR_ERROR )
	    ( "IIapi_putColumns: column data conflicts with descriptor\n" );

	/*
	** We only issue a warning on data conflicts, but if the
	** warning can't be generated then abort the operation.
	*/
	if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, err_code, 
				 II_SS22500_INVALID_DATA_TYPE,
				 IIAPI_ST_WARNING ) )
	{
	    IIapi_appCallback( &putColParm->pc_genParm, NULL, 
			       IIAPI_ST_OUT_OF_MEMORY );
	    return;
    	}
    }
    
    stmtHndl->sh_colFetch = putColParm->pc_columnCount;

    IIapi_uiDispatch( IIAPI_EV_PUTCOLUMN_FUNC, 
		      (IIAPI_HNDL *)stmtHndl, (II_PTR)putColParm );

    return;
}