Esempio n. 1
0
/*{
** Name: QEU_DELETE     - delete tuples from a table
**
** External QEF call:   status = qef_call(QEU_DELETE, &qeu_cb);
**
** Description:
**      Tuples are deleted from a table opened with the QEU_OPEN
** command. If no qualification is given, the current tuple is 
** deleted.
**
** Inputs:
**       qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id                     table access id
**          .qeu_tup_length                 tuple length of the table
**					    Only required for keyed delete
**          .qeu_qual                       qualification function
**          .qeu_qarg                       argument to qualification function
**          .qeu_klen                       length of key - number of entries
**          .qeu_key                        key for delete
**      <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY
**              .attr_number
**              .attr_operation
**              .attr_value_ptr
**	    .qeu_flag			    operation qualifier
**		QEU_BY_TID		    remove tuple whose TID is in qeu_tid
**	    .qeu_tid			    contains TID of the tuple to be
**					    removed if (qeu_flag & QEU_BY_TID)
**
** Outputs:
**      qeu_cb
**          .qeu_count                      number of tuples retrieved
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      27-may-86 (daved)
**          written
**      02-sep-86 (jennifer)
**          Modified qeu_delete to return a count of tuples 
**          deleted.
**	21-oct-86 (daved)
**	    did above fix for case where dmf returns no more rows.
**	22-dec-86 (daved)
**	    return OK if deleting keyed records
**      10-dec-87 (puree)
**          Converted all ulm_palloc to qec_palloc
**	04-jan-91 (andre)
**	    added functionality to delete tuples by TID
**	18-jun-92 (andre)
**	    do not allocate memory unless we will actually be reading tuples,
**	    i.e. if a key is specified
**	06-mar-96 (nanpr01)
**	    removed the dependency on DB_MAXTUP for increased tuple size
**	    project. Also added the check to make sure tuple size is set
**	    whoever called this routine.  Also tuple size consistency is
**	    checked iff qeu_klen > 0.
**	24-Jan-2001 (jenjo02)
**	    Ensure that memory stream is closed before returning.
**	11-Apr-2008 (kschendel)
**	    Revised DMF qualification requirements, simplified for QEU.
*/
DB_STATUS
qeu_delete(
QEF_CB          *qef_cb,
QEU_CB          *qeu_cb)
{
    i4         err;
    i4              count;
    DMR_CB          dmr_cb;
    DB_STATUS       status;
    GLOBALREF QEF_S_CB *Qef_s_cb;
    ULM_RCB         ulm;        /* so we don't need to allocate a tuple buffer
                                ** as a stack variable, use dynamic memory
                                */

    count = 0;
    qeu_cb->qeu_count = 0;
    qeu_cb->error.err_code = E_QE0000_OK;

    /* QEU_DELETE is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }
    dmr_cb.type                 = DMR_RECORD_CB;
    dmr_cb.length               = sizeof(DMR_CB);
    dmr_cb.dmr_access_id        = qeu_cb->qeu_acc_id;
    dmr_cb.dmr_q_fcn		= NULL;

    /* position the cursor */
    /* if there is a key, position by qual. Else, position all records */
    if (qeu_cb->qeu_klen)
    {
        if (qeu_cb->qeu_tup_length <= 0)
        {
            qef_error(E_QE0018_BAD_PARAM_IN_CB, 0L, E_DB_ERROR, &err,
                &qeu_cb->error, 0);
            return (E_DB_ERROR);
        }
	/* allocate memory for a tuple only if planning to call qeu_get() */
	
	STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm);
	/* Open stream and allocate tuple memory in one action */
	ulm.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC;
	ulm.ulm_psize = ulm.ulm_blocksize = qeu_cb->qeu_tup_length;

	if ((status = qec_mopen(&ulm)) != E_DB_OK)
	{
	    qef_error(E_QE001E_NO_MEM, 0L, E_DB_ERROR, &err,
		&qeu_cb->error, 0);
	    return (status);
	}

        /* set the keys */
        dmr_cb.dmr_position_type = DMR_QUAL;
        dmr_cb.dmr_attr_desc.ptr_address    = (PTR) qeu_cb->qeu_key;
        dmr_cb.dmr_attr_desc.ptr_in_count   = qeu_cb->qeu_klen;
	dmr_cb.dmr_attr_desc.ptr_size	    = sizeof (DMR_ATTR_ENTRY);
	dmr_cb.dmr_s_estimated_records	    = -1;

        /* row qualifier */
        dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual;
        dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg;
	if (qeu_cb->qeu_qual != NULL)
	{
	    dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr;
	    dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval;
	}
	dmr_cb.dmr_flags_mask = 0;
        status = dmf_call(DMR_POSITION, &dmr_cb);
        if (status != E_DB_OK)
        {
	    ulm_closestream(&ulm);
	    if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		return (E_DB_OK);

            qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0);
            return (status);
        }
        /* the tuple length will not change. Tell DMF about it */
	dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length;
	dmr_cb.dmr_data.data_address = ulm.ulm_pptr;
    }

    for (;;)
    {
        if (qeu_cb->qeu_klen)
	{
            /* get the tuple */
            dmr_cb.dmr_flags_mask = DMR_NEXT;
            status = dmf_call(DMR_GET, &dmr_cb);
            if (status != E_DB_OK)
            {
                if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		{
		    status = E_DB_OK;
                    break;
		}
                else
                {
                    qef_error(dmr_cb.error.err_code, 0L, status, 
                        &err, &qeu_cb->error, 0);
                }
                break;
            }
	}
	/*
	** delete the tuple: if deleting by TID, copy qeu_tid to dmr_tid and set
	** dmr_flags_mask to DMR_BY_TID
	*/
	if (qeu_cb->qeu_flag & QEU_BY_TID)
	{
	    dmr_cb.dmr_flags_mask = DMR_BY_TID;
	    dmr_cb.dmr_tid = qeu_cb->qeu_tid;
	}
	/* otherwise delete the current tuple */
	else
	{
	    dmr_cb.dmr_flags_mask = DMR_CURRENT_POS;
	}

        status = dmf_call(DMR_DELETE, &dmr_cb);
        if (status != E_DB_OK)
        {
            qef_error(dmr_cb.error.err_code, 0L, status, 
                &err, &qeu_cb->error, 0);
            break;
        }
	count++;
	if (qeu_cb->qeu_klen == 0)
	{
	    /* we are only deleting current tuple */
	    break;        
        }
    }
    
    if (qeu_cb->qeu_klen)
    {
	/* don't try to close a stream unless it was opened */
	ulm_closestream(&ulm);
    }
    
    qeu_cb->qeu_count = count;
    return (status);
}
Esempio n. 2
0
DB_STATUS
qet_t9_ok_w_ldbs(
QEE_DSH		*i_dsh_p,
QEF_RCB		*v_qer_p,
bool		*o1_ok_p)
{
    DB_STATUS	    status_0 = E_DB_OK,
		    status_t = E_DB_OK,
		    status_u = E_DB_OK;		
    DB_ERROR	    ulm_err,
		    tpf_err;
    QES_DDB_SES	    *dds_p = & v_qer_p->qef_cb->qef_c2_ddb_ses;
    TPR_CB	    tpr_cb,
		    *tpr_p = & tpr_cb;
    QEF_QP_CB	    *qp_p = i_dsh_p->dsh_qp_ptr;
    QEF_AHD	    *act_p = qp_p->qp_ahd;
    QEQ_D1_QRY	    *subqry_p;
    ULM_RCB	    ulm;
    i4		    w_ldbcnt;
    TPR_W_LDB	    *wldb1_p = (TPR_W_LDB *) NULL,
		    *wldb2_p = (TPR_W_LDB *) NULL;


    *o1_ok_p = TRUE;	/* assume */

    if (qp_p->qp_qmode == QEQP_01QM_RETRIEVE)
	return(E_DB_OK);	    /* read-only query */

    /* assume that there are update sites within this query plan */

    /* allocate stream to build list of LDB ptrs; note that this 
    ** stream must be closed upon return from this routine */

    STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_s_ulmcb, ulm);
    ulm.ulm_blocksize = sizeof(TPR_W_LDB);  /* allocation size */

    status_u = qec_mopen(&ulm);
    if (status_u)
    {
	v_qer_p->error.err_code = ulm.ulm_error.err_code;
	return(status_u);
    }

    /* traverse the action list to build an LDB ptr list */

    MEfill(sizeof(tpr_cb), '\0', (PTR) & tpr_cb);
    tpr_p->tpr_session = dds_p->qes_d2_tps_p;	/* TPF session CB ptr */
    tpr_p->tpr_rqf = dds_p->qes_d3_rqs_p;	/* RQF session CB ptr */
    tpr_cb.tpr_15_w_ldb_p = (TPR_W_LDB *) NULL;
    w_ldbcnt = 0;
    act_p = qp_p->qp_ahd; 
    while (act_p != (QEF_AHD *) NULL && status_u == E_DB_OK)
    {
	if (act_p->ahd_atype == QEA_D1_QRY)
	{
	    subqry_p = & act_p->qhd_obj.qhd_d1_qry;

	    if (subqry_p->qeq_q3_ctl_info & QEQ_002_USER_UPDATE)
	    {
		/* an update site */

		w_ldbcnt++;

		ulm.ulm_psize = sizeof(TPR_W_LDB);
		status_u = qec_malloc(&ulm);
		if (status_u)
		{
		    STRUCT_ASSIGN_MACRO(ulm.ulm_error, ulm_err);
		    goto dismantle_9;
		}
		else
		{
		    /* allocation ok */

		    wldb2_p = (TPR_W_LDB *) ulm.ulm_pptr;

		    if (wldb1_p == (TPR_W_LDB *) NULL)
		    {
			/* first in list */

			tpr_cb.tpr_15_w_ldb_p = 
			    wldb1_p = wldb2_p;  
			wldb2_p->tpr_1_prev_p = 
			    wldb2_p->tpr_2_next_p = (TPR_W_LDB *) NULL;
		    }
		    else
		    {
			/* append to list */

			wldb1_p->tpr_2_next_p = wldb2_p;  
			wldb2_p->tpr_1_prev_p = wldb1_p;
			wldb2_p->tpr_2_next_p = (TPR_W_LDB *) NULL;
		    }

		    wldb2_p->tpr_3_ldb_p = subqry_p->qeq_q5_ldb_p;
		}
  	    }
	}
	act_p = act_p->ahd_next;	/* advance */
    }
    /* call TPF if any update sites */

    if (tpr_cb.tpr_15_w_ldb_p != (TPR_W_LDB *) NULL)
    {
	status_t = qed_u17_tpf_call(TPF_OK_W_LDBS, & tpr_cb, v_qer_p);
	if (status_t)
	    STRUCT_ASSIGN_MACRO(tpr_cb.tpr_error, tpf_err);
	else
	    *o1_ok_p = tpr_cb.tpr_14_w_ldbs_ok;
    }

