Exemple #1
0
bool
gcd_skip( GCD_CCB *ccb, u_i2 length )
{
    if ( length <= ccb->msg.msg_len )
	while( length )
	{
	    GCD_RCB	*rcb = (GCD_RCB *)ccb->msg.msg_q.q_next;
	    u_i2	len;

	    if ( (len = min( length, rcb->msg.msg_len )) )
	    {
		rcb->buf_ptr += len;
		rcb->buf_len -= len;
		rcb->msg.msg_len -= len;
		ccb->msg.msg_len -= len;
		length -= len;
	    }

	    if ( ! rcb->msg.msg_len )
	    {
		QUremove( &rcb->q );
		gcd_del_rcb( rcb );
	    }
	}

    return( ! length );
}
Exemple #2
0
GCD_CIB *
gcd_new_cib( u_i2 count )
{
    GCD_CIB	*cib = NULL;
    u_i2	len = sizeof( GCD_CIB ) + (sizeof(CONN_PARM) * (count - 1));

    if ( count < ARR_SIZE( GCD_global.cib_free ) )
	if (! (cib = (GCD_CIB *)QUremove(GCD_global.cib_free[count].q_next)))
	    if ( (cib = (GCD_CIB *)MEreqmem( 0, len, FALSE, NULL )) )
		cib->id = GCD_global.cib_total++;

    if ( ! cib )
	gcu_erlog(0, GCD_global.language, E_GC4808_NO_MEMORY, NULL, 0, NULL);
    else  
    {
	u_i4	id = cib->id;
	char	buff[16];

	MEfill( len, 0, (PTR)cib );
	cib->id = id;
	cib->parm_max = count;
	QUinit( &cib->caps );

	MOulongout( 0, (u_i8)cib->id, sizeof( buff ), buff );
	MOattach( MO_INSTANCE_VAR, GCD_MIB_DBMS, buff, (PTR)cib );

	GCD_global.cib_active++;

	if ( GCD_global.gcd_trace_level >= 6 )
	    TRdisplay( "%4d    GCD new CIB (%d)\n", -1, cib->id );
    }

    return( cib );
}
Exemple #3
0
bool
gcd_get_bytes( GCD_CCB *ccb, u_i2 length, u_i1 *ptr )
{
    if ( length <= ccb->msg.msg_len )
	while( length )
	{
	    GCD_RCB	*rcb = (GCD_RCB *)ccb->msg.msg_q.q_next;
	    u_i2	len;

	    if ( (len = min( length, rcb->msg.msg_len )) )
	    {
		MEcopy( (PTR)rcb->buf_ptr, len, (PTR)ptr );
		rcb->buf_ptr += len;
		rcb->buf_len -= len;
		rcb->msg.msg_len -= len;
		ccb->msg.msg_len -= len;
		ptr += len;
		length -= len;
	    }

	    if ( ! rcb->msg.msg_len )
	    {
		QUremove( &rcb->q );
		gcd_del_rcb( rcb );
	    }
	}

    return( ! length );
}
Exemple #4
0
/*
** Name: cleanup_queues
**
** Description:
**      Empty reamaining info in the merge and GCN queues.
**
** Input:
**
** Output:
**
** Returns:
**      VOID
**
** History:
**      15-Nov-2010 (Ralph Loen)
**          Created.
*/
void cleanup_queues()
{
    QUEUE *q;

    /*
    ** Empty information remaining in queues, if any.
    */
    for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = gcn_qhead.q_prev)
    {
        QUremove(q);
        MEfree((PTR)q);
    }

    for (q = merge_qhead.q_prev; q != &merge_qhead; q = merge_qhead.q_prev)
    {
        QUremove(q);
        MEfree((PTR)q);
    }
}
Exemple #5
0
void
gcadm_free_scb( GCADM_SCB *scb )
{
	
    /* remove scb from queue before free   */

     QUremove( &scb->q);  

    if ( scb->buffer )
	(*GCADM_global.dealloc_rtn)( (PTR)scb->buffer );
			 
    if ( scb )
	(*GCADM_global.dealloc_rtn)( (PTR)scb );
    
    return;
}
Exemple #6
0
static bool
copy_atom
( 
    GCD_CCB	*ccb, 
    u_i2	length, 
    void	(*func)( u_i1 *, u_i1 * ), 
    u_i1	*ptr
)
{
    if ( length <= ccb->msg.msg_len )
	while( length )
	{
	    GCD_RCB *rcb = (GCD_RCB *)ccb->msg.msg_q.q_next;

	    if ( rcb->msg.msg_len )
		if ( length > rcb->msg.msg_len )
		{
		    /*
		    ** Atomic values must not be split.
		    */
		    break;
		}
		else
		{
		    (*func)( rcb->buf_ptr, ptr );
		    rcb->buf_ptr += length;
		    rcb->buf_len -= length;
		    rcb->msg.msg_len -= length;
		    ccb->msg.msg_len -= length;
		    length = 0;
		}

	    if ( ! rcb->msg.msg_len )
	    {
		QUremove( &rcb->q );
		gcd_del_rcb( rcb );
	    }
	}

    return( ! length );
}
Exemple #7
0
GCD_CCB *
gcd_new_ccb( void )
{
    GCD_CCB	*ccb;

    if ( ! (ccb = (GCD_CCB *)QUremove( GCD_global.ccb_free.q_next )) )
	if ( (ccb = (GCD_CCB *)MEreqmem( 0, sizeof(GCD_CCB), FALSE, NULL )) )
	    ccb->id = GCD_global.ccb_total++;

    if ( ! ccb )
	gcu_erlog(0, GCD_global.language, E_GC4808_NO_MEMORY, NULL, 0, NULL);
    else
    {
	u_i4	id = ccb->id;

	MEfill( sizeof( GCD_CCB ), 0, (PTR)ccb );
	ccb->id = id;
	ccb->use_cnt = 1;
	ccb->max_buff_len = 1 << DAM_TL_PKT_MIN;
	ccb->tl.proto_lvl = DAM_TL_PROTO_1;
	ccb->xact.auto_mode = GCD_XACM_DBMS;
	ccb->api.env = NULL;
	QUinit( &ccb->q );
	QUinit( &ccb->rcb_q );
	QUinit( &ccb->gcc.send_q );
	QUinit( &ccb->msg.msg_q );
	QUinit( &ccb->msg.info_q );
	QUinit( &ccb->stmt.stmt_q );
	QUinit( &ccb->rqst.rqst_q );

	GCD_global.ccb_active++;
	QUinsert( &ccb->q, &GCD_global.ccb_q );

	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD new CCB (%d)\n", ccb->id, ccb->id );
    }

    return( ccb );
}
Exemple #8
0
static void 
gcadm_event( GCADM_RCB  *rcb )
{

   GCADM_SCB *scb=rcb->scb;

    if ( gcadm_active )
    {
	if ( GCADM_global.gcadm_trace_level >= 5 )
	    TRdisplay( "%4d   GCADM event: queueing event %s  \n",
		    scb->aid, events[ rcb->event ]);
	QUinsert( &rcb->q, GCADM_global.rcb_q.q_prev); 
	return;
    }

    gcadm_active = TRUE;
    gcadm_sm( rcb );

    while( ( rcb  = (GCADM_RCB  *)QUremove( GCADM_global.rcb_q.q_next )) )
    {
	if ( GCADM_global.gcadm_state != GCADM_ACTIVE )
	{
	    if ( GCADM_global.gcadm_trace_level >= 1 )
		TRdisplay( "%4d   GCADM event: ADM not active\n", -1 );
	    gcadm_free_rcb ( rcb );
	}
	else
	{
	    if( GCADM_global.gcadm_trace_level >= 5 )
		TRdisplay( "%4d   GCADM event: processing queued event %s \n",
			scb->aid, events[ rcb->event ]);
	    gcadm_sm( rcb );
	}
    }

    gcadm_active = FALSE;
    return;
}
Exemple #9
0
/******************************************************************************
** Name:
** 	MEfree.c
**
** Function:
** 	MEfree
**
** Arguments:
** 	void *	block;
**
** Result:
** 	Frees the block of memory pointed to by 'block'.
**
** 	Removes the block from the tag queue if appropriate.
**
** Returns:
**	STATUS: OK, ME_00_FREE, ME_FREE_FIRST
**
** Side Effects:
** 	None
**
** History:
**	21-mar-1996 (canor01)
**	    Free memory from calling process's heap.  Compact the
**	    heap after every several frees.
**	03-jun-1996 (canor01)
**	    Internally, store the tag as an i4 instead of an i2. This makes
**	    for more efficient code on byte-aligned platforms that do fixups.
**	08-aug-1999 (mcgem01)
**	    Changed longnat to i4.
**	08-feb-2001 (somsa01)
**	    Changed types of i_meactual and i_meuser  to be SIZE_TYPE.
**	21-jun-2002 (somsa01)
**	    Sync'ed up with UNIX. Rely on ME_NODE rather than a ptr UNION.
**	    Also, removed call to HeapCompact() logic.
**	05-Jul-2005 (drivi01)
**		Replaced HeapFree call with free.
**	11-May-2009 (kschendel) b122041
**	    Change pointer arg to void *, more appropriate.
** 	23-Sep-2009 (wonst02) Bug 122427
** 	    Fix possibly trashing memory (alloc'd by tag) by using taglist mutex
**
******************************************************************************/
STATUS
MEfree(void *block)
{
    register ME_NODE	*this;
    STATUS		rv = OK;

    if ( block == NULL )
	rv = ME_00_FREE;
    else 
    {
	this = (ME_NODE *)((char *)block - sizeof(ME_NODE));

	/*
	** assume block is legit if the node looks like it points to an
	** allocated block.
	*/
	if (this->MEaskedfor == 0)
	    rv = ME_NO_FREE;

	if (rv == OK)
	{
	    i_meactual -= this->MEsize;
	    i_meuser -= this->MEaskedfor;

	    if (this->MEtag)
	    {
	    	CS_synch_lock(&MEtaglist_mutex);	  
		QUremove((QUEUE *)this);
		CS_synch_unlock(&MEtaglist_mutex);
	    }

	    free((char *)this);
	}
    }

    return(rv);
}
Exemple #10
0
void
gcd_del_cib( GCD_CIB *cib )
{
    GCD_CAPS	*caps;
    char	buff[16];
    u_i2	i;

    GCD_global.cib_active--;

    MOulongout( 0, (u_i8)cib->id, sizeof( buff ), buff );
    MOdetach( GCD_MIB_DBMS, buff );

    while( (caps = (GCD_CAPS *)QUremove( cib->caps.q_next )) )
    {
	MEfree( caps->data );
	MEfree( (PTR)caps );
    }

    if ( cib->database )  MEfree( (PTR)cib->database );
    if ( cib->username )  MEfree( (PTR)cib->username );
    if ( cib->password )  MEfree( (PTR)cib->password );
    for( i = 0; i < cib->parm_cnt; i++ )  MEfree( (PTR)cib->parms[i].value );

    if ( GCD_global.gcd_trace_level >= 6 )
	TRdisplay( "%4d    GCD del CIB (%d)\n", -1, cib->id );

    if ( cib->parm_max < ARR_SIZE( GCD_global.cib_free ) )
	QUinsert( &cib->q, GCD_global.cib_free[ cib->parm_max ].q_prev );
    else
    {
	MEfree( (PTR)cib );
	GCD_global.cib_total--;
    }

    return;
}
Exemple #11
0
PTR
MEreqmem(
	u_i2	tag,
	SIZE_TYPE size,
	bool	zero,
	STATUS	*status)
{
    PTR	block=NULL;
    register ME_NODE *node;		/* the node to return */
    register ME_NODE *start;		/* for searching free list */
    register ME_NODE *this;		/* block to get node from */
    register ME_NODE *frag;		/* fragment block */
    
    ME_NODE 	*tmp;			/* not register for MEadd */
    SIZE_TYPE	nsize;			/* nsize node to obtain */
    SIZE_TYPE	fsize;			/* size of 'this' fragment block */
    SIZE_TYPE	newstuff;		/* size to add to process, or  0 */
    SIZE_TYPE	prev_actual;		/* rescan free list? */
    SIZE_TYPE	alloc_pages;
    CL_ERR_DESC	err_code;

    STATUS	MEstatus = OK;
    
    i_meuser += size;
    
    if (!size)
	MEstatus = ME_NO_ALLOC;
    
    if( !MEsetup )
        MEinitLists();
    
    /*
    **	Try to do the allocation.
    */
    if( MEstatus == OK )
    {
	nsize = SIZE_ROUND( size );
	/*
	** Get memory with malloc().
	*/
	if( MEadvice == ME_USER_ALLOC )
	{
	    if( (node = (ME_NODE *)malloc( nsize )) == NULL )
	    	MEstatus = ME_GONE;
	}
	/*
	** Get block from private free list.
	*/
	else
	{
# ifdef OS_THREADS_USED
	    CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */

	    /*
	    **  Look on free list for 1st block big enough
	    **  to hold request.  This linear search can be slow.
	    */
	    start = (ME_NODE *)&MEfreelist;
	    this = MEfreelist.MEfirst;
	    while ( this != NULL && this != start && this->MEsize < nsize )
		this = this->MEnext;
	    
	    if( this == NULL )
	        MEstatus = ME_CORRUPTED;
	    
	    /*
	    ** At this point, we are in one of three states:
	    ** 1)  Corrupted memory; MEstatus != OK
	    ** 2)  this is good node, this != start
	    ** 3)  No good node; this == start;
	    */
	    if ( MEstatus == OK )
	    {
		/*
		** If nothing on free list is big enough
		** get one or more standard blocks from system,
		** take what is needed and add remainder
		** to free list.
		*/
		if (this != start)
		{
		    /* take right off the free list */
		    newstuff = 0;
		}
		else	/* this == start */
		{
		    /*
		     * Expand the free list by calling getpages
		     * newstuff holds the number of pages needed
		     */
		    newstuff = (nsize + ME_MPAGESIZE-1)/ME_MPAGESIZE;
		    /* if first time allocation, get enough for MO overhead */
		    if ( (prev_actual = i_meactual) == (SIZE_TYPE) 0 )
			newstuff += 4;
# ifdef OS_THREADS_USED
	            CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    MEstatus = MEget_pages(ME_SPARSE_MASK, newstuff, NULL, 
			(PTR *)&tmp, &alloc_pages, &err_code);
# ifdef OS_THREADS_USED
	            CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    if (MEstatus == OK)
		    {
			/* now we need to find where to put this new memory
			   on the sorted free list - we search in reverse */
			tmp->MEsize = newstuff * ME_MPAGESIZE;
			this = MEfreelist.MElast;
			while (start != this && this != NULL &&
			       this > tmp)
			    this = this->MEprev;
			if (this != start && NEXT_NODE(this) == tmp)
			{
			    this->MEsize += tmp->MEsize;
			}
			else
			{
			    (void)QUinsert( (QUEUE *) tmp, (QUEUE *)this );
			    this = tmp;
			}
			if (this->MEnext != start &&
			    NEXT_NODE(this) == this->MEnext)
			{
			    this->MEsize += this->MEnext->MEsize;
			    (void)QUremove( (QUEUE *) this->MEnext);
			}
			/*
			** While the free list mutex was released, another
			** thread may have freed up a big enough piece of
			** memory for our needs, or may have extended the
			** free list.
			** If that's the case, research the free list;
			** we'll find either a right-sized node or 
			** the new memory we just added to the free list.
			*/
			if ( prev_actual != i_meactual )
			{
			    this = MEfreelist.MEfirst;
			    while ( this != NULL && this != start && this->MEsize < nsize )
				this = this->MEnext;
		
			    if( this == NULL )
				MEstatus = ME_CORRUPTED;
			}
		    }
		    else
			if (MEstatus == ME_OUT_OF_MEM)
			    MEstatus = ME_GONE;
		}

		/*
		** At this point, we can be in two states.
		** 1)  Corrupted memory, MEstatus != OK
		** 2)  'this' is an OK node from the free list.
		*/
		
		if ( MEstatus == OK )
		{
		    node = this;
		    
		    /*
		    ** if this is correct size or would
		    **   leave useless block in chain
		    **	just move block to allocated list
		    ** else
		    **	grab what is needed from 'this'
		    **	  block and then update 'this'
		    */
		    
		    fsize = node->MEsize - nsize;
		    if ( fsize <= sizeof(ME_NODE) )
		    {
			(void)QUremove( (QUEUE *) node );
			
			/* fudge size in node to eat leftover amount. */
			fsize = 0;
			nsize = node->MEsize;
		    }
		    else	/* make fragment block */
		    {
			/*
			** Make a leftover block after the
			** allocated space in node, in 'this'
			*/
			frag = (ME_NODE *)((char *) node + nsize );
			frag->MEsize = fsize;
			frag->MEtag = 0;
			
			/* remove node, add fragment to free list */
			(void)QUremove( (QUEUE *) node );
			MEstatus = MEfadd( frag, FALSE );
			
		    }  /* fragment left over */
		    /* Increment meactual while mutex held */
		    i_meactual += nsize;
		}  /* Got a node */
	    }  /* free list search OK */
# ifdef OS_THREADS_USED
	    CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
	}  /* ME_USER_ALLOC */
	
	/*
	** At this point we are in one of two states:
	** 1.  Corrupted, MEstatus != OK.
	** 2.  Have a 'node' to use, from freelist or malloc.
	**     The freelist is consistant, but the allocated list is
	**     not setup for the node. "nsize" is the actual size of "node".
	*/
	
	if( MEstatus == OK )
	{
	    /* splice into allocated object queue */
	    if (0 == tag)
	    {
# ifdef OS_THREADS_USED
	    	CS_synch_lock( &MElist_mutex );
# endif /* OS_THREADS_USED */
	    	(void)QUinsert( (QUEUE *) node, (QUEUE *) MElist.MElast );
# ifdef OS_THREADS_USED
		CS_synch_unlock( &MElist_mutex );
# endif /* OS_THREADS_USED */
	    }
	    else
	    {
		IIME_atAddTag(tag, node);
	    }
	    /* Set values in block to be returned */
	    node->MEtag = tag;
	    node->MEsize = nsize;
	    node->MEaskedfor = size;
	    
	    /* Fill in the returned pointer */
	    block = (PTR)((char *)node + sizeof(ME_NODE));
	    
	    if (zero)
		MEfill( (nsize - sizeof(ME_NODE)), 0, block);
	}  /* got node OK */
    }
    if (status != NULL)
	*status = MEstatus;
    if (MEstatus != OK)
	return((PTR)NULL);
    else
	return(block);
}
Exemple #12
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 );
}
Exemple #13
0
GCD_RCB *
gcd_new_rcb( GCD_CCB *ccb, i2 len )
{
    GCD_RCB *rcb;

    /*
    ** Adjust length to reserve header space.
    **
    ** The majority of RCB allocations are for default
    ** buffer sizes or no buffers.  Re-use free RCB with
    ** same buffer size if available.
    */
    if ( len == 0 )
	rcb = (GCD_RCB *)QUremove( GCD_global.rcb_q.q_next );
    else  if ( len < 0 )
    {
	/*
	** Use the negotiated TL protocol buffer size from 
	** the CCB (TL header length already included) and
	** provide space for the NL header.
	*/
	len = ccb->max_buff_len + (u_i2)GCD_global.nl_hdr_sz;
	rcb = (GCD_RCB *)QUremove( ccb->rcb_q.q_next );
    }
    else
    {
	/*
	** NL protocol restricts the size of buffers which
	** may be sent.  Provide space for TL header by
	** increasing requested buffer length.  Space is
	** also provided for the NL header.
	*/
	len = min( len + (u_i2)GCD_global.tl_hdr_sz, ccb->max_buff_len ) +
	      (u_i2)GCD_global.nl_hdr_sz;
	rcb = NULL;	/* RCB must be allocated */
    }

    if ( rcb )
	MEfill( sizeof( GCD_RCB ), 0, rcb );
    else
    {
	rcb = (GCD_RCB *)MEreqmem( 0, sizeof( GCD_RCB ) + len, TRUE, NULL );

    	if ( ! rcb )
	{
	    gcu_erlog( 0, GCD_global.language, 
	    	       E_GC4808_NO_MEMORY, NULL, 0, NULL );
	    return( NULL );
	}

	if ( GCD_global.gcd_trace_level >= 6 )
	    TRdisplay( "%4d    GCD new RCB[%d] (%p)\n", ccb->id, len, rcb );
    }

    rcb->ccb = ccb;

    if ( len )
    {
	rcb->buffer = (u_i1 *)rcb + sizeof( GCD_RCB );
	rcb->buf_max = (u_i2)len;
	gcd_init_rcb( rcb );
    }

    return( rcb );
}
Exemple #14
0
void IIodbc_timeOutThread()
{
    QUEUE *q, *p, *pq;
    pENV penv;
    pDBC pdbc;
    RETCODE rc;
    SYSTIME expire_time;
    TM_STAMP stamp;
    char stampStr[TM_SIZE_STAMP];

    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
        ("IIodbc_timeOutThread() with timeout %d\n", IIodbc_cb.timeout);
    while(TRUE)
    {
        /*
        ** Search the pool every thirty seconds and check for expired
        ** connections.  Force disconnect and free from the pool
        ** if the connection handle has passed the expiration time.  
        ** Note that the CLI and driver connection handles are not
        ** freed.  
        */
        PCsleep(30000);
        TMget_stamp(&stamp);
        TMstamp_str(&stamp, stampStr);
        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
            ("IIodbc_timeOutThread woke up at %s\n", stampStr);
        TMnow(&expire_time);
        
        if (IIodbc_cb.pooling == DRIVER_POOL)
        {
            applyLock(SQL_HANDLE_IIODBC_CB, NULL);
            for (q = IIodbc_cb.pool_q.q_prev; q!= &IIodbc_cb.pool_q;
                q = p)
            {
                ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                    ("IIodbc_timeOutThread: driver pool count is %d\n", 
                    IIodbc_cb.pool_count);
                p = q->q_prev;
                pdbc = (pDBC)((pPOOL)q)->pdbc;
                ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                    ("IIodbc_timeOutThread: found conn handle %p with time diff %d\n",pdbc,
                    expire_time.TM_secs - pdbc->expire_time.TM_secs);
                if (expire_time.TM_secs - pdbc->expire_time.TM_secs > 
                    IIodbc_cb.timeout)
                {
                    /*
                    **  Note that the connection handle is not freed, only
                    **  removed from the pool. 
                    */
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("IIodbc_timeOutThread: EXPIRED.  pdbc time is %d vs %d\n",
                        pdbc->expire_time.TM_secs, expire_time.TM_secs);
                    rc = IIDisconnect(pdbc->hdr.driverHandle);
                    QUremove(q);
                    MEfree((PTR)q);
                    IIodbc_cb.pool_count -= 1;
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("new pool count is %d\n",IIodbc_cb.pool_count);
                    applyLock(SQL_HANDLE_DBC, pdbc);
                    pdbc->hdr.state = C2;
                    releaseLock(SQL_HANDLE_DBC, pdbc);
                }
            }
            releaseLock(SQL_HANDLE_IIODBC_CB, NULL);
        }
        else
        {
            for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q;
                q = q->q_prev)
            {
                penv = (pENV)q;
                TRdisplay("Found env handle %p\n",penv);
                applyLock(SQL_HANDLE_ENV, penv);
                for (pq = penv->pool_q.q_prev; pq != &penv->pool_q;
                    pq = p)
                {
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("Env pool count is %d\n",penv->pool_count);
                    p = q->q_prev;
                    pdbc = (pDBC)((pPOOL)pq)->pdbc;
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("IIodbc_TimeOutThread: Found conn handle %p with time diff %d\n",pdbc,
                        expire_time.TM_secs - pdbc->expire_time.TM_secs);
                    if (expire_time.TM_secs - pdbc->expire_time.TM_secs
                        > 1)
                    {
                        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                            ("IIodbc_timeOutThread: EXPIRED.  pdbc time is %d vs %d\n",
                            pdbc->expire_time.TM_secs,   
                            expire_time.TM_secs);
                        rc = IIDisconnect(pdbc->hdr.driverHandle);
                        QUremove(q);
                        MEfree((PTR)q);
                        penv->pool_count -= 1;
                        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                            ("IIodbc_timeOutThread: new pool count is %d\n",
                            penv->pool_count);
                    }
                }
                releaseLock(SQL_HANDLE_ENV, penv);
            } /* for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q;
                q = q->q_prev) */
        } /* if (IIodbc_cb.pooling == DRIVER_POOL) */
    } /* while (TRUE) */
}
Exemple #15
0
void
gcd_del_ccb( GCD_CCB *ccb )
{
    if ( ccb->use_cnt )  ccb->use_cnt--;

    if ( ccb->use_cnt )
    {
	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD del CCB (use count %d)\n", 
		       ccb->id, ccb->use_cnt );
    }
    else
    {
	GCD_RCB *rcb;
	GCD_SCB *scb;
	QUEUE	 *q;

	QUremove( &ccb->q );
	GCD_global.ccb_active--;
	if ( ccb->qry.crsr_name )  MEfree( (PTR)ccb->qry.crsr_name );
	if ( ccb->qry.schema_name )  MEfree( (PTR)ccb->qry.schema_name );
	if ( ccb->qry.proc_name )  MEfree( (PTR)ccb->qry.proc_name );
	if ( ccb->qry.qtxt_max )  MEfree( (PTR)ccb->qry.qtxt );
	if ( ccb->rqst.rqst_id0 )  MEfree( (PTR)ccb->rqst.rqst_id0 );
	if ( ccb->rqst.rqst_id1 )  MEfree( (PTR)ccb->rqst.rqst_id1 );
	if ( ccb->client_user )  MEfree( (PTR)ccb->client_user );
	if ( ccb->client_host )  MEfree( (PTR)ccb->client_host );
	if ( ccb->client_addr )  MEfree( (PTR)ccb->client_addr );
	gcd_free_qdata( &ccb->qry.svc_parms );
	gcd_free_qdata( &ccb->qry.qry_parms );
	gcd_free_qdata( &ccb->qry.all_parms );

	/*
	** Free control blocks and request queues.
	*/
	if ( ccb->cib )  gcd_del_cib( ccb->cib );

	if ( ccb->xact.savepoints )  gcd_release_sp( ccb, NULL );

	if ( ccb->msg.xoff_pcb )
	    gcd_del_pcb( (GCD_PCB *)ccb->msg.xoff_pcb );

	if ( ccb->gcc.abort_rcb )
	    gcd_del_rcb( (GCD_RCB *)ccb->gcc.abort_rcb );

	while( (scb = (GCD_SCB *)QUremove( ccb->stmt.stmt_q.q_next )) )
	{
	    gcd_free_qdata( &scb->column );
	    MEfree( (PTR)scb );
	}

	while( (rcb = (GCD_RCB *)QUremove( ccb->gcc.send_q.q_next )) )
	    gcd_del_rcb( rcb );

	while( (rcb = (GCD_RCB *)QUremove( ccb->msg.msg_q.q_next )) )
	    gcd_del_rcb( rcb );

	while( (rcb = (GCD_RCB *)QUremove( ccb->msg.info_q.q_next )) )
	    gcd_del_rcb( rcb );

	/* Free RCB must be physically freed */
	while( (rcb = (GCD_RCB *)QUremove( ccb->rcb_q.q_next )) )
	    gcd_free_rcb( rcb );

	while( (q = QUremove( ccb->rqst.rqst_q.q_next )) )
	    MEfree( (PTR)q );

	/*
	** Save CCB on free queue.
	*/
	QUinsert( &ccb->q, GCD_global.ccb_free.q_prev );

	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD del CCB (%d)\n", ccb->id, ccb->id );
    }

    return;
}
Exemple #16
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_SAVEPTHNDL	*savePtHndl;
    IIAPI_SAVEPTPARM    *savePtParm;
    IIAPI_STATUS        status = OK;
    II_BOOL             success = TRUE;
    char		queryText[ 64 ];

    switch( action )
    {
        case NS_TA_REMC :
	    /*
	    ** Remember callback.
	    */
	    tranHndl->th_callback = TRUE;
	    tranHndl->th_parm = (IIAPI_GENPARM *)parmBlock;
	    break;

	case NS_TA_DELH :
	    /*
	    ** Mark handle for deletion.
	    */
	    QUremove( (QUEUE *)tranHndl );
	    sm_hndl->hd_delete = TRUE;
	    break;

	case NS_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 NS_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 );

            /*
            ** We must return the failure here rather
            ** than following the normal exit route
            ** to ensure that the transaction handle
            ** callback does not get made.
            */
            return( FALSE );

	case NS_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 );
	    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 );
}
Exemple #17
0
STATUS
MEfadd(
	ME_NODE	*block,
	i4 releasep)
{
    register ME_NODE *this;
    register ME_NODE *start;
    register ME_NODE *nextblk;	/* 1st address after end of 'block' */
    STATUS  MEstatus;

    MEstatus = OK;

    if ( block == NULL )
    {
	MEstatus = ME_00_PTR;
    }
    else if ( OUT_OF_DATASPACE(block) )
    {
	MEstatus = ME_OUT_OF_RANGE;
    }
    else
    {

	nextblk = NEXT_NODE(block);

	/*
	** The freelist IS sorted.  We might be able to take
	** advantage of this to speed up this linear search.
	** In practice the freelist is usually much
	** smaller than the allocated list, so it might not
	** really matter (daveb).
	*/

	/* adding inside existing freelist */
	start = (ME_NODE *)&MEfreelist;
	this = MEfreelist.MEfirst;

	while ( this != NULL && this != start && this < nextblk )
	    this = this->MEnext;

	if( this == NULL )
	    MEstatus = ME_CORRUPTED;

	/*
	** this->MEprev points to free node before 'block', the one
	** to free.  this points to the block in the free
	** list following 'block' to free.
	*/
	if ( MEstatus == OK )
	{
	    block->MEaskedfor = 0;
	    (void)QUinsert( (QUEUE *) block, (QUEUE *) this->MEprev );

	    /* Coalesce backwards until this is the start of the queue */
	    this = block;
	    while( this->MEprev != start &&
                 this->MEprev != this && NEXT_NODE(this->MEprev) == this )
	    {
		block = this->MEprev;
		block->MEsize += this->MEsize;
		(void)QUremove( (QUEUE *) this );
		this = block;
	    }

	    /* Coalesce forwards until the queue goes back to the start */
	    while( this->MEnext != start && NEXT_NODE(this) == this->MEnext )
	    {
		this->MEsize += this->MEnext->MEsize;
		(void)QUremove( (QUEUE *) this->MEnext );
	    }
	}
    }
			
    return(MEstatus);
}
Exemple #18
0
/*{
** Name:	IIME_ftFreeTag	- Free all allocated memory for a tag.
**
** Description:
**	This routine is called by MEtfree to free all the allocated 
**	memory for a tag.
**
**	It works by finding the METAGNODE for the tag in the hash table
**	and then traversing the QUEUE of allocated blocks freeing
**	each block.
**
** Inputs:
**	tag		The tag whose memory is to be freed.
**
** Outputs:
**	Returns:
**		OK if all the allocated memory for the tag was freed.
**		ME_NO_TFREE if the tag does not have a record in the hash table.
**		other failure status if the nodes can't be freed.
**
** Side Effects:
**	Will return the METAGNODE for the tag to freelist.
**
** History:
**	5-dec-1989 (Joe)
**	    First Written
**      30-May-96 (stial01)
**          New advice ME_TUXEDO_ALLOC should behave like ME_INGRES_ALLOC
**	12-feb-1997 (canor01)
**	    Initialize local MEstatus.
**      27-Jan-1999 (fanra01)
**          Add thread alloc case for tag free.  Otherwise our memory is
**          returned to the system heap causing wonderfully esoteric execution.
*/
STATUS
IIME_ftFreeTag(
	i4	tag )
{
    register METAGNODE	**first;
    STATUS MEstatus = OK;

# ifdef OS_THREADS_USED
    CS_synch_lock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
    for (first = &(htab[tag%256]);
	 *first != NULL;
	 first = &((*first)->met_hash))
    {
	if ((*first)->met_tag == tag)
	{
	    register ME_NODE	*this;
	    register ME_NODE	*next;
	    register METAGNODE	*freenode;

	    for (this = (*first)->met_list.MEfirst;
		 this != NULL && this != (ME_NODE *) &((*first)->met_list);)
	    {
		next = this->MEnext;
		if ( MEstatus == OK )
		{
		    i_meactual -= this->MEsize;
		    i_meuser -= this->MEaskedfor;
		    (void)QUremove( (QUEUE *) this );
		    if( (MEadvice == ME_INGRES_ALLOC )
			|| (MEadvice == ME_INGRES_THREAD_ALLOC)
			|| (MEadvice == ME_TUXEDO_ALLOC) )
		    {
# ifdef OS_THREADS_USED
			CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
			MEstatus = MEfadd(this, TRUE);
# ifdef OS_THREADS_USED
			CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    }
		    else
			free( (char *)this );
		}
		if (MEstatus == OK)
		    this = next;
		else
		    break;
	    }
	    freenode =  *first;
	    *first = freenode->met_hash;
	    freenode->met_hash = freelist;
	    freelist = freenode;
# ifdef OS_THREADS_USED
	    CS_synch_unlock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
	    return MEstatus;
	}
    }
# ifdef OS_THREADS_USED
    CS_synch_unlock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
    return ME_NO_TFREE;
}
Exemple #19
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 );
}