Esempio n. 1
0
/*{
** Name: opx_init	- initialize the AIC and PAINE handlers
**
** Description:
**      This routine will inform SCF of the AIC and PAINE handlers
**
** Inputs:
**	opf_cb				    - ptr to caller's control block
**
** Outputs:
**	Returns:
**	    E_DB_OK
**          E_DB_ERROR - if initialization failed
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      31-mar-87 (seputis)
**          initial creation
**      12-dec-88 (seputis)
**	    return E_DB_OK
[@history_template@]...
*/
DB_STATUS
opx_init(
	OPF_CB		*opf_cb)
{
    SCF_CB                 scf_cb;
    DB_STATUS              scf_status;

    scf_cb.scf_length = sizeof(scf_cb);
    scf_cb.scf_type = SCF_CB_TYPE;
    scf_cb.scf_facility = DB_OPF_ID;
    scf_cb.scf_ptr_union.scf_afcn = opx_call;
    scf_cb.scf_session = DB_NOSESSION;
    scf_cb.scf_nbr_union.scf_amask = SCS_PAINE_MASK;
    scf_status = scf_call(SCS_DECLARE, &scf_cb);
# ifdef E_OP0090_PAINE
    if (DB_FAILURE_MACRO(scf_status))
    {
	opx_rverror( opf_cb, scf_status, E_OP0090_PAINE,
	    scf_cb.scf_error.err_code);
	return(E_DB_ERROR);
    }
# endif
    scf_cb.scf_nbr_union.scf_amask = SCS_AIC_MASK;
    scf_status = scf_call(SCS_DECLARE, &scf_cb);
# ifdef E_OP0091_AIC
    if (DB_FAILURE_MACRO(scf_status))
    {
	opx_rverror( opf_cb, scf_status, E_OP0091_AIC,
	    scf_cb.scf_error.err_code);
	return(E_DB_ERROR);
    }
# endif
    return(E_DB_OK);
}
Esempio n. 2
0
/*{
** Name: ops_unlock	- release exclusive access to server control block
**
** Description:
{@comment_line@}...
**
** Inputs:
[@PARAM_DESCR@]...
**
** Outputs:
[@PARAM_DESCR@]...
**	Returns:
**	    {@return_description@}
**	Exceptions:
**	    [@description_or_none@]
**
** Side Effects:
**	    [@description_or_none@]
**
** History:
**	09-Oct-1998 (jenjo02)
**	    Removed SCF semaphore functions, inlining the CS calls instead.
[@history_template@]...
*/
DB_STATUS
ops_unlock(
    OPF_CB             *opf_cb,
    SCF_SEMAPHORE      *semaphore)
{
    STATUS		status;

    status = CSv_semaphore(semaphore);

    if (status != OK)
    {
# ifdef E_OP0092_SEMWAIT
        opx_rverror( opf_cb, E_DB_ERROR, E_OP0092_SEMWAIT, status);
# endif
        return(E_DB_ERROR);
    }
    return(E_DB_OK);
}
Esempio n. 3
0
/*{
** Name: ops_exlock	- exclusive access to OPF server control block
**
** Description:
**      Get semaphore to have single thread access to update OPF
**      structures including OPF server control block
**
** Inputs:
**      opf_cb                          opf control block
**      semaphore                       ptr to OPF semaphore
**
** Outputs:
**	Returns:
**
**	Exceptions:
**
** Side Effects:
**	    gets lock on OPF semaphore
**
** History:
**      20-jul-93 (ed)
**          changed name ops_lock for solaris, due to OS conflict
**	09-Oct-1998 (jenjo02)
**	    Removed SCF semaphore functions, inlining the CS calls instead.
[@history_line@]...
[@history_template@]...
*/
DB_STATUS
ops_exlock(
    OPF_CB             *opf_cb,
    SCF_SEMAPHORE      *semaphore)
{
    STATUS		status;

    /* First, wait to get exclusive access to the server control block */
    status = CSp_semaphore(1, semaphore); 	/* exclusive */

    if (status != OK)
    {
# ifdef E_OP0092_SEMWAIT
        opx_rverror( opf_cb, E_DB_ERROR, E_OP0092_SEMWAIT, status);
# endif
        return(E_DB_ERROR);
    }
    return(E_DB_OK);
}
Esempio n. 4
0
/*{
** Name: opx_verror	- this routine will report another facility's error
**
** Description:
**      This routine will report an error from another facility
**      optimizer error.  It will check the status and see the error
**      is recoverable.  The routine will not return if the status is fatal
**      but instead generate an internal exception and
**      exit via the exception handling mechanism.  The error code will be
**      placed directly in the user's calling control block.  A ptr to this
**      block was placed in the session control block (which can be requested
**      from SCF)
**
** Inputs:
**      error                           optimizer error code to report
**      facility                        facility's error code
**      status                          facility's return status
**
** Outputs:
**	Returns:
**	    VOID
**	Exceptions:
**	    - internal exception generated
**
** Side Effects:
**	    the exception handling routines are responsible for
**          deallocating OPF resources bound to this session.
**
** History:
**	3-jul-86 (seputis)
**          initial creation
**	28-jan-91 (seputis)
**          added support for OPF ACTIVE flag
**	30-apr-92 (bryanp)
**	    Translate E_RD002A_DEADLOCK to E_OP0010_RDF_DEADLOCK.
[@history_line@]...
*/
VOID
opx_verror(
	DB_STATUS          status,
	OPX_ERROR          error,
	OPX_FACILITY       facility)
{
    OPS_CB              *opscb;			/* ptr to session control block
                                                ** for this optimization */
    opscb = ops_getcb();
    opscb->ops_retstatus = status;		/* save status code */
    if (facility == E_RD002A_DEADLOCK)
	error = E_OP0010_RDF_DEADLOCK;
    if ((facility == E_RD002B_LOCK_TIMER_EXPIRED)
	&&
	(opscb->ops_smask & OPS_MCONDITION))
    {
	error = E_OP000D_RETRY;			/* when an attempt is made to
						** report the RDF timeout error
						** then it should be translated
						** into a retry error, since an
						** undetected deadlock may have
						** occurred due to the ACTIVE flag */
	opscb->ops_server->opg_sretry++;	/* track number of retrys */
	opx_vrecover(status, E_OP000D_RETRY, facility); /* this routine will not
						** return */
    }
    else
	opx_rverror(opscb->ops_callercb, status, error, facility); 

    if (DB_SUCCESS_MACRO(status))
    {
	return;					/* return if error is not
                                                ** serious */
    }
    EXsignal( (EX)EX_JNP_LJMP, (i4)1, (long)error); /* signal an optimizer long
                                                ** jump with error code */
}
Esempio n. 5
0
/*{
** Name: ops_deallocate	- deallocate resources for an optimization
**
** Description:
**      This routine will deallocate the resources used for an optimization.
**      Resources include any memory requested from the optimizer memory pool
**      and any RDF cache objects which were locked in the global range
**      table
**
** Inputs:
**      global                          ptr to global state variable
**      report                          TRUE if errors should be reported
**                                      via the user's control block.
**      partial_dbp                     partial deallocation required for
**                                      statement within a procedure
**
** Outputs:
**	Returns:
**	    VOID
**	Exceptions:
**	    none
**
** Side Effects:
**	    memory resources released, RDF unfixed, 
**          QSF query tree memory released
**
** History:
**	29-jun-86 (seputis)
**          initial creation
**	8-nov-88 (seputis)
**          if no query run trace point is set then destroy the QP since
**	    SCF assumes optimizer cleans up after error
**	8-nov-88 (seputis)
**          turn off CPU accounting if was off originally
**	28-jan-91 (seputis)
**	    added support for OPF ACTIVE flag
**      20-jul-93 (ed)
**	    changed name ops_lock for solaris, due to OS conflict
**	29-jul-93 (andre)
**	    rdr_types_mask must be initialized (to RDR_RELATION) before
**	    calling RDF_UNFIX.  Otherwise RDF may end up complaining because we
**	    ask it to destroy a relation cache entry while RDR_PROCEDURE bit is
**	    set.
**	12-aug-93 (swm)
**	    Cast first parameter of CSaltr_session() to CS_SID to match
**	    revised CL interface specification.
**	02-Jun-1997 (shero03)
**	    Update the saved rdf_info_block after calling RDF.
**      02-Aug-2001 (hanal04) Bug 105360 INGSRV 1505
**          Plug the RDF memory leak introduced by inkdo01's new
**          function oph_temphist().
**	17-Dec-2003 (jenjo02)
**	    Added (CS_SID)NULL to CScnd_signal prototype.
**	6-Feb-2006 (kschendel)
**	    Fix some squirrely looking code that purported to avoid dangling
**	    references, but didn't really.  (No symptoms known.)
**	14-nov-2007 (dougi)
**	    Add support for cached dynamic query plans.
**	20-may-2008 (dougi)
**	    Add support for table procedures.
**	29-may-2009 (wanfr01)    Bug 122125
**	    Need to add dbid to cache_dynamic queries for db uniqueness
*/
VOID
ops_deallocate(
	OPS_STATE          *global,
	bool               report,
	bool               partial_dbp)
{
    DB_STATUS           finalstatus;	/* this status is returned to the user
                                        ** - it will contain the first error
                                        ** during resource deallocation
                                        */
    DB_ERROR            error;          /* error code from offending facility
                                        */

    finalstatus = E_DB_OK;
    error.err_code = 0;

    {    /* close any fixed RDF objects - deallocate prior to closing the
         ** global memory stream 
         */

	OPV_IGVARS             gvar;	    /* index into global range variable
                                            ** table */
	OPV_GRT                *gbase;	    /* ptr to base of array of ptrs
                                            ** to global range table elements
                                            */
	OPV_IGVARS	       maxgvar;	    /* number of global range table
                                            ** elements allocated
                                            */
	RDF_CB                 *rdfcb;	    /* ptr to rdf control block used
                                            ** unfix the relation info */
	OPV_GBMVARS            *rdfmap;     /* ptr to map of global range
                                            ** variables which have RDF info
                                            ** fixed */

	gbase = global->ops_rangetab.opv_base;
        maxgvar = global->ops_rangetab.opv_gv;
	rdfcb = &global->ops_rangetab.opv_rdfcb;
        rdfmap = &global->ops_rangetab.opv_mrdf;

	/*
	** rdr_types_mask needs to be initialized - since we will be unfixing
	** relation entries, RDR_RELATION seems like a good choice, although 0
	** would suffice as well
	*/
	rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION;
	
	if (global->ops_cstate.opc_relation)
	{   /* OPC allocates a RDF descriptor for cursors so deallocate
            ** if this is the case */
	    DB_STATUS	   opcrdfstatus; /* RDF return status */

	    rdfcb->rdf_info_blk = global->ops_cstate.opc_relation;
	    opcrdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb );
	    if ( (DB_FAILURE_MACRO(opcrdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
	    {
		finalstatus = opcrdfstatus;
		error.err_code = rdfcb->rdf_error.err_code;
	    }
	    global->ops_cstate.opc_relation = NULL;
	}
	if (maxgvar)
	{
	    for ( gvar = -1; 
		 (gvar = BTnext((i4)gvar, (char *)rdfmap, (i4)maxgvar)) >=0;)
	    {
		OPV_GRV             *gvarp;	    /* ptr to global range variable to
						** be deallocated */

		if	((gvarp = gbase->opv_grv[gvar]) /* NULL if not allocated */
		     &&
		     (gvarp->opv_relation)	    /* not NULL if RDF has been
						** called for this range variable */
		     &&
		     !(gvarp->opv_gmask & OPV_TPROC)	/* not table procedure */
		    )
		{
		    /* if this element has been allocated and if it has an RDF
		    ** cache element associated with it */
		    DB_STATUS	   rdfstatus; /* RDF return status */

		    gbase->opv_grv[gvar] = NULL; /* so we do not try to deallocate
						** twice in case of an error */
		    rdfcb->rdf_info_blk = gvarp->opv_relation;
		    rdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb );
		    if ( (DB_FAILURE_MACRO(rdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
		    {
			finalstatus = rdfstatus;
			error.err_code = rdfcb->rdf_error.err_code;
		    }
		    gvarp->opv_relation = NULL;
		}

		if ((gvarp) && (gvarp->opv_ttmodel))
		{
		    /* if this element has been allocated and if it has an RDF
		    ** cache element associated with a persistent table
                    ** which provides histogram models.
		    */
		    DB_STATUS      rdfstatus; /* RDF return status */

		    rdfcb->rdf_info_blk = gvarp->opv_ttmodel;
		    gvarp->opv_ttmodel = NULL;
		    rdfstatus = rdf_call( RDF_UNFIX, (PTR)rdfcb );
		    if ( (DB_FAILURE_MACRO(rdfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
		    {
		        finalstatus = rdfstatus;
	                error.err_code = rdfcb->rdf_error.err_code;
		    }
		    
		}

	    }
	    global->ops_rangetab.opv_gv = 0;
	}
    }
    if (partial_dbp)
	return;					/* only deallocate the global range table
						** for DBP, and keep the memory streams
						** until the end */
    if (global->ops_estate.opn_statistics
	&&
	global->ops_estate.opn_reset_statistics)
    {	/* statistics CPU accounting was turned on, and needs to be reset */
	STATUS		cs_status;
	i4		turn_off;

	turn_off = FALSE;			/* turn off accounting */
	global->ops_estate.opn_statistics = FALSE;
	cs_status = CSaltr_session((CS_SID)0, CS_AS_CPUSTATS, (PTR)&turn_off);
	if (cs_status != OK)
	{
	    finalstatus = E_DB_ERROR;
	    error.err_code = cs_status;
	}
    }

    /* deallocate ULM memory stream */
    if (global->ops_mstate.ops_streamid == NULL)	/* non-zero if allocated */
    {
	/* check if ULM stream does not exist then this deallocation has
        ** already occurred so just return */
        return;
    }
    else
    {
	DB_STATUS            ulm1status;/* ULM return status */
	global->ops_mstate.ops_ulmrcb.ulm_streamid_p = 
	    &global->ops_mstate.ops_streamid; /* ulm will NULL ops_streamid */
	ulm1status = ulm_closestream( &global->ops_mstate.ops_ulmrcb );
	if ( (DB_FAILURE_MACRO(ulm1status)) && (DB_SUCCESS_MACRO(finalstatus)) )
	{
	    finalstatus = ulm1status;
	    error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code;
	}
    }

    /* deallocate ULM temp buffer memory stream */
    if ( global->ops_mstate.ops_tstreamid )	/* non-zero if allocated */
    {
	DB_STATUS            ulm2status; /* ULM return status */
	global->ops_mstate.ops_ulmrcb.ulm_streamid_p
	    = &global->ops_mstate.ops_tstreamid; /* ulm will NULL ops_tstreamid */
	ulm2status = ulm_closestream( &global->ops_mstate.ops_ulmrcb );
	if ( (DB_FAILURE_MACRO(ulm2status)) && (DB_SUCCESS_MACRO(finalstatus)) )
	{
	    finalstatus = ulm2status;
	    error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code;
	}
    }

    /* deallocate OPC ULM buffer memory stream */
    if ( global->ops_mstate.ops_sstreamid )	/* non-zero if allocated */
    {
	DB_STATUS            ulm3status; /* ULM return status */
	global->ops_mstate.ops_ulmrcb.ulm_streamid_p = &global->ops_mstate.ops_sstreamid;
	/* ulm will NULL ops_sstreamid */
	ulm3status = ulm_closestream( &global->ops_mstate.ops_ulmrcb );
	if ( (DB_FAILURE_MACRO(ulm3status)) && (DB_SUCCESS_MACRO(finalstatus)) )
	{
	    finalstatus = ulm3status;
	    error.err_code = global->ops_mstate.ops_ulmrcb.ulm_error.err_code;
	}
    }

    if (!report
#ifdef    OPT_F032_NOEXECUTE
	||
	/* if trace flag is set then cleanup QSF memory since optimizer will
	** generate an error to SCF and SCF assumes optimizer will cleanup
        */
	    (global->ops_cb->ops_check 
	    && 
	    (opt_strace( global->ops_cb, OPT_F032_NOEXECUTE)
	    || 
	    opt_strace( global->ops_cb, OPT_F023_NOCOMP)  )
	    )
#endif
       )
    {	/* an error or an asychronous abort has occurred so destroy the plan
        ** or shared plan , FIXME destroy the shared plan in the earlier
        ** exception handler */
	DB_STATUS	       qsfqpstatus;   /* QSF return status */
	if(global->ops_qpinit)
	{   /* deallocate QSF object for query plan if another error has occurred 
            ** - in this case OPC has already created a new QP handle and has
            ** gotten a lock on it */

	    STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_qep, global->ops_qsfcb.qsf_obj_id); /* get
						** query plan id */
	    global->ops_qsfcb.qsf_lk_id = global->ops_qplk_id; /* get lock id for 
						** QSF */
	    qsfqpstatus = ops_qsfdestroy(global); /* destroy the query plan */
	    if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
	    {
		finalstatus = qsfqpstatus;
		error.err_code = global->ops_qsfcb.qsf_error.err_code;
	    }
	}
	else 
	{   /* OPC has not been reached so need to check for shared query plan
            */
	    if (!global->ops_procedure)
	    {	/* get query tree if it has not already been retrieved */
		qsfqpstatus = ops_gqtree(global);
		if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
		{
		    finalstatus = qsfqpstatus;
		    error.err_code = global->ops_qsfcb.qsf_error.err_code;
		}
	    }
	    if (global->ops_qheader && 
			(global->ops_qheader->pst_mask1 & PST_RPTQRY))
	    {	/* shared query plan possible */
		if (global->ops_procedure->pst_flags & PST_REPEAT_DYNAMIC)
		{
		    char	*p;

		    global->ops_qsfcb.qsf_obj_id.qso_lname = 
						sizeof(DB_CURSOR_ID) + sizeof(i4);
		    MEfill(sizeof(global->ops_qsfcb.qsf_obj_id.qso_name), 0,
			global->ops_qsfcb.qsf_obj_id.qso_name);
		    MEcopy((PTR)&global->ops_procedure->
						pst_dbpid.db_cursor_id[0],
			sizeof (global->ops_procedure->
						pst_dbpid.db_cursor_id[0]),
			(PTR)global->ops_qsfcb.qsf_obj_id.qso_name);
		    p = (char *) global->ops_qsfcb.qsf_obj_id.qso_name + 
								2*sizeof(i4);
		    MEcopy((PTR)"qp", sizeof("qp"), p);
		    p = (char *) global->ops_qsfcb.qsf_obj_id.qso_name + 
						sizeof(DB_CURSOR_ID);
		    I4ASSIGN_MACRO(global->ops_caller_cb->opf_udbid, *(i4 *) p);
		    
		}
		else	/* must be proc or regular repeat query */
		{
		    global->ops_qsfcb.qsf_obj_id.qso_lname = 
				sizeof (global->ops_procedure->pst_dbpid);
		    MEcopy((PTR)&global->ops_procedure->pst_dbpid, 
			    sizeof (global->ops_procedure->pst_dbpid),
			    (PTR)&global->ops_qsfcb.qsf_obj_id.qso_name[0]);
		}
		global->ops_qsfcb.qsf_obj_id.qso_type = QSO_QP_OBJ;
		global->ops_qsfcb.qsf_lk_state = QSO_SHLOCK;
		qsfqpstatus = qsf_call(QSO_GETHANDLE, &global->ops_qsfcb);
		if (DB_SUCCESS_MACRO(qsfqpstatus))
		{
		    qsfqpstatus = ops_qsfdestroy( global );
		    if ( (DB_FAILURE_MACRO(qsfqpstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
		    {
			finalstatus = qsfqpstatus;
			error.err_code = global->ops_qsfcb.qsf_error.err_code;
		    }
		}
		else if (global->ops_qsfcb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ)
		{   /* if object is not found then this is not a shared query */
		    finalstatus = qsfqpstatus;
		    error.err_code = global->ops_qsfcb.qsf_error.err_code;
		}
	    }
	}	
    }

    /* release QSF memory allocated to query tree, make sure that this
    ** is done after the QP has been processed since pst_rptqry is still
    ** needed for above block */
    {
	DB_STATUS	       qsfstatus;   /* QSF return status */

	STRUCT_ASSIGN_MACRO(global->ops_caller_cb->opf_query_tree, global->ops_qsfcb.qsf_obj_id); /* get
					    ** query tree id */
        global->ops_qsfcb.qsf_lk_id = global->ops_lk_id; /* get lock id for 
                                            ** QSF */
	qsfstatus = ops_qsfdestroy( global );
	if ( (DB_FAILURE_MACRO(qsfstatus)) && (DB_SUCCESS_MACRO(finalstatus)) )
	{
	    finalstatus = qsfstatus;
	    error.err_code = global->ops_qsfcb.qsf_error.err_code;
	}
    }

    /* signal that the session is exiting OPF and that another thread may enter */
    if (global->ops_cb->ops_smask & OPS_MCONDITION)
    {
	DB_STATUS   lockstatus;
	OPG_CB	    *servercb;

	servercb = global->ops_cb->ops_server;
	global->ops_cb->ops_smask &= (~OPS_MCONDITION);
	lockstatus = ops_exlock(global->ops_caller_cb, &servercb->opg_semaphore); 
					    /* check if server
					    ** thread is available, obtain
					    ** semaphore lock on critical variable */
	servercb->opg_activeuser--;	    /* since exit is about to occur, and memory
					    ** has already been deallocated, allow another
					    ** user to enter OPF */
	servercb->opg_waitinguser--;	    /* since exit is about to occur, and memory
					    ** has already been deallocated, allow another
					    ** user to enter OPF */
	if (DB_FAILURE_MACRO(lockstatus) && (DB_SUCCESS_MACRO(finalstatus)))
	{
	    finalstatus = lockstatus;
	    error.err_code = global->ops_caller_cb->opf_errorblock.err_data;
	}
	else
	{
	    if (servercb->opg_waitinguser > servercb->opg_activeuser)
	    {
		STATUS	    csstatus;
		csstatus = CScnd_signal(&servercb->opg_condition, (CS_SID)NULL);
						/* signal only if some users are waiting */
		if ((csstatus != OK) && (DB_SUCCESS_MACRO(finalstatus)))
		{
		    finalstatus = E_DB_ERROR;
		    error.err_code = csstatus;
		}
	    }
	    lockstatus = ops_unlock(global->ops_caller_cb, 
		&servercb->opg_semaphore);	/* check if server
						** thread is available */
	    if (DB_FAILURE_MACRO(lockstatus) && (DB_SUCCESS_MACRO(finalstatus)))
	    {
		finalstatus = lockstatus;
		error.err_code = global->ops_caller_cb->opf_errorblock.err_data;
	    }
	}
    }

    if (DB_FAILURE_MACRO(finalstatus))
    {
	if (report)
	    opx_verror( finalstatus, E_OP0084_DEALLOCATION, error.err_code); /* report
					    ** error and generate an exception */
	else
	    opx_rverror(global->ops_cb->ops_callercb, finalstatus,
		E_OP0084_DEALLOCATION, error.err_code);
					    /* report error only but do not generate an
					    ** exception */
    }
}
Esempio n. 6
0
/*{
** Name: opx_adfexception	- handle ADF exceptions if possible
**
** Description:
**      Routine will be called by exception handlers in the optimizer to
**	handle arithmetic exceptions if possible
**
** Inputs:
**      ops_cb                          OPF session control block
**      ex_args                         exception handler arguments
**
** Outputs:
**	Returns:
**	    exception status - EXCONTINUES, or EXRESIGNAL
**		where EXRESIGNAL means that the exception is unknown
**	Exceptions:
**	    OPF exception is generated for a fatal ADF exception
**
** Side Effects:
**	    none
**
** History:
**      20-jan-86 (seputis)
**          initial creation
**	31-mar-92 (rog)
**	    Remove underscores from EX return statuses.
**	24-oct-92 (andre)
**	    interface of opx_sccerror() has been changed to receive
**	    (DB_SQLSTATE *)
[@history_template@]...
*/
static STATUS
opx_adfexception(
	OPS_CB		   *ops_cb,
	EX_ARGS            *ex_args)
{
    DB_STATUS           status;
    ADF_CB              *adf_scb;

    adf_scb = ops_cb->ops_adfcb;
    status = adx_handler(adf_scb, ex_args);
    if ((status == E_DB_WARN) 
	&& 
	(adf_scb->adf_errcb.ad_errcode == E_AD0116_EX_UNKNOWN)
	)
    {	/* adf does not know about this error so resignal it */
	return (EXRESIGNAL);
    }
    if (DB_SUCCESS_MACRO(status))
    {	/* adf will return OK status if it knowns about the error and the
        ** correct action is to continue */
#ifdef    OPT_F031_WARNINGS
	/* if trace flag is set then warning or info errors will be reported */
	if ( DB_SUCCESS_MACRO(status)
	    &&
	    ops_cb->ops_check 
	    &&
	    opt_strace( ops_cb, OPT_F031_WARNINGS)
	   )
	    opx_rverror( ops_cb->ops_callercb, 
		E_DB_WARN, E_OP0701_ADF_EXCEPTION, (OPX_FACILITY)0); /* report 
						** warning is 
						** trace flag is set */
#endif
	return(EXCONTINUES);			/* return if error is not
                                                ** serious */
    }

    {
	OPX_ERROR	adf_error;
	OPX_ERROR	opf_error;
	ops_cb->ops_retstatus = status;
	if (adf_scb->adf_errcb.ad_errclass == ADF_USER_ERROR)
	{	/* report the error message to the user */
	    adf_error = adf_scb->adf_errcb.ad_usererr;
	    opf_error = E_OP0702_ADF_EXCEPTION;
	}
	else
	{	/* report non-user error code */
	    adf_error = adf_scb->adf_errcb.ad_errcode;
	    opf_error = E_OP0795_ADF_EXCEPTION;
	}
	opx_rverror(ops_cb->ops_callercb, E_DB_WARN, opf_error,(OPX_FACILITY)0);
					/* do not report facility error
					** since opx_sccerror will report it
					** in the next statement
                                        ** - need to use the formatted message
                                        ** the ADF provides since it may contain
                                        ** parameters */
	(VOID) opx_sccerror(status, &adf_scb->adf_errcb.ad_sqlstate,
	    adf_error, adf_scb->adf_errcb.ad_errmsgp,
	    adf_scb->adf_errcb.ad_emsglen);
    }
    return (EXDECLARE);		    /* return to declaration point of
					    ** exception handler */
}