dismantle_9:

    /* must always close stream */

    status_0 = ulm_closestream(&ulm);

    if (status_u)
    {
	/* return previous ulm error */

	STRUCT_ASSIGN_MACRO(ulm_err, v_qer_p->error);
	return(status_u);
    }

    if (status_t)
    {
	/* return tpf error */

	STRUCT_ASSIGN_MACRO(tpf_err, v_qer_p->error);
	return(status_t);
    }

    if (status_0)
    {
	/* return close-stream ulm error */

	STRUCT_ASSIGN_MACRO(ulm.ulm_error, v_qer_p->error);
    }
    
    return(status_0);
}
Esempio n. 3
0
/*{
** Name: QEU_REPLACE     - replace tuple(s) in a table
**
** External QEF call:   status = qef_call(QEU_REPLACE, &qeu_cb);
**
** Description:
**      A tuple is replaced in a table opened with the QEU_OPEN
** command.
** If QEU_BY_TID is specified,
**	the tuple with specified TID is repalced
** else if qeu_cb->kqeu_klen > 0
**	qeu_f_qual points to a function which will both determine whether the
**	tuple should be updated and make appropriate changes to the tuple
**      passed to it
** else
**	replace the tuple which was read by position as specified by the caller
**
** Inputs:
**       qeu_cb
**	    .qeu_eflag			    designate error handling semantis
**					    for user errors.
**		QEF_INTERNAL		    return error code.
**		QEF_EXTERNAL		    send message to user.
**          .qeu_acc_id                     table access id
**          .qeu_tup_length                 lenth of a tuple
**          .qeu_input                      buffer containing new values for the
**					    tuple being replaced
**	    .qeu_qual			    qualification function for DMF
**	    .qeu_qarg			    argument to (*qeu_qual) ()
**          .qeu_klen                       length of key 
**          .qeu_key                        key for update
**      <qeu_key> is a pointer to an array of pointers of type DMR_ATTR_ENTRY
**              .attr_number
**              .attr_operation
**              .attr_value_ptr
**	    .qeu_flag			    operation qualifier
**		QEU_BY_TID		    replace tuple whose TID is in
**					    qeu_tid
**	    .qeu_tid			    contains TID of the tuple to be
**					    replaced if (qeu_flag & QEU_BY_TID)
**	    .qeu_f_qual			    if !(qeu_klen > 0) this must point
**					    at a function which will decide
**					    whether and how the current tuple
**					    must be replaced
**	    .qeu_f_qarg			    argument to (*qeu_f_qual) ()
**	    
** Outputs:
**      qeu_cb
**	    .qeu_count			    number of tuples updated
**          .error.err_code                 One of the following
**                                          E_QE0000_OK
**                                          E_QE0002_INTERNAL_ERROR
**                                          E_QE0004_NO_TRANSACTION
**                                          E_QE0007_NO_CURSOR
**                                          E_QE0017_BAD_CB
**                                          E_QE0018_BAD_PARAM_IN_CB
**      Returns:
**          E_DB_OK
**          E_DB_ERROR                      caller error
**          E_DB_FATAL                      internal error
**      Exceptions:
**          none
**
** Side Effects:
**          none
**
** History:
**      18-jun-92 (andre)
**          written
**	22-jun-92 (andre)
**	    changed the function to allow update one row by tid or to update
**	    multiple rows subject to qualification function
**	24-jun-92 (andre)
**	    another change to allow update of prepositioned tuple
**	13-sep-93 (robf)
**	    Extended to handle update multiple rows without
**	    requiring a key position. This is signalled when qeu_klen==0
**	    and qeu_qual != NULL and qeu_f_qual!=NULL
**	30-nov-93 (robf)
**          When updating multiple rows, keep going after first update.
**	24-Jan-2001 (jenjo02)
**	    Ensure that memory stream is closed before returning.
**	11-Apr-2008 (kschendel)
**	    Revised DMF qualification requirements, simplified for QEU.
*/
DB_STATUS
qeu_replace(
QEF_CB          *qef_cb,
QEU_CB          *qeu_cb)
{
    i4		    err = 0L;
    DMR_CB		    dmr_cb;
    DB_STATUS		    status;
    GLOBALREF QEF_S_CB	    *Qef_s_cb;
    ULM_RCB		    ulm;
    i4			    (*repl_func)(void *, void *);
    bool		    position_all=FALSE;
    bool		    mem_opened=FALSE;

    if (qeu_cb->qeu_flag & QEU_BY_TID)
    {
	/*
	** if update_by_tid, no key(s), qualification function, or qualification
	** function parameters should be passed;
	** qeu_cb->qeu_input must point at a structure containing a ptr to the
	** new value for the tuple of specified size
	*/
	if (qeu_cb->qeu_klen || qeu_cb->qeu_qual || qeu_cb->qeu_qarg ||
	    qeu_cb->qeu_f_qual || qeu_cb->qeu_f_qarg || !qeu_cb->qeu_input ||
	    !qeu_cb->qeu_input->dt_data || !qeu_cb->qeu_input->dt_size)
	{
	    err = E_QE0018_BAD_PARAM_IN_CB;
	    status = E_DB_ERROR;
	}
    }
    else if (qeu_cb->qeu_klen==0 &&  
	    (repl_func = qeu_cb->qeu_f_qual) != NULL &&
	    qeu_cb->qeu_qual)
    {
	position_all=TRUE;
	/*
	** Request to replace all qualifying in table, without key 
	** positioning
	*/
	if (!qeu_cb->qeu_qarg || 
	    !qeu_cb->qeu_f_qarg 
	    )
	{
	    err = E_QE0018_BAD_PARAM_IN_CB;
	    status = E_DB_ERROR;
	}
    }
    else if (qeu_cb->qeu_klen == 0)
    {
	/*
	** if asked to update the current tuple, no qualification function, or
	** qualification function parameters should be passed;
	** qeu_cb->qeu_input must point at a structure containing a ptr to
	** the new value for the tuple of specified size
	*/
	if (qeu_cb->qeu_qual || qeu_cb->qeu_qarg || qeu_cb->qeu_f_qual ||
	    qeu_cb->qeu_f_qarg || !qeu_cb->qeu_input ||
	    !qeu_cb->qeu_input->dt_data || !qeu_cb->qeu_input->dt_size)
	{
	    err = E_QE0018_BAD_PARAM_IN_CB;
	    status = E_DB_ERROR;
	}
    }
    else if ((repl_func = qeu_cb->qeu_f_qual) == NULL)
    {
	/*
	** if caller supplied a key, must specify the function which
	** will determine whether and how the tuple must be updated
	*/
	err = E_QE0018_BAD_PARAM_IN_CB;
	status = E_DB_ERROR;
    }

    if (err)
    {
	(VOID) qef_error(err, 0L, status, &err, &qeu_cb->error, 0);
	return(status);
    }

    qeu_cb->qeu_count = 0;
    qeu_cb->error.err_code = E_QE0000_OK;

    /* QEU_REPLACE is only valid in a transaction */
    if (qef_cb->qef_stat == QEF_NOTRAN)
    {
        qef_error(E_QE0004_NO_TRANSACTION, 0L, E_DB_ERROR, &err,
            &qeu_cb->error, 0);
        return (E_DB_ERROR);
    }

    dmr_cb.type                 = DMR_RECORD_CB;
    dmr_cb.length               = sizeof(DMR_CB);
    dmr_cb.dmr_access_id        = qeu_cb->qeu_acc_id;
    dmr_cb.dmr_q_fcn		= NULL;

    /* if replacing by key, position the cursor */
    if (qeu_cb->qeu_klen || position_all)
    {
	/* allocate memory for a tuple only if planning to call qeu_get() */
	
	STRUCT_ASSIGN_MACRO(Qef_s_cb->qef_d_ulmcb, ulm);
	/* Open stream and allocate tuple memory in one action */
	ulm.ulm_flags = ULM_PRIVATE_STREAM | ULM_OPEN_AND_PALLOC;
	ulm.ulm_psize = ulm.ulm_blocksize = qeu_cb->qeu_tup_length;

	if ((status = qec_mopen(&ulm)) != E_DB_OK)
	{
	    qef_error(E_QE001E_NO_MEM, 0L, E_DB_ERROR, &err,
		&qeu_cb->error, 0);
	    return (status);
	}
	mem_opened=TRUE;

        /* set the keys */
	if(position_all)
	{
		dmr_cb.dmr_position_type = DMR_ALL;
	}
	else
	{
		dmr_cb.dmr_position_type = DMR_QUAL;
		dmr_cb.dmr_attr_desc.ptr_address    = (PTR) qeu_cb->qeu_key;
		dmr_cb.dmr_attr_desc.ptr_in_count   = qeu_cb->qeu_klen;
		dmr_cb.dmr_attr_desc.ptr_size	    = sizeof (DMR_ATTR_ENTRY);
		dmr_cb.dmr_s_estimated_records	    = -1;
	}
        /* row qualifier */
        dmr_cb.dmr_q_fcn = (DB_STATUS (*)(void *,void *)) qeu_cb->qeu_qual;
        dmr_cb.dmr_q_arg = (PTR) qeu_cb->qeu_qarg;
	if (qeu_cb->qeu_qual != NULL)
	{
	    dmr_cb.dmr_q_rowaddr = &qeu_cb->qeu_qarg->qeu_rowaddr;
	    dmr_cb.dmr_q_retval = &qeu_cb->qeu_qarg->qeu_retval;
	}
	dmr_cb.dmr_flags_mask = 0;
        status = dmf_call(DMR_POSITION, &dmr_cb);
        if (status != E_DB_OK)
        {
	    ulm_closestream(&ulm);

	    if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		return (E_DB_OK);
            qef_error(dmr_cb.error.err_code, 0L, status, &err, &qeu_cb->error, 0);
            return (status);
        }

	/* the tuple length will not change. Tell DMF about it */
	dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_tup_length;
	dmr_cb.dmr_data.data_address = ulm.ulm_pptr;
    }
    else
    {
	/*
	** make dmr_data point at the new value for the tuple
	*/
	dmr_cb.dmr_data.data_address = qeu_cb->qeu_input->dt_data;
	dmr_cb.dmr_data.data_in_size = qeu_cb->qeu_input->dt_size;

	/*
	** if (qeu_flag & QEU_BY_TID)
	**    indicate to dmr_replace() that we are replacing by tid
	** else
	**    indicate to dmr_replace to replace the current tuple
	*/

	if (qeu_cb->qeu_flag & QEU_BY_TID)
	{	
	    dmr_cb.dmr_flags_mask = DMR_BY_TID;
	    dmr_cb.dmr_tid = qeu_cb->qeu_tid;
	}
	else
	{
	    dmr_cb.dmr_flags_mask = DMR_CURRENT_POS;
	}
    }

    for (;;)
    {
        if (qeu_cb->qeu_klen || position_all)
	{
	    i4	ret_val;

            /* get the tuple */
            dmr_cb.dmr_flags_mask = DMR_NEXT;
            status = dmf_call(DMR_GET, &dmr_cb);
            if (status != E_DB_OK)
            {
                if (dmr_cb.error.err_code == E_DM0055_NONEXT)
		{
		    status = E_DB_OK;
		}
		else
		{
		    err = dmr_cb.error.err_code;
		}
                break;
            }

	    /*
	    ** let caller's function determine whether and how the tuple must be
	    ** changed; QEU_F_RETURN indicates that we must proceed; QEU_F_NEXT
	    ** says "skip this tuple"
	    */
	    ret_val = (*repl_func) (dmr_cb.dmr_data.data_address,
		qeu_cb->qeu_f_qarg);

	    if (ret_val != QEU_F_RETURN)
	    {
		continue;
	    }

	    /* will replace the current tuple */
	    dmr_cb.dmr_flags_mask = DMR_CURRENT_POS;
	}

	dmr_cb.dmr_attset = NULL;
	status = dmf_call(DMR_REPLACE, &dmr_cb);
	if (status != E_DB_OK)
	{
	    err = dmr_cb.error.err_code;
	    break;
	}
	else
	{
	    qeu_cb->qeu_count++;
	}

	if (qeu_cb->qeu_klen == 0 && !position_all)
	{
	    /* we were replacing a tuple by tid and are done */
	    break;
	}
    }

    if (status != E_DB_OK)
    {
	qef_error(err, 0L, status, &err, &qeu_cb->error, 0);
    }

    if (mem_opened)
    {
	/* don't try to close a stream unless it was opened */
	ulm_closestream(&ulm);
    }
    
    return (status);
}