Exemplo n.º 1
0
i4
gcu_put_int( char *buff, i4  value )
{
    i4	i4val = value;

    I4ASSIGN_MACRO( i4val, *buff );

    return( sizeof( i4val ) );
}
Exemplo n.º 2
0
i4
gcu_get_int( char *buff, i4  *value )
{
    i4	i4val;

    I4ASSIGN_MACRO( *buff, i4val );
    *value = (i4)i4val;

    return( sizeof( i4val ) );
}
Exemplo n.º 3
0
i4
gcu_put_str( char *buff, char *str )
{
    i4	len;

    if ( ! str || ! *str )
    {
	len = 0;
	I4ASSIGN_MACRO( len, *buff );
    }
    else
    {
	len = (i4)STlength( str ) + 1;
	I4ASSIGN_MACRO( len, *buff );
	MEcopy( str, len, buff + sizeof( len ) );
    }

    return( sizeof( len ) + len );
}
Exemplo n.º 4
0
i4
gcu_get_str( char *buff, char **str )
{
    i4	len;

    I4ASSIGN_MACRO( *buff, len );

    if ( len )
	*str = buff + sizeof( len );
    else
	*str = "";

    return( sizeof( len ) + len );
}
Exemplo n.º 5
0
/*
** Name: gcu_alloc_str() - allocate buffer and copy var string from input.
**
** Description:
**      allocate memory with the size of input buff size.  
**      Copies the string from input buff into the allocated ptr, 
**      null terminating ptr.
**      assign ptr to output str.  
**
** Returns:
**      Amount of buffer used.
**
** History:
**      19-Jul-2001 (wansh01) 
**         created
*/
i4
gcu_alloc_str( char *buff,  char **str)
{
    i4	     len;
    STATUS   status;
    char     *ptr;

    I4ASSIGN_MACRO( *buff, len );

 
        if ((ptr = (char *)MEreqmem(0,len+1, FALSE, &status)) == NULL)
	   return 0;

	MEcopy( buff + sizeof( len ), len, ptr );

	if( !len || buff[ len - 1 ] )
	   ptr[ len ] = '\0';

        *str = ptr; 

	return sizeof( len ) + len;
}
Exemplo n.º 6
0
VOID
adu_2prvalue(
i4		    (*fcn)(char *, ...),
DB_DATA_VALUE      *db_dv)
{
    char			num_buf[64];
    i2				flt_wid;
    f8				f8_tmp;
    AD_DTUNION			*dp;
    DB_TAB_LOGKEY_INTERNAL  	*tab_logkey;
    DB_OBJ_LOGKEY_INTERNAL  	*obj_logkey;
    DB_DT_ID			bdt;
    i4				blen;
    i4				prec;
    char			*data;
    char			fmt[16];
    i4			tmp;
    i4			tcnt;
    i4				i;
    i4				res_wid;
    i8				i8_tmp;
    f4				f4_tmp;
    i4				i4_tmp;
    i2				i2_tmp, i2_tmp2;
    i1				i1_tmp;
    char			stbuf[2048];


    if (db_dv == NULL)
    {
	(*fcn)(STprintf(stbuf,"< Pointer to DB_DATA_VALUE is NULL >\n"));
	return;
    }

    bdt  = abs(db_dv->db_datatype);
    blen = db_dv->db_length - (db_dv->db_datatype < 0);
    prec = db_dv->db_prec;
    data = db_dv->db_data;
    dp = (AD_DTUNION*)data;

    if (data == NULL)
    {
	(*fcn)(STprintf(stbuf,"< pointer to data is NULL >\n"));
    }
    else if (ADI_ISNULL_MACRO(db_dv))
    {
	(*fcn)(STprintf(stbuf,"< NULL >\n"));
    }
    else
    {
	switch (bdt)
	{
	  case DB_LOGKEY_TYPE:

	    obj_logkey = (DB_OBJ_LOGKEY_INTERNAL *) data;

	    (*fcn)(STprintf(stbuf, "olk_db_id = %x\tolk_rel_id = %x\n",
		    obj_logkey->olk_db_id, obj_logkey->olk_rel_id));
	    (*fcn)(STprintf(stbuf, "olk_high_id = %x\tolk_low_id = %x\n",
		    obj_logkey->olk_high_id, obj_logkey->olk_low_id));
	    
	    break;

	  case DB_TABKEY_TYPE:

	    tab_logkey = (DB_TAB_LOGKEY_INTERNAL *) data;

	    (*fcn)(STprintf(stbuf, "tlk_high_id = %x\ttlk_low_id = %x\n",
		    tab_logkey->tlk_high_id, tab_logkey->tlk_low_id));

	    break;

	  case DB_CHA_TYPE:
	  case DB_CHR_TYPE:
	  case DB_BYTE_TYPE:
	    if (blen == 0)
	    {
	        (*fcn)(STprintf(stbuf,"''"));
		break;
	    }
	    (*fcn)(STprintf(stbuf, "'%*s'", blen, (u_char *) data));
	    break;

	  case DB_DTE_TYPE:
	    (*fcn)(STprintf(stbuf,
		      "dn_status = %x\tdn_highday = %d\tdn_time = %d\n",
		      dp->ing_date.dn_status, dp->ing_date.dn_highday, dp->ing_date.dn_time));
	    (*fcn)(STprintf(stbuf,
		      "dn_year = %d\tdn_month = %d\tdn_lowday = %d",
		      dp->ing_date.dn_year, dp->ing_date.dn_month, dp->ing_date.dn_lowday));
	    break;

	  case DB_ADTE_TYPE:
	    (*fcn)(STprintf(stbuf,"dn_year = %d\tdn_month = %d\tdn_day = %d\n",
		      dp->adate.dn_year, dp->adate.dn_month, dp->adate.dn_day));
	    break;

	  case DB_TMWO_TYPE:
	  case DB_TMW_TYPE:
	  case DB_TME_TYPE:
	    (*fcn)(STprintf(stbuf,"dn_seconds = %d\tdn_nsecond = %d\n",
		      dp->atime.dn_seconds, dp->atime.dn_nsecond));
	    (*fcn)(STprintf(stbuf,"dn_tzoffset = %d\n",
		      AD_TZ_OFFSET(&dp->atime)));
	    break;

	  case DB_INYM_TYPE:
	    (*fcn)(STprintf(stbuf,"dn_years = %d\tdn_months = %d\n",
		      dp->aintym.dn_years, dp->aintym.dn_months));
	    break;

	  case DB_INDS_TYPE:
	    (*fcn)(STprintf(stbuf,"dn_days = %d\tdn_seconds = %d\tdn_nseconds = %d\n",
		      dp->aintds.dn_days, dp->aintds.dn_seconds, dp->aintds.dn_nseconds));
	    break;

	  case DB_TSWO_TYPE:
	  case DB_TSW_TYPE:
	  case DB_TSTMP_TYPE:
	    (*fcn)(STprintf(stbuf,"dn_year = %d\tdn_month = %d\tdn_day = %d\n",
		      dp->atimestamp.dn_year, dp->atimestamp.dn_month, dp->atimestamp.dn_day));
	    (*fcn)(STprintf(stbuf,"dn_seconds = %d\tdn_nsecond = %d\n",
		      dp->atimestamp.dn_seconds, dp->atimestamp.dn_nsecond));
	    (*fcn)(STprintf(stbuf,"dn_tzoffset = %d\n",
		      AD_TZ_OFFSET(&dp->atimestamp)));
	    break;

	  case DB_DEC_TYPE:
	    CVpka(data,
		(i4)DB_P_DECODE_MACRO(prec),
		(i4)DB_S_DECODE_MACRO(prec),
		'.',
		(i4)DB_P_DECODE_MACRO(prec) + 5,
		(i4)DB_S_DECODE_MACRO(prec),
		CV_PKLEFTJUST,
		num_buf,
		&res_wid);
		
	    tmp = res_wid;
	    i = 0;
	    fmt[i++] = '%';
	    if (tmp >= 10)
	    {
		fmt[i++] = (tmp / 10) + '0';
		tmp = tmp % 10;
	    }
	    fmt[i++] = tmp + '0';
	    fmt[i++] = 's';
	    fmt[i] = EOS;
	    (*fcn)(STprintf(stbuf, fmt, num_buf));
	    break;
	    
	  case DB_FLT_TYPE:
	    if (blen == 4)
	    {
		F4ASSIGN_MACRO(*data, f4_tmp);
		f8_tmp = f4_tmp;
	    }
	    else
		F8ASSIGN_MACRO(*data, f8_tmp);

	    CVfa(f8_tmp, (i4) sizeof(num_buf), (i4) 4, 'f', '.', num_buf, &flt_wid);
	    (*fcn)(STprintf(stbuf, "%*s", flt_wid, (u_char *)num_buf));
	    break;

	  case DB_INT_TYPE:
	    if (blen == 4)
	    {
		I4ASSIGN_MACRO(*data, i4_tmp);
	    }
	    else if (blen == 2)
	    {
		I2ASSIGN_MACRO(*data, i2_tmp);
		i4_tmp = i2_tmp;
	    }
	    else if (blen == 1)
	    {
		i4_tmp = I1_CHECK_MACRO(*(i1 *)data);
	    }
	    else /* blen == 8 */
	    {
		/* Depending on host, printing i8's might be %ld (lp64)
		** or %lld (lpi32).  Avoid issues by converting to string.
		*/
		I8ASSIGN_MACRO(*data,i8_tmp);
		CVla8(i8_tmp,&num_buf[0]);
		(*fcn)(num_buf);
		break;
	    }
	    (*fcn)(STprintf(stbuf, "%d", i4_tmp));
	    break;

	  case DB_MNY_TYPE:
	    f8_tmp = ((AD_MONEYNTRNL *) data)->mny_cents / 100.0;
	    CVfa(f8_tmp, 32, 2, 'f', '.', num_buf, &flt_wid);
	    tmp = flt_wid;
	    i = 0;
	    fmt[i++] = '%';
	    if (flt_wid >= 100)
	    {
		fmt[i++] = (tmp / 100) + '0';
		tmp = tmp % 100;
	    }
	    if (flt_wid >= 10)
	    {
		fmt[i++] = (tmp / 10) + '0';
		tmp = tmp % 10;
	    }
	    fmt[i++] = tmp + '0';
	    fmt[i++] = 's';
	    fmt[i] = EOS;
	    (*fcn)(STprintf(stbuf, fmt, num_buf));
	    break;

	  case DB_VCH_TYPE:
	  case DB_TXT_TYPE:
	  case DB_LTXT_TYPE:
	  case DB_VBYTE_TYPE:
	    I2ASSIGN_MACRO(((DB_TEXT_STRING *)data)->db_t_count, i2_tmp);
	    if (i2_tmp == 0)
	    {
	        (*fcn)(STprintf(stbuf,"''"));
		break;
	    }
	    (*fcn)(STprintf(stbuf, "'%*s'", i2_tmp, ((DB_TEXT_STRING *) data)->db_t_text));
	    break;

	  case DB_BOO_TYPE:
	    if (*((bool *) data))
	        (*fcn)(STprintf(stbuf,"TRUE"));
	    else
	        (*fcn)(STprintf(stbuf,"FALSE"));
	    break;

	  case DB_NCHR_TYPE:
	    for(i=0; i< blen/2; i++)
	    {
                I2ASSIGN_MACRO(data[2*i], i2_tmp);
                i4_tmp = i2_tmp;
                (*fcn)(STprintf(stbuf,"%x ", i4_tmp));
	     }
             break;

          case DB_NVCHR_TYPE:
          case DB_PAT_TYPE:
            I2ASSIGN_MACRO(((DB_NVCHR_STRING *)data)->count, i2_tmp);
	    if (bdt == DB_PAT_TYPE)
		i2_tmp = 4;
	    for(i=0; i< i2_tmp; i++)
            {
                I2ASSIGN_MACRO(((DB_NVCHR_STRING *)data)->element_array[i], i2_tmp2);
                i4_tmp = i2_tmp2;
		(*fcn)(STprintf(stbuf,"%x ", i4_tmp));
             }
             break;

	  case DB_LVCH_TYPE:
  	  case DB_LBYTE_TYPE:
  	  case DB_GEOM_TYPE:
          case DB_POINT_TYPE:
          case DB_MPOINT_TYPE:
          case DB_LINE_TYPE:
          case DB_MLINE_TYPE:
          case DB_POLY_TYPE:
          case DB_MPOLY_TYPE:
          case DB_GEOMC_TYPE:
	  case DB_LNVCHR_TYPE:
	    {
		ADP_PERIPHERAL	    *p = (ADP_PERIPHERAL *) data;
		ADP_COUPON	    *cpn;
		
		(*fcn)(STprintf(stbuf, "%s/length = (%d., %0d.):  ",
			(p->per_tag == ADP_P_COUPON ? "ADP_P_COUPON" :
				    "ADP_P_DATA"),
			p->per_length0, p->per_length1));
		if (p->per_tag == ADP_P_COUPON)
		{
		    cpn = &p->per_value.val_coupon;
		    
#if defined(axp_osf) || defined(ris_u64) || defined(LP64) || \
    defined(axp_lnx)
		    (*fcn)(STprintf(stbuf, "(%d.,%d.,%d.,%d.,%d.,%d.)",
			cpn->cpn_id[0],cpn->cpn_id[1],
			cpn->cpn_id[2],cpn->cpn_id[3],
			cpn->cpn_id[4],cpn->cpn_id[5]));
#else
		    (*fcn)(STprintf(stbuf, "(%d.,%d.,%d.,%d.,%d.)",
			cpn->cpn_id[0],cpn->cpn_id[1],
			cpn->cpn_id[2],cpn->cpn_id[3],
			cpn->cpn_id[4]));
#endif
		}
		else
		{
		    (*fcn)(STprintf(stbuf, "(first %d. of value) '%t'",
			    min(100, p->per_length1),
			    min(100, p->per_length1),
			    p->per_value.val_value));
		}
			
	    }
	    break;
	  default:
	    (*fcn)(STprintf(stbuf,
		    "< unknown type: don't know how to interpret data >"));
	    break;
	}
    }

    return;
}
Exemplo n.º 7
0
STATUS
adu_sc930prtdataval(
i4 msg_type,
char *parameter_name,
i4 parameter_no,
DB_DATA_VALUE      *db_dv,
ADF_CB *tzcb,
PTR file)
{
    char			num_buf[64];
    i2				flt_wid;
    f8				f8_tmp;
    AD_NEWDTNTRNL		dateval;
    AD_NEWDTNTRNL		*datep=&dateval;
    DB_TAB_LOGKEY_INTERNAL  	*tab_logkey;
    DB_OBJ_LOGKEY_INTERNAL  	*obj_logkey;
    DB_DT_ID			bdt;
    DB_STATUS			db_stat;
    i4				blen;
    i4				prec;
    char			*data;
    char			fmt[16];
    i4			tmp;
    i4			tcnt;
    i4				i;
    i4				res_wid;
    f4				f4_tmp;
    i4				i4_tmp;
    i2				i2_tmp, i2_tmp2;
    i1				i1_tmp;
    u_char 			u_tmp_i1;
    char			stbuf[SC930_DATAVAL_BUFSIZE];
    AD_DTUNION			*dp;
    i8				i8_tmp;
    char			*c_tmp,*c_buf_end;


    if (db_dv == NULL)
    {
	SIfprintf(file, "< Pointer to DB_DATA_VALUE is NULL >\n");
	return E_DB_ERROR;
    }

    if (parameter_name)
    {
	    STprintf(stbuf,"%d:%d(%s)=",
		db_dv->db_datatype,
		parameter_no,
	        parameter_name);
    } else
    {
	    STprintf(stbuf,"%d:%d=",
		db_dv->db_datatype,
	        parameter_no);
    }

    /* output the PARM/PARMEXEC 'header' to the trace file */
    switch (msg_type)
    {
	    case SC930_LTYPE_PARM:
		    SIfprintf(file,"PARM:%s",stbuf);
		    break;
	    case SC930_LTYPE_PARMEXEC:
		    SIfprintf(file,"PARMEXEC:%s",stbuf);
		    break;
	    default:
		    SIfprintf(file,"UNKNOWN:%s",stbuf);
    }

    bdt  = abs(db_dv->db_datatype);
    blen = db_dv->db_length - (db_dv->db_datatype < 0);
    prec = db_dv->db_prec;
    data = db_dv->db_data;

    if (data == NULL)
    {
	SIfprintf(file, "< pointer to data is NULL >\n");
	return E_DB_ERROR;
    }
    else if (ADI_ISNULL_MACRO(db_dv))
    {
	SIfprintf(file, "< NULL >\n");
	return OK;
    }
    else
    {
	switch (bdt)
	{
	  case DB_LOGKEY_TYPE:

	    obj_logkey = (DB_OBJ_LOGKEY_INTERNAL *) data;

	    SIfprintf(file, "olk_high_id = %x\tolk_low_id = %x\t"
				   "olk_rel_id = %d\tolk_db_id = %d\n" ,
		    obj_logkey->olk_high_id, obj_logkey->olk_low_id,
		    obj_logkey->olk_rel_id, obj_logkey->olk_db_id);
	    
	    break;

	  case DB_TABKEY_TYPE:

	    tab_logkey = (DB_TAB_LOGKEY_INTERNAL *) data;

	    SIfprintf(file, "tlk_high_id = %x\ttlk_low_id = %x\n",
		    tab_logkey->tlk_high_id, tab_logkey->tlk_low_id);

	    break;

	  case DB_CHA_TYPE:
	  case DB_CHR_TYPE:
	    if (blen == 0)
		SIfprintf(file, "''\n");
	    else
	        SIfprintf(file, "'%*s'\n", blen, (u_char *) data);

	    break;

	  case DB_DTE_TYPE:
	    db_stat = adu_6to_dtntrnl (tzcb, db_dv, datep);

	    if (datep->dn_status == 0)
	    {
		SIfprintf(file, "''\n");
		break;
	    }

	    SIfprintf(file,
		"(%s) %d/%d/%d %d:%d:%d.%.3d (%d)\n",
		(datep->dn_status & AD_DN_ABSOLUTE)?
		    ((datep->dn_status & AD_DN_TIMESPEC)?"DATETIME":"DATE")
		    :"INTERVAL",
		(i2)datep->dn_year,(i2)datep->dn_month,datep->dn_day,
		datep->dn_seconds / AD_39DTE_ISECPERHOUR,
		(datep->dn_seconds / AD_10DTE_ISECPERMIN) % 60,
		datep->dn_seconds % 60,
		(datep->dn_nsecond % AD_29DTE_NSPERMS), AD_TZ_OFFSETNEW(datep));
	    break;

	  case DB_ADTE_TYPE:
	    dp = (AD_DTUNION*)data;
	    SIfprintf(file,"%d/%d/%d\n",
		dp->adate.dn_year, dp->adate.dn_month, dp->adate.dn_day);
	    break;

	  case DB_TMWO_TYPE:
	  case DB_TMW_TYPE:
	  case DB_TME_TYPE:
	    dp = (AD_DTUNION*)data;
	    SIfprintf(file,"%d,%d +/- %d\n",
		dp->atime.dn_seconds, dp->atime.dn_nsecond,
		AD_TZ_OFFSET(&dp->atime));
	    break;

	  case DB_INYM_TYPE:
	    dp = (AD_DTUNION*)data;
	    SIfprintf(file,"%d %d\n",dp->aintym.dn_years, dp->aintym.dn_months);
	    break;

	  case DB_INDS_TYPE:
	    dp = (AD_DTUNION*)data;
	    SIfprintf(file,"%d %d %d\n", dp->aintds.dn_days,
		dp->aintds.dn_seconds, dp->aintds.dn_nseconds);
	    break;

	  case DB_TSWO_TYPE:
	  case DB_TSW_TYPE:
	  case DB_TSTMP_TYPE:
	    dp = (AD_DTUNION*)data;
	    SIfprintf(file,"%d/%d/%d %d %d (%d)\n",
		dp->atimestamp.dn_year, dp->atimestamp.dn_month,
		dp->atimestamp.dn_day,
		dp->atimestamp.dn_seconds, dp->atimestamp.dn_nsecond,
		AD_TZ_OFFSET(&dp->atimestamp));
	    break;
	  
	  case DB_DEC_TYPE:
	    CVpka(data,
		(i4)DB_P_DECODE_MACRO(prec),
		(i4)DB_S_DECODE_MACRO(prec),
		'.',
		(i4)DB_P_DECODE_MACRO(prec) + 5,
		(i4)DB_S_DECODE_MACRO(prec),
		CV_PKLEFTJUST,
		num_buf,
		&res_wid);
		
	    tmp = res_wid;
	    i = 0;
	    fmt[i++] = '%';
	    if (tmp >= 10)
	    {
		fmt[i++] = (tmp / 10) + '0';
		tmp = tmp % 10;
	    }
	    fmt[i++] = tmp + '0';
	    fmt[i++] = 's';
	    fmt[i++] = '\n';
	    fmt[i] = EOS;
	    SIfprintf(file, fmt, num_buf);
	    break;
	    
	  case DB_FLT_TYPE:
	    if (blen == 4)
	    {
		F4ASSIGN_MACRO(*data, f4_tmp);
		f8_tmp = f4_tmp;
	    }
	    else
		F8ASSIGN_MACRO(*data, f8_tmp);

	    CVfa(f8_tmp, (i4) sizeof(num_buf), (i4) 4, 'f', '.', num_buf, &flt_wid);
	    SIfprintf(file, "%*s\n", flt_wid, (u_char *) num_buf);
	    break;

	  case DB_INT_TYPE:
	    if (blen == 4)
	    {
		I4ASSIGN_MACRO(*data, i4_tmp);
	    }
	    else if (blen == 2)
	    {
		I2ASSIGN_MACRO(*data, i2_tmp);
		i4_tmp = i2_tmp;
	    }
	    else if (blen == 1)
	    {
		i4_tmp = I1_CHECK_MACRO(*(i1 *)data);
	    } else /* blen == 8 */
	    {
		I8ASSIGN_MACRO(*data,i8_tmp);
		CVla8(i8_tmp,num_buf);
	        SIfprintf(file, "%s\n", num_buf);
		break;
	    }
	    SIfprintf(file, "%d\n", i4_tmp);
	    break;

	  case DB_MNY_TYPE:
	    f8_tmp = ((AD_MONEYNTRNL *) data)->mny_cents / 100.0;
	    CVfa(f8_tmp, 32, 2, 'f', '.', num_buf, &flt_wid);
	    tmp = flt_wid;
	    i = 0;
	    fmt[i++] = '%';
	    if (flt_wid >= 100)
	    {
		fmt[i++] = (tmp / 100) + '0';
		tmp = tmp % 100;
	    }
	    if (flt_wid >= 10)
	    {
		fmt[i++] = (tmp / 10) + '0';
		tmp = tmp % 10;
	    }
	    fmt[i++] = tmp + '0';
	    fmt[i++] = 's';
	    fmt[i++] = '\n';
	    fmt[i] = EOS;
	    SIfprintf(file, fmt, num_buf);
	    break;

	  case DB_VCH_TYPE:
	  case DB_TXT_TYPE:
	  case DB_LTXT_TYPE:
	    I2ASSIGN_MACRO(((DB_TEXT_STRING *)data)->db_t_count, i2_tmp);
	    if (i2_tmp == 0)
	    {
		SIfprintf(file, "''\n");
	    }
	    else
	    {
	        SIfprintf(file, "'%*s'\n", i2_tmp, ((DB_TEXT_STRING *) data)->db_t_text);
	    }

	    break;

	  case DB_BOO_TYPE:
	    if (*((bool *) data))
		SIfprintf(file,"TRUE\n");
	    else
		SIfprintf(file,"FALSE\n");
	    break;

	  case DB_VBYTE_TYPE:
            I2ASSIGN_MACRO(((DB_TEXT_STRING *)data)->db_t_count, i2_tmp);
	    blen=i2_tmp;
	    data = ((DB_TEXT_STRING *)data)->db_t_text;

	  case DB_BYTE_TYPE:
	    c_tmp=stbuf;
	    c_buf_end=c_tmp + SC930_DATAVAL_BUFSIZE - 10;
	    STprintf(c_tmp,"%d:",blen);
	    c_tmp += STlength(c_tmp);
	    for(i=0; i< blen; i++)
	    {
                u_tmp_i1=(u_char) data[i];
                STprintf(c_tmp,"%02x ", u_tmp_i1);
		c_tmp += 3;
		if (c_tmp > c_buf_end )
		{
		  SIfprintf(file,stbuf);
		  c_tmp=stbuf;
		  stbuf[0]=EOS;
		}

	    }
            SIfprintf(file,"%s\n",stbuf);
            break;

	  case DB_NCHR_TYPE:
	    stbuf[0] = EOS;
	    c_tmp = stbuf;
	    c_buf_end=c_tmp + SC930_DATAVAL_BUFSIZE - 10;
	    for(i=0; i< blen/2; i++)
	    {
                I2ASSIGN_MACRO(data[2*i], i2_tmp);
                i4_tmp = i2_tmp;
                STprintf(c_tmp,"%x ", i4_tmp);
		c_tmp += STlength(c_tmp);
		if (c_tmp > c_buf_end )
		{
		  SIfprintf(file,stbuf);
		  c_tmp=stbuf;
		  stbuf[0]=EOS;
		}
	     }
             SIfprintf(file,"%s\n",stbuf);
             break;

          case DB_NVCHR_TYPE:
            I2ASSIGN_MACRO(((DB_NVCHR_STRING *)data)->count, i2_tmp);
	    stbuf[0] = EOS;
	    c_tmp = stbuf;
	    c_buf_end=c_tmp + SC930_DATAVAL_BUFSIZE - 10;
	    for(i=0; i< i2_tmp; i++)
            {
                I2ASSIGN_MACRO(((DB_NVCHR_STRING *)data)->element_array[i], i2_tmp2);
                i4_tmp = i2_tmp2;
                STprintf(c_tmp,"%x ", i4_tmp);
		c_tmp += STlength(c_tmp);
		if (c_tmp > c_buf_end )
		{
		  SIfprintf(file,stbuf);
		  c_tmp=stbuf;
		  stbuf[0]=EOS;
		}
             }
             SIfprintf(file,"%s\n",stbuf);
             break;

	  case DB_LVCH_TYPE:
  	  case DB_LBYTE_TYPE:
  	  case DB_GEOM_TYPE:
          case DB_POINT_TYPE:
          case DB_MPOINT_TYPE:
          case DB_LINE_TYPE:
          case DB_MLINE_TYPE:
          case DB_POLY_TYPE:
          case DB_MPOLY_TYPE:
          case DB_GEOMC_TYPE:
	  case DB_LNVCHR_TYPE:
	    {
		ADP_PERIPHERAL	*p = (ADP_PERIPHERAL *) data;
		ADP_COUPON	*cpn;
		DB_DATA_VALUE	dv_work;
		char tmp_val[DB_MAXSTRING + 1] = {0};
		i4 i;
		
		dv_work.db_datatype = DB_CHA_TYPE;
		dv_work.db_length = DB_MAXSTRING;
		dv_work.db_data = tmp_val;

		adu_lvch_move(tzcb, db_dv, &dv_work);

		i = DB_MAXSTRING;
		while (dv_work.db_data[i] == ' ')
			dv_work.db_data[i--] = EOS;

		SIfprintf(file, "(%d/%d):'%s'\n",p->per_length0,p->per_length1,
			dv_work.db_data);
	    }
	    break;

	  default:
            SIfprintf(file,
	        "< unknown type: don't know how to interpret data >\n");
            return E_DB_ERROR;
	}
    }

    return OK;
}
Exemplo n.º 8
0
/*{
** Name: adu_rdm2_finish	- Finish Redeeming an ADF_COUPON
**
** Description:
**      This routine completes the action of redeeming a coupon.
**      If running in test mode, this routine makes sure that the
**      varchar field is padded out with the appropriate amount of
**      garbage.
**
**      In general, it places the "closing remarks" in the
**      data stream.  This means that it will place the final segment
**      indicator (saying "no more") in the stream if the stream is
**      destined for GCA.  If the datatype is nullable, then the null
**      bit is set/cleared as appropriate.  If there is insufficient
**      room to make these closing remarks (or to supply the correct
**      amount of garbage in the test case), then the fip_state is set
**      to ADW_F_DONE_NEED_NULL, and an incomplete status is returned.
**      This status will set up the main redeem call to call this
**      routine again with a new buffer, repeating this action until
**      all is done.
**
** Inputs:
**      adf_scb                        Standard ADF SCB Ptr
**      result_dv                      Ptr to output area DB_DATA_VALUE
**      coupon_dv                      PTR to input area DB_DATA_VALUE
**      work                           Ptr to ADP_LO_WKSP in which work
**                                         is done.
**          ->adw_shared               Contains the result of the action
**                                         so far
**          ->adw_fip                  Contains more such results
**      for_gca                        Nat indicating whether the result
**                                         is destined for GCA
**                                         transmission.
**
** Outputs:
**      adf_scb->adf_error             Filled as appropriate.
**      result_dv->db_length           Set correctly.
**      work->adw_fip.fip_state        Set to indicate whether to
**                                         return.
**      work->adw_fip.fip_test*        Set to control the garbage
**                                         returned for the test cases.
**
**	Returns:
**	    DB_STATUS
**	Exceptions:
**	    None
**
** Side Effects:
**	    None
**
** History:
**      07-dec-1989 (fred)
**          Prototyped.
**      06-oct-1992 (fred)
**          Altered to work with timezone integration.  As a temporary measure,
**	    this routine was using the ADF_CB.adf_4rsvd field to store
**	    some context across calls.  In that this field disappeared, a new,
**	    more appropriately named field was added (adf_lo_context).  This
**	    new ADF_CB field is now used in this file.
**	30-Oct-1992 (fred)
**	    Fixed to correctly handle being called with a length too short
**	    for the original header.
**	20-Nov-1992 (fred)
**	    Rewritten for better clarity & better delineation of
**	    function in support of OME large objects.
[@history_template@]...
*/
DB_STATUS static
adu_rdm2_finish(ADF_CB             *adf_scb,
		DB_DATA_VALUE      *result_dv,
		DB_DATA_VALUE      *coupon_dv,
		ADP_LO_WKSP        *work,
		i4                for_gca)
{
    DB_STATUS         status = E_DB_OK;
    i4                zero = 0;

    if (work->adw_shared.shd_l1_check != work->adw_fip.fip_l1_value)
    {
	/* Fix_me -- get more detailed error message to log (log_key, */
	/* what's wrong, etc. */

	/* Then we are sending an inconsistent blob */

	status = adu_error(adf_scb, E_AD7004_ADP_BAD_BLOB,0);
    }
    else if (result_dv->db_length >=
	     (work->adw_shared.shd_o_used + (for_gca * sizeof(i4)) +
	                                        work->adw_fip.fip_null_bytes))

    {
	if (for_gca)
	{
	    I4ASSIGN_MACRO(zero,
			   result_dv->db_data[work->adw_shared.shd_o_used]);
	    work->adw_shared.shd_o_used += sizeof(i4);
	}
	if (work->adw_fip.fip_test_mode)
	{
	    work->adw_fip.fip_test_sent += sizeof(i4);
	    if (work->adw_fip.fip_test_sent <=
		    (work->adw_fip.fip_test_length -
		                      work->adw_fip.fip_null_bytes))

	    {
		/* Then there isn't enough to fill the varchar() */

		if (result_dv->db_length <
		    (work->adw_fip.fip_test_length
		         - work->adw_fip.fip_test_sent))
		{
		    /*
		    ** This is for test purposes only.
		    **
		    ** We need to send a true VARCHAR() datatype.
		    ** Thus, if the blob os smaller than that, then we
		    ** need to pad it out with garbage bytes.  To do
		    ** so, we will increment test_sent by the
		    ** remainder of the buffer, and happily return,
		    ** knowing that we will arrive here with an empty
		    ** buffer in the relatively near future.
		    **
		    ** To set test_sent appropriately, we must first
		    ** decrement it by the amount it was incremented
		    ** before arriving here.  Then we increment as
		    ** appropriate.
		    */
		
		    work->adw_fip.fip_test_sent -=
			work->adw_shared.shd_o_used; 
		    work->adw_fip.fip_test_sent += result_dv->db_length;
		    work->adw_fip.fip_state = ADW_F_DONE_NEED_NULL;
		    adf_scb->adf_errcb.ad_errcode  = E_AD0002_INCOMPLETE;
		    status = E_DB_INFO;
		}
	    }
	}
	
	if (status == E_DB_OK)
	{
	    result_dv->db_length = work->adw_shared.shd_o_used +
		    work->adw_fip.fip_null_bytes;
	    
	    if (work->adw_fip.fip_null_bytes)
	    {
		/*
		**	Then the datatype was nullable.  Copy the NULL byte
		**	from the coupon.
		*/
		
		if (ADI_ISNULL_MACRO(coupon_dv))
		{
		    ADF_SETNULL_MACRO(result_dv);
		}
		else
		{
		    ADF_CLRNULL_MACRO(result_dv);
		}
	    }
	    adf_scb->adf_errcb.ad_errcode = E_DB_OK;
	}
    }
    else
    {
	/*
	**  In this case, we are at the end of data, but the "closing
	**	remarks" (no more strings (if gca) and null bytes) doesn't
	**	fit in the buffer.
	**
	**  We mark this fact by setting the state to ADW_F_DONE_NEED_NULL.
	*/
	result_dv->db_length = work->adw_shared.shd_o_used;
	work->adw_fip.fip_state = ADW_F_DONE_NEED_NULL;

	adf_scb->adf_errcb.ad_errcode  = E_AD0002_INCOMPLETE;
	status = E_DB_INFO;
    }

    return(status);
}
Exemplo n.º 9
0
i4
main(
i4	argc,
char *	argv[])
{
    char      c='\0';
    char      *tz_file=NULL;
    char      *tz_name=NULL;
    char      *tz_def;
    char      tzname[TM_MAX_TZNAME+1];
    char      tzfile[MAX_LOC+1];
    char      ioptarg[MAX_LOC + 1];
    char      tz_pmvalue[MAX_LOC + 1];
    char      tz_pmname[MAX_LOC + 1];
    char      *p, *ip, *pm_value;
    char      *tm_tztype;
    char      chr='/';
    char      *out_file;
    i4        ioptind=1, i;
    char      *tm_tztime;
    i4        timecnt, tempi, temptype, temptz;
    char      buf[sizeof(TM_TZ_CB)+TM_MAX_TIMECNT*(sizeof(i4)+1)];
    FILE      *fid;
    LOCATION  loc_root, tmp_loc;
    STATUS    status=OK;
    TM_TZ_CB  *tm_tz_cb;
    struct timevect time_v;

    appname = argv[0];

    if( TMtz_getopt(argc, argv, "n:name:f:file", &ioptind, ioptarg, &c) == OK)
    {
	switch (c) 
	{
	  case 'f':
	    tz_file = ioptarg;
	    break;
	  case 'n':
	    tz_name = ioptarg;
	    break;
	  default:
	    break;
	}
    }
    else
    {
	TMtz_usage();
	PCexit(FAIL);
    }

    if( tz_file == NULL)
    {
	if( tz_name == NULL)
	{
	    /* Get II_TIMEZONE_NAME value */
	    NMgtAt(ERx("II_TIMEZONE_NAME"), &tz_def);
	    if (!tz_def || !(*tz_def))
	    {
		SIprintf("%s: %s_TIMEZONE_NAME is not set\n", 
				appname, SystemVarPrefix);
		PCexit(FAIL);
	    }
	    STncpy(tzname, tz_def, TM_MAX_TZNAME);
	    tzname[ TM_MAX_TZNAME ] = EOS;
	}
	else
	{
	    STncpy(tzname, tz_name, TM_MAX_TZNAME);
	    tzname[ TM_MAX_TZNAME ] = EOS;
	}
	PMinit();	
	if( PMload( NULL, (PM_ERR_FUNC *)NULL) != OK)
	{
	    SIprintf("%s: Error loading PM %s_CONFIG/config.dat file\n", 
			appname, SystemVarPrefix);
	    PCexit(FAIL);	    
	}
	/* Get timezone file name */
	STprintf( tz_pmname, ERx("%s.*.tz.%s"), SystemCfgPrefix, tzname);
	if( PMget( tz_pmname, &pm_value) != OK)
	{
	    SIprintf("%s: Error locating %s in PM config.dat file\n",
		     appname, tz_pmname);
    	    PCexit(FAIL);	    
	}
	do
	{
	    if((status = NMloc(FILES, PATH, ERx("zoneinfo"), &loc_root)) != OK)
		break;
#if defined(conf_BUILD_ARCH_32_64) && defined(BUILD_ARCH64)
	    if((status = LOfaddpath(&loc_root, ERx("lp64"), &loc_root)) != OK)
	        break;
#endif
#if defined(conf_BUILD_ARCH_64_32) && defined(BUILD_ARCH32)
	    {
	        /*
	        ** Reverse hybrid support must be available in ALL
	        ** 32bit binaries
	        */
	        char    *rhbsup;
	        NMgtAt("II_LP32_ENABLED", &rhbsup);
	        if ( (rhbsup && *rhbsup) &&
	       ( !(STbcompare(rhbsup, 0, "ON", 0, TRUE)) ||
	         !(STbcompare(rhbsup, 0, "TRUE", 0, TRUE))))
	            status = LOfaddpath(&loc_root, "lp32", &loc_root);
	    }
#endif /* reverse hybrid */

	    STcopy( pm_value, tz_pmvalue);

	    /*
	     ** Compose the directory path 
	     */
	    for( p = tz_pmvalue, ip = tz_pmvalue; 
		(p = STchr(ip, chr)) != NULL;)
	    {
		*p = EOS;
		if((status = LOfaddpath(&loc_root, ip, &loc_root)) != OK)
		    break;
		ip = CMnext(p);
	    }
	   
	    /* 
	    ** Add file name to the directory path
	    */
	    if((status = LOfroms(FILENAME, ip, &tmp_loc)) != OK)
		break;
	    status = LOstfile( &tmp_loc, &loc_root);
	} while( FALSE);

	if( status != OK)
	{
	    SIprintf("%s: Error composing timezone file name for %s\n",
		     appname, tz_pmvalue);
	    PCexit(FAIL);
	}
    }
    else
    {
	STcopy("<unknown>", tzname);
	STncpy( tzfile, tz_file, MAX_LOC);
	tzfile[ MAX_LOC ] = EOS;
	if( LOfroms(FILENAME&PATH, tzfile, &loc_root) != OK)
	{
	    SIprintf("%s: Error composing timezone file name for %s\n",
		     appname, tz_pmvalue);
	    PCexit(FAIL);
	}
    }

    /*
    ** Now open the timezone information file
    */
    do
    {
	if((status = SIfopen( &loc_root, ERx("r"), SI_VAR, sizeof buf, &fid)) 
	             != OK)
	    break;
	status = SIread(fid, sizeof buf, &i, buf);
	status = SIclose(fid);
    } while(FALSE);

    if( status != OK)
    {
	LOtos( &loc_root, &out_file);
	SIprintf("%s: Error opening %s for timezone %s\n", 
		 appname, out_file, tzname);
	PCexit(FAIL);
    }

    tm_tz_cb = (TM_TZ_CB *)&buf;
    I4ASSIGN_MACRO( tm_tz_cb->timecnt, timecnt);

    /* Make sure the input file has correct file size */
    if( timecnt > TM_MAX_TIMECNT || timecnt < 0
        || i != sizeof(TM_TZ_CB) + timecnt*(sizeof(i4)+1))
    {
	LOtos( &loc_root, &out_file);
	SIprintf(
	  "%s: Invalid file format for timezone file %s for timezone %s\n",
          appname, out_file, tzname);
	SIprintf(
	  "         File size: %d, Expected file size: %d, time periods: %d\n",
	  i, sizeof(TM_TZ_CB) + timecnt*(sizeof(i4)+1), 
	  timecnt);
	PCexit(FAIL);
    }

    /* Now we are all set to display the content of timezone information file */
    LOtos( &loc_root, &out_file);    
    SIprintf("\n\n");
    SIprintf("timezone name:     %s\n", tzname);
    SIprintf("timezone file:     %s\n", out_file);    
    SIprintf("-------------------------------------");
    SIprintf("-------------------------------------\n");

    if(timecnt == 0)
    {
	I4ASSIGN_MACRO( tm_tz_cb->tzinfo[0].gmtoff, tempi);
	SIprintf("     Fixed GMT offset (secs): %d\n", tempi);      
    }
    else
    {
	SIprintf("\tPeriod Begin");
	SIprintf("\t\tGMT offset\n");
	SIprintf("\t(YYYY_MM_DD HH:MM)");
	SIprintf("\t(Minute)\n\n");
	tm_tztype = buf + sizeof(TM_TZ_CB);
	tm_tztime = tm_tztype + timecnt;
	i=0;
	while( i < timecnt)
	{
	    I4ASSIGN_MACRO( *tm_tztime, tempi);
	    /* Adjust for timezone */
	    if( i == 0)
		temptype = (i4)tm_tztype[i+1];
	    else
		temptype = (i4)tm_tztype[i-1];

	    I4ASSIGN_MACRO( tm_tz_cb->tzinfo[temptype].gmtoff, temptz);
	    /* Get real timezone */
	    tempi += temptz;
	    temptype = (i4)tm_tztype[i];
	    I4ASSIGN_MACRO( tm_tz_cb->tzinfo[temptype].gmtoff, temptz);
	    TMtz_cvtime( tempi, &time_v);
	    SIprintf("\t%04d_%02d_%02d %02d:%02d\t%d\t%s\n", 
		     time_v.tm_year+1900,
		     time_v.tm_mon+1, 
		     time_v.tm_mday,
		     time_v.tm_hour,
		     time_v.tm_min,
		     temptz/60,
		     tm_tz_cb->tzlabel + tm_tz_cb->tzinfo[temptype].abbrind);  
	    tm_tztime += sizeof(i4);
	    i++;
	}
    }
    PCexit(OK);
}
Exemplo n.º 10
0
VOID
opc_querycomp(
		OPS_STATE          *global)
{
    DB_STATUS	    	ret;

    global->ops_gmask |= OPS_OPCEXCEPTION;  /* mark facility as being in OPC */
#ifdef OPT_F033_OPF_TO_OPC
    if (opt_strace(global->ops_cb, OPT_F033_OPF_TO_OPC) == TRUE)
    {
	char	temp[OPT_PBLEN + 1];
	bool	init = 0;

	if (global->ops_cstate.opc_prbuf == NULL)
	{
	    global->ops_cstate.opc_prbuf = temp;
	    init++;
	}

	/* Trace all of 'global' */
        if (global->ops_statement != NULL)
        {
	    opt_state(global);
	}
	    
	if (init)
	{
	    global->ops_cstate.opc_prbuf = NULL;
	}
    }
#endif

    if ( opt_strace(global->ops_cb, OPT_F071_QEP_WITHOUT_COST ) == TRUE && global->ops_subquery)
    {
	opt_cotree_without_stats( global );
    }

    /* If this is CREATE TABLE, check for primary, unique, foreign key
    ** constraints to use for default base table structure. */
    if (global->ops_statement &&
	global->ops_statement->pst_type == PST_CREATE_TABLE_TYPE &&
	global->ops_statement->pst_specific.pst_createTable.
			pst_createTableFlags == PST_CRT_TABLE)
    {
	QEU_CB *qeucb = global->ops_statement->pst_specific.pst_createTable.pst_createTableQEUCB;
	DMU_CB *dmucb = (DMU_CB *) qeucb->qeu_d_cb;
	bool checkit = FALSE;

	if (BTtest(DMU_AUTOSTRUCT, dmucb->dmu_chars.dmu_indicators))
	    checkit = (dmucb->dmu_chars.dmu_flags & DMU_FLAG_AUTOSTRUCT) != 0;
	else
	    checkit = opt_strace(global->ops_cb, OPT_F084_TBLAUTOSTRUCT ) ||
			global->ops_cb->ops_alter.ops_autostruct != 0;
	if (checkit)
	    opc_checkcons(global->ops_statement, dmucb);
    }

    /* On entry for rule processing, assume ops_qpinit == TRUE. There	    */
    /* is no need to allocate a memory stream since we are contuing	    */
    /* processing on the QP that was started by the triggering statement. */
    if (global->ops_qpinit == FALSE)
    {
	/* First, lets open the stack ULM memory stream that OPC uses */
	opu_Osmemory_open(global);

	/* Tell QSF that we want to store an object; */
	global->ops_qsfcb.qsf_obj_id.qso_type = QSO_QP_OBJ;
	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);
	    if (global->ops_caller_cb->opf_locator)
		MEcopy((PTR)"ql", sizeof("ql"), p);
	    else 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 if (   global->ops_procedure->pst_isdbp == TRUE
	    || (   global->ops_qheader != NULL
		&& (global->ops_qheader->pst_mask1 & PST_RPTQRY)
	       )
	   )
	{
	    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);
	}
	else
	{
	    global->ops_qsfcb.qsf_obj_id.qso_lname = 0;
	}

	/* Also allow for the case where a concurrent clash causes a new
	** object at an awkward point */
	if ((ret = qsf_call(QSO_CREATE, &global->ops_qsfcb)) != E_DB_OK &&
	    !(ret == E_DB_ERROR &&
		global->ops_qsfcb.qsf_error.err_code == E_QS001C_EXTRA_OBJECT) &&
	    !((global->ops_procedure->pst_flags & PST_SET_INPUT_PARAM)  &&
	     global->ops_qsfcb.qsf_error.err_code == E_QS001C_EXTRA_OBJECT))
	{
	    /* if object exists and we have a named query plan. */
	    if (global->ops_qsfcb.qsf_error.err_code
		    == E_QS000A_OBJ_ALREADY_EXISTS
	       )
	    {
		/* Log query info */
		QSO_OBID    *obj = &global->ops_qsfcb.qsf_obj_id;
		char	    *qrytype;
		char	    *objtype;
		char	    *objname;
		char	    *qrytext;
		char	    tmp[(DB_OWN_MAXNAME + DB_CURSOR_MAXNAME)  + 3 + 1];
		DB_STATUS   status;
		QSF_RCB	    qsf_rb;
		PSQ_QDESC   *qdesc;

		if (global->ops_procedure->pst_isdbp == TRUE)
		    qrytype = "database procedure";
		else if (global->ops_qheader != NULL
			 && (global->ops_qheader->pst_mask1 & PST_RPTQRY)
			)
		    qrytype = "repeat query";
		else
		    qrytype = "non-repeat query";

		objtype = "QSO_QP_OBJ";

		if (obj->qso_lname == 0)
		{
		    objname = "QSF object has no name";
		}
		else
		{
		    char	    fmt[30];
		    DB_CURSOR_ID    *curid;
		    char	    *user;
		    i4		    *dbid;

		    curid = (DB_CURSOR_ID *)obj->qso_name;
		    user = curid->db_cur_name + DB_CURSOR_MAXNAME;
		    dbid = (i4 *)(user + DB_OWN_MAXNAME);

		    STprintf(fmt, ":%%lx:%%lx:%%.%ds:%%.%ds:%%lx:",
			DB_CURSOR_MAXNAME, DB_OWN_MAXNAME);

		    STprintf(tmp, fmt, (i4)curid->db_cursor_id[0], 
			(i4)curid->db_cursor_id[1],
			curid->db_cur_name, user, (i4)(*dbid));

		    objname = tmp;
		}
 
		qsf_rb.qsf_type = QSFRB_CB;
		qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID;
		qsf_rb.qsf_length = sizeof(qsf_rb);
		qsf_rb.qsf_owner = (PTR)DB_OPF_ID;
		qsf_rb.qsf_obj_id.qso_handle = global->ops_caller_cb->opf_thandle;

		qrytext = "Query text was not available.";

		if (qsf_rb.qsf_obj_id.qso_handle != NULL)
		{
		    status = qsf_call(QSO_INFO, &qsf_rb);

		    if (DB_SUCCESS_MACRO(status))
		    {
			qdesc = (PSQ_QDESC*) qsf_rb.qsf_root;

			qrytext = qdesc->psq_qrytext;
		    }
		}

		/* log an error */
		opx_lerror((OPX_ERROR)E_OP089F_QSF_FAILCREATE, (i4)4,
		    (PTR)qrytype, (PTR)objtype, (PTR)objname, (PTR)qrytext);
	    }

	    opx_verror(ret, E_OP0882_QSF_CREATE, 
		global->ops_qsfcb.qsf_error.err_code);
	}

	/* Put the handle for the QEP into the callers CB; 
	** - will be used for deallocation in case of an error
	** - both the object id and the lock id are needed in order to destroy
	** the object
	*/
	STRUCT_ASSIGN_MACRO(global->ops_qsfcb.qsf_obj_id,
	    global->ops_caller_cb->opf_qep);
	global->ops_qplk_id = global->ops_qsfcb.qsf_lk_id;
	global->ops_qpinit = TRUE;

	/* Allocate and initialize the QP. */
	opc_iqp_init(global);
    }

    /* Continue the QP compilation by adding the current statement */
    if (global->ops_statement != NULL)
    {
	opc_cqp_continue(global);
    }

    /* if it's time to stop compiling the query, then lets close stuff. */
    /* The caller is responsible for making one additional call to OPC	    */
    /* with ops_statement == NULL after all statements in the QP we are	    */
    /* currently building have been compiled. Note that this is a change    */
    /* from the previous version of this routine which required the extra   */
    /* call only if a db procedure was being compiled. Such a call must	    */
    /* also be made after the last statement in each rule list. This allows */
    /* OPC to link all conditionals statements in the rule list together    */
    /* before continuing with the next user statement to be compiled. */
    if (global->ops_statement == NULL)
    {
	/* We're finished compiling all of the statements, so lets finish
	** the QP
	*/
	opc_fqp_finish(global);

	/* The QP is only associated with the outer query, not a rule list  */
	if (!global->ops_inAfterRules && !global->ops_inBeforeRules)
	{
	    /* Tell QSF what the root of the QEP is; */
	    global->ops_qsfcb.qsf_root = (PTR) global->ops_cstate.opc_qp;
	    if ((ret = qsf_call(QSO_SETROOT, &global->ops_qsfcb)) != E_DB_OK)
	    {
		opx_verror(ret, E_OP0883_QSF_SETROOT, 
					global->ops_qsfcb.qsf_error.err_code);
	    }

	    if ((ret = qsf_call(QSO_UNLOCK, &global->ops_qsfcb)) != E_DB_OK)
	    {
		opx_verror(ret, E_OP089E_QSF_UNLOCK, 
		    global->ops_qsfcb.qsf_error.err_code);
	    }

	    /* Now lets close the stack ULM memory stream that OPC used */
	    opu_Csmemory_close(global);
	}
    }
    global->ops_gmask &= (~OPS_OPCEXCEPTION);  /* mark facility as leaving OPC */
}
Exemplo n.º 11
0
/*{
** Name: psy_kproc - Drop a database procedure definition from
**		     the system catalogs.
**
** Description:
**
** Inputs:
**
** Outputs:

**	Exceptions:
**	    none
**
** Side Effects:
**	    Modifies system catalogs.
**
** History:
**      27-apr-88 (stec)
**	    Created.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	12-jun-90 (andre)
**	    when trying to destroy a dbproc QEP, use "private" alias, which is
**	    always defined as opposed to the "public" alias which would not be
**	    defined if the dbproc is not grantable.
**	06-aug-92 (teresa)
**	    change interface to invalidate procedure by name, owner.
**	    must set rdr_flags_mask = RDR_PROCEDURE when invalidating the
**	    procedure cache object.
**	07-nov-92 (andre)
**	    we will no longer create private aliases for dbproc QPs
**	16-jun-94 (andre)
**	    it is dangerous to cast a (char *) into a (DB_CURSOR_ID *) and then
**	    dereference the resulting pointer because the chat ptr may not be 
**	    pointing at memory not aligned on an appopriate boundary.  Instead,
**	    we will allocate a DB_CURSOR_ID structure on the stack, initialize 
**	    it and MEcopy() it into the char array
*/
DB_STATUS
psy_kproc(
	PSY_CB		*psy_cb,
	PSS_SESBLK	*sess_cb)
{
    RDF_CB		rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    DB_STATUS		status, stat;
    i4		err_code;

    pst_rdfcb_init(&rdf_cb, sess_cb);
    (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME),
	(PTR)&rdf_rb->rdr_name.rdr_prcname);
    STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner);
    rdf_rb->rdr_types_mask = RDR_PROCEDURE;
    rdf_rb->rdr_update_op = RDR_DELETE;

    status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);

    if (DB_FAILURE_MACRO(status))
    {
	if (rdf_cb.rdf_error.err_code == E_RD0013_NO_TUPLE_FOUND)
	{
	    /* Retry */
	    psy_cb->psy_error.err_code = E_PS0008_RETRY;
	}
	else
	{
	    (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
		&psy_cb->psy_error);
	    return (status);
	}
    }

    /* Try to destroy the procedure QP in QSF if things went OK. */
    if (DB_SUCCESS_MACRO(status))
    {
    	QSF_RCB		qsf_rb;
	PSS_DBPALIAS	dbpid;
	DB_CURSOR_ID	dbp_curs_id;

	/* Initialize the header of the QSF control block */
	qsf_rb.qsf_type = QSFRB_CB;
	qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID;
	qsf_rb.qsf_length = sizeof(qsf_rb);
	qsf_rb.qsf_owner = (PTR)DB_PSF_ID;
	qsf_rb.qsf_sid = sess_cb->pss_sessid;

	qsf_rb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ;
	qsf_rb.qsf_feobj_id.qso_lname = sizeof(dbpid);

	/* Identify the object first */
	dbp_curs_id.db_cursor_id[0] = dbp_curs_id.db_cursor_id[1] = 0;
	(VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], DB_TAB_MAXNAME,
	    (PTR)dbp_curs_id.db_cur_name);
	MEcopy((PTR) &dbp_curs_id, sizeof(DB_CURSOR_ID), (PTR) dbpid);

	(VOID) MEcopy((PTR) &sess_cb->pss_user, DB_OWN_MAXNAME,
	    (PTR) (dbpid + sizeof(DB_CURSOR_ID)));

	I4ASSIGN_MACRO(sess_cb->pss_udbid,
		       *(i4 *) (dbpid + sizeof(DB_CURSOR_ID) + DB_OWN_MAXNAME));

	(VOID)MEcopy((PTR) dbpid, sizeof(dbpid),
	    (PTR) qsf_rb.qsf_feobj_id.qso_name);

	/* See if QEP for the alias already exists. */
	qsf_rb.qsf_lk_state = QSO_SHLOCK;
	stat = qsf_call(QSO_JUST_TRANS, &qsf_rb);

	if (DB_FAILURE_MACRO(stat))
	{
	    if (qsf_rb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ)
	    {
		(VOID) psf_error(E_PS037A_QSF_TRANS_ERR,
		    qsf_rb.qsf_error.err_code, PSF_INTERR,
		    &err_code, &psy_cb->psy_error, 0);
		if (stat > status)
		    status = stat;
		goto exit;
	    }
	    else
	    {
		/* Nothing to destroy, QP not in QSF */
		goto exit;
	    }
	}

	/* Now destroy the ALIAS and the QP objects in QSF */
	stat = qsf_call(QSO_DESTROY, &qsf_rb);

	if (DB_FAILURE_MACRO(stat))
	{
	    (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code,
		    PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    if (stat > status)
		status = stat;
	}
    }

    /* Invalidate procedure object from RDF cache */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME),
	(PTR)&rdf_rb->rdr_name.rdr_prcname);
    STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner);
    rdf_rb->rdr_types_mask = RDR_PROCEDURE;
    status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb);
    if (DB_FAILURE_MACRO(status))
    {
	(VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error,
			&psy_cb->psy_error);
    }

exit:
    return (status);
}
Exemplo n.º 12
0
/*{
** Name: psy_cproc - Create a database procedure definition in
**		     the system catalogs.
**
** Description:
**
** Inputs:
**
** Outputs:
**	Exceptions:
**	    none
**
** Side Effects:
**	    Modifies system catalogs.
**
** History:
**      27-apr-88 (stec)
**	    Created.
**	23-aug-88 (stec)
**	    Added comments, initialize new fields in DB_PROCEDURE.
**	26-apr-89 (andre)
**	    For internal procedures, set db_mask[0] to DB_IPROC.
**	12-mar-90 (andre)
**	    set rdr_2types_mask to 0.
**      22-may-90 (teg)
**          init rdr_instr to RDF_NO_INSTR
**	12-jun-90 (andre)
**	    when trying to destroy a dbproc QEP, use "private" alias, which is
**	    always defined as opposed to the "public" alias which would not be
**	    defined if the dbproc is not grantable.
**	04-mar-92 (andre)
**	    set DB_ACTIVE_DBP in db_mask[0] to indicate that the dbproc is not
**	    abandoned.  If the dbproc is grantable, set DB_DBPGRANT_OK in
**	    db_mask[0].
**	18-may-92 (andre)
**	    call psy_dbp_status() to verify that the new dbproc is not abandoned
**	    and trust psy_dbp_status() to determine whether the dbproc is
**	    grantable or just active.
**	19-may-92 (andre)
**	    in pslsgram.yi, pss_dependencies_stream was opened to collect info
**	    about objects/privileges on which the new dbproc depends;
**	    this stream must be closed before leaving this function since the
**	    dependence information will be of no use once we return
**	01-jun-92 (andre)
**	    pass information about objects/privileges on which the new database
**	    procedure depends to QEF.
**	26-jun-92 (andre)
**	    enter information about the dbproc into IIPROCEDURE and the list of
**	    objects and privileges on which it depends into IIDBDEPENDS and
**	    IIPRIV respectively before calling psy_dbp_status() to determine
**	    whether it is active.  This is necessary since otherwise it would be
**	    impossible to create mutually recursive database procedures (if P1
**	    calls P2 and we are trying to create P2 calling P1, psy_dbp_status()
**	    will report that P1 is dormant and prevent us from creating P2)
**
**	    Since we won't know whether the dbproc is active and/or grantable
**	    until psy_dbp_status() is done, we will set only DB_DBP_INDEP_LIST
**	    bit in IIPROCEDURE.dbp_mask1 here, unless the independent
**	    object/privilege list is empty, in which case there is no reason to
**	    call psy_dbp_status(), so we will set DB_DBPGRANT_OK and
**	    DB_ACTIVE_DBP bits in IIPROCEDURE.dbp_mask1.
**
**	    If the independent object/privilege list is not empty and the
**	    procedure is not dormant, psy_dbp_status() will set appropriate bits
**	    (DB_DBPGRANT_OK and/or DB_ACTIVE_DBP) in IIPROCEDURE.dbp_mask1 once
**	    it has determined whether the dbproc is active or grantable
**	09-sep-92 (andre)
**	    psy_dbp_status() no longer accepts or returns an indicator of
**	    whether cache had to be flushed in psy_dbp_priv_check()
**	07-nov-92 (andre)
**	    we will no longer create private aliases for dbproc QPs
**	22-feb-93 (rblumer)
**	    initialize new RDF proc_param variables for both normal and
**	    set-input procedures; reverse order of MEcopy and I4assign in
**	    QP cleanup code so that qsf id gets set up correctly.
**	13-apr-93 (andre)
**	    if creating a system-generated procedure, independent
**	    object/privilege list will be empty - QEF will insert IIDBDEPENDS
**	    tuple recording dependence of the dbproc on a constraint (for
**	    constraint-enforcing dbprocs) or view (for CHECK OPTION-enforcing
**	    dbprocs.)  Here we will set bits indicating that there will be
**	    independent object list and that the dbproc is active but not
**	    grantable (we don't want the user to grant privileges on
**	    system-generated dbprocs)
**	01-sep-93 (andre)
**	    in the course of parsing a dbproc definition, we will try to 
**	    determine id of a base table on which the dbproc depends; here we
**	    will copy it into proctuple.dbPdbp_ubt_id to ensure that it gets 
**	    inserted into IIPROCEDURE
**	22-oct-93 (rblumer)
**	    normal procedures will now have their parameters inserted into the
**	    catalogs (previously just set-input procedures did); changed
**	    initialization of db_parameterCount, rdr_proc_param_cnt and
**	    rdr_proc_params to work for both types of procedures.
**	30-apr-94 (andre)
**	    fix for bug 61087:
**	    proctuple.db_mask[0] was being set before proctuple was MEfill'd 
**	    with NULLCHAR; moved the line initializing proctuple.db_mask[0] 
**	    below call to MEfill() 
**	16-jun-94 (andre)
**	    Bug #64395
**	    it is dangerous to cast a (char *) into a (DB_CURSOR_ID *) and then
**	    dereference the resulting pointer because the chat ptr may not be 
**	    pointing at memory not aligned on an appopriate boundary.  Instead,
**	    we will allocate a DB_CURSOR_ID structure on the stack, initialize 
**	    it and MEcopy() it into the char array
**	19-june-06 (dougi)
**	    Add DBP_DATA_CHANGE flag for BEFORE trigger validation.
**	28-march-2008 (dougi)
**	    Changes to support table procedures and named result row elements.
**	4-feb-2009 (dougi)
**	    Tidy up computation of table procedure result row length.
**	30-mar-2009 (toumi01) b121871
**	    Rewrite and simplify the computation of table procedure input
**	    and output parameter count and width (fixes a logic error that
**	    caused the result width to be decremented by the width of the
**	    first result parameter when there were no input parameters).
*/
DB_STATUS
psy_cproc(
	PSY_CB	   *psy_cb,
	PSS_SESBLK *sess_cb)
{
    RDF_CB		rdf_cb;
    register RDR_RB	*rdf_rb = &rdf_cb.rdf_rb;
    i4			textlen;
    QSF_RCB		qsf_rb;
    DB_PROCEDURE	proctuple;
    DB_STATUS		status, stat;
    i4		err_code;
    PSY_TBL		dbp_descr;
    i4			dbp_mask[2];
    bool		empty_indep_list, rowproc;

    /* If this is a recreate case, and this code gets called
    ** just return since there is no work to be done, not even
    ** recovery of resources.
    */
    if (sess_cb->pss_dbp_flags & PSS_RECREATE)
	return(E_DB_OK);

    /* determine if the new dbproc depends on any object or privileges */
    if (   sess_cb->pss_indep_objs.psq_objs
	|| sess_cb->pss_indep_objs.psq_objprivs
	|| sess_cb->pss_indep_objs.psq_colprivs
       )
    {
	empty_indep_list = FALSE;
    }
    else
    {
	empty_indep_list = TRUE;
    }

    /*
    ** Initialize the header of the QSF control block
    ** NOTE: it is important that we init qsf_rb before calling
    **       psy_dbp_status() - if the dbproc cannot be created, code under
    **	     exit: will expect the control block set up for deleting the query
    **	     text QSF object and the query plan QSF object
    */
    qsf_rb.qsf_type = QSFRB_CB;
    qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID;
    qsf_rb.qsf_length = sizeof(qsf_rb);
    qsf_rb.qsf_owner = (PTR)DB_PSF_ID;
    qsf_rb.qsf_sid = sess_cb->pss_sessid;
    STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id);

    /* Retrieve info about the procedure text object */
    status = qsf_call(QSO_INFO, &qsf_rb);

    if (DB_FAILURE_MACRO(status))
    {
	goto exit;
    }

    /* Get the text length. */
    MEcopy((PTR) qsf_rb.qsf_root, sizeof(i4), (PTR) &textlen);

    /* Initialize the II_PROCEDURE tuple. */
    MEfill(sizeof(proctuple), NULLCHAR, (PTR) &proctuple);

    (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME),   
	(PTR)&proctuple.db_dbpname);

    /* Current user is the owner. */
    STRUCT_ASSIGN_MACRO(sess_cb->pss_user, proctuple.db_owner);

    proctuple.db_txtlen = textlen;

    TMnow((SYSTIME *) &proctuple.db_txtid);

    /*
    ** if the independent object/privilege list is non-empty, we will set
    ** DB_DBP_INDEP_LIST bit and leave it to psy_dbp_status() to set the
    ** remaining bits, if appropriate; otherwise we will set DB_DBPGRANT_OK and
    ** DB_ACTIVE_DBP bits and avoid calling psy_dbp_status()
    **
    ** if creating a system-generated dbproc, mark the dbproc ACTIVE and
    ** indicate that there is independent object list (there is not one at this
    ** point, but QEF will insert IIDBDEPENDS tuple recording dependence of the
    ** dbproc on a constraint (for constraint-enforcing dbprocs) or view (for
    ** CHECK OPTION-enforcingdbprocs.)
    */
    
    /* If working on internal dbproc, set DB_IPROC in db_mask[0] */
    if (sess_cb->pss_dbp_flags & PSS_IPROC)
	proctuple.db_mask[0] |= DB_IPROC;

    if (sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED)
	proctuple.db_mask[0] |=
	    DBP_SYSTEM_GENERATED | DB_ACTIVE_DBP | DB_DBP_INDEP_LIST;
    else if (empty_indep_list)
	proctuple.db_mask[0] |= DB_DBPGRANT_OK | DB_ACTIVE_DBP;
    else
	proctuple.db_mask[0] |= DB_DBP_INDEP_LIST;

    if (sess_cb->pss_dbp_flags & PSS_SET_INPUT_PARAM)
	proctuple.db_mask[0] |= DBP_SETINPUT;

    if (sess_cb->pss_dbp_flags & PSS_NOT_DROPPABLE)
	proctuple.db_mask[0] |= DBP_NOT_DROPPABLE;

    if (sess_cb->pss_dbp_flags & PSS_SUPPORTS_CONS)
	proctuple.db_mask[0] |= DBP_CONS;

    if (sess_cb->pss_dbp_flags & PSS_DATA_CHANGE)
	proctuple.db_mask[0] |= DBP_DATA_CHANGE;

    if (sess_cb->pss_dbp_flags & PSS_OUT_PARMS)
	proctuple.db_mask[0] |= DBP_OUT_PARMS;

    if (sess_cb->pss_dbp_flags & PSS_TX_STMT)
	proctuple.db_mask[0] |= DBP_TX_STMT;

    if (sess_cb->pss_dbp_flags & PSS_ROW_PROC)
    {
	rowproc = TRUE;
	proctuple.db_mask[0] |= DBP_ROW_PROC;
    }
    else rowproc = FALSE;

    proctuple.db_mask[1] = 0;

    /*
    ** if we were able to determine id of a base table on which this dbproc will
    ** depend, copy it into proctuple
    */
    proctuple.db_dbp_ubt_id.db_tab_base  = sess_cb->pss_dbp_ubt_id.db_tab_base;
    proctuple.db_dbp_ubt_id.db_tab_index = sess_cb->pss_dbp_ubt_id.db_tab_index;

    /* db_procid to be filled in by RDF or QEF */

    proctuple.db_parameterCount = 0;
    proctuple.db_recordWidth    = 0;
    proctuple.db_rescolCount = 0;
    proctuple.db_resrowWidth    = 0;

    if (sess_cb->pss_procparmlist != (QEF_DATA *) NULL)
    {
	DB_PROCEDURE_PARAMETER	*param_tuple;
	QEF_DATA		*listptr;

	/* compute count and total width of input and result parameters */
	for (listptr = sess_cb->pss_procparmlist;
	     listptr != (QEF_DATA *) NULL;
	     listptr = listptr->dt_next)
	{
	    param_tuple = (DB_PROCEDURE_PARAMETER *)listptr->dt_data;
	    if (param_tuple->dbpp_flags & DBPP_RESULT_COL)
	    {
		proctuple.db_rescolCount++;
		proctuple.db_resrowWidth = param_tuple->dbpp_offset 
			+ param_tuple->dbpp_length;
	    }
	    else
	    {
		proctuple.db_parameterCount++;
		proctuple.db_recordWidth = param_tuple->dbpp_offset 
			+ param_tuple->dbpp_length;
	    }
	}
	if (proctuple.db_rescolCount > 0)
	    proctuple.db_resrowWidth -= proctuple.db_recordWidth;
    }

    /* Initialize the RDF request block. */
    pst_rdfcb_init(&rdf_cb, sess_cb);
    (VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], sizeof(DB_DBP_NAME),
	(PTR)&rdf_rb->rdr_name.rdr_prcname);
    STRUCT_ASSIGN_MACRO(sess_cb->pss_user, rdf_rb->rdr_owner);
    rdf_rb->rdr_types_mask = RDR_PROCEDURE;
    rdf_rb->rdr_update_op = RDR_APPEND;
    rdf_rb->rdr_qrytuple = (PTR) &proctuple; 
    rdf_rb->rdr_l_querytext = textlen;
    rdf_rb->rdr_querytext = ((char *) qsf_rb.qsf_root) + sizeof(i4);

    /*
    ** pass information about objects/privileges on which the new database
    ** procedure depends to QEF
    */
    sess_cb->pss_indep_objs.psq_grantee = &sess_cb->pss_user;
    rdf_rb->rdr_indep = (PTR) &sess_cb->pss_indep_objs;

    /* fill in the description of the procedure's parameters
    ** (which RDF/QEF will store into iiprocedure_parameter);
    */
    rdf_rb->rdr_proc_param_cnt = proctuple.db_parameterCount
					+ proctuple.db_rescolCount;
    rdf_rb->rdr_proc_params    = sess_cb->pss_procparmlist;

    /* Create a new procedure in the system catalogs */
    status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb);

    if (DB_FAILURE_MACRO(status))
    {
	if (rdf_cb.rdf_error.err_code == E_RD0137_DUPLICATE_PROCS)
	{
	    /* Retry */
	    psy_cb->psy_error.err_code = E_PS0008_RETRY;
	}
	else
	{
	    (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error,
		&psy_cb->psy_error);
	}

	goto exit;
    }

    /*
    ** if the independent object/privilege list is non-empty, verify that the
    ** dbproc we are about to create is not abandoned; strictly speaking, as
    ** long as the independent object list is empty, we are guaranteed that the
    ** dbproc is not abandoned (user posesses required privileges), but we will
    ** take an extra step and try to determine whether it is grantable
    */
    if (!empty_indep_list)
    {
	MEcopy((PTR) psy_cb->psy_tabname, sizeof(DB_DBP_NAME),
	    (PTR) &dbp_descr.psy_tabnm);
	dbp_descr.psy_tabid.db_tab_base = proctuple.db_procid.db_tab_base;
	dbp_descr.psy_tabid.db_tab_index = proctuple.db_procid.db_tab_index;
	
	status = psy_dbp_status(&dbp_descr, sess_cb, (PSF_QUEUE *) NULL,
	    (i4) PSQ_CREDBP, dbp_mask, &psy_cb->psy_error);
	if (DB_FAILURE_MACRO(status))
	{
	    goto exit;
	}
    }


exit:

    /*
    ** close the memory stream which was used to allocate descriptors of
    ** objects/privileges on which the new dbproc depends
    */
    stat = psf_mclose(sess_cb, sess_cb->pss_dependencies_stream, &psy_cb->psy_error);
    if (DB_FAILURE_MACRO(stat) && stat > status)
	status = stat;

    /*
    ** ensure that no one tries to use the stream that is no longer valid
    */
    sess_cb->pss_dependencies_stream = (PSF_MSTREAM *) NULL;

    /* Get a lock on the query text from QSF */
    qsf_rb.qsf_lk_state = QSO_EXLOCK;

    stat = qsf_call(QSO_LOCK, &qsf_rb);

    if (DB_FAILURE_MACRO(stat))
    {
	(VOID) psf_error(E_PS0A08_CANTLOCK, qsf_rb.qsf_error.err_code,
	    PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	if (stat > status)
	    status = stat;
    }
    else
    {
	/* Now destroy the query text */
	stat = qsf_call(QSO_DESTROY, &qsf_rb);

	if (DB_FAILURE_MACRO(stat))
	{
	    (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code,
		PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    if (stat > status)
		status = stat;
	}
    }


    /* Destroy the procedure QP in QSF if things went wrong. */
    if (DB_FAILURE_MACRO(status))
    {
	PSS_DBPALIAS	dbpid;
	DB_CURSOR_ID	dbp_curs_id;

	qsf_rb.qsf_feobj_id.qso_type = QSO_ALIAS_OBJ;
	qsf_rb.qsf_feobj_id.qso_lname = sizeof(dbpid);

	/* Identify the object first */
	dbp_curs_id.db_cursor_id[0] = dbp_curs_id.db_cursor_id[1] = 0;
	(VOID) MEcopy((PTR)&psy_cb->psy_tabname[0], DB_TAB_MAXNAME,
	    (PTR)dbp_curs_id.db_cur_name);
	MEcopy((PTR) &dbp_curs_id, sizeof(DB_CURSOR_ID), (PTR) dbpid);

	(VOID) MEcopy((PTR) &sess_cb->pss_user, DB_OWN_MAXNAME,
	    (PTR) (dbpid + sizeof(DB_CURSOR_ID)));

	I4ASSIGN_MACRO(sess_cb->pss_udbid,
		       *(i4 *) (dbpid + sizeof(DB_CURSOR_ID) + DB_OWN_MAXNAME));

	(VOID)MEcopy((PTR) dbpid, sizeof(dbpid),
	    (PTR) qsf_rb.qsf_feobj_id.qso_name);

	/* See if QP for the alias already exists. */
	qsf_rb.qsf_lk_state = QSO_SHLOCK;
	stat = qsf_call(QSO_JUST_TRANS, &qsf_rb);

	if (DB_FAILURE_MACRO(stat))
	{
	    if (qsf_rb.qsf_error.err_code != E_QS0019_UNKNOWN_OBJ)
	    {
		(VOID) psf_error(E_PS037A_QSF_TRANS_ERR,
		    qsf_rb.qsf_error.err_code, PSF_INTERR,
		    &err_code, &psy_cb->psy_error, 0);
		if (stat > status)
		    status = stat;
		goto exit1;
	    }
	    else
	    {
		/* QP disappeared, which is alright. */
		goto exit1;
	    }
	}

	/* Now destroy the QP object in QSF */
	stat = qsf_call(QSO_DESTROY, &qsf_rb);

	if (DB_FAILURE_MACRO(stat))
	{
	    (VOID) psf_error(E_PS0A09_CANTDESTROY, qsf_rb.qsf_error.err_code,
		    PSF_INTERR, &err_code, &psy_cb->psy_error, 0);
	    if (stat > status)
		status = stat;
	}
    }

exit1:
    return (status);
}
Exemplo n.º 13
0
/*{
** Name: adt_compare() - Compare 2 data values.
**
** Description:
**	This routine compares two data values.  This will tell the caller if the
**	supplied values are equal, or if not, which one is "greater than" the
**	other.
**
**	This routine exists as a performance boost for DMF.  DMF is not allowed
**	to know how to compare data values for the various datatypes.
**	Therefore, if this routine did not exist, DMF would have to make a
**	function call to "adc_compare()" for every attribute in the tuples
**	being compared.  Even though tuples are constructs that seem a level
**	above what ADF logically handles, the performance improvement in this
**	case justifies this routine.
**
**	To avoid the overhead of an adc_compare call,
**	this routine has built into it the semantics for
**	comparing several of the most common datatypes supported by INGRES.
**
**	If the routine does run across a datatype that is not in this list, it
**	will call the general routine "adc_compare()", thereby guaranteeing
**	that it will function (perhaps slower), for ALL datatypes, even future
**	user defined ADTs.
**
**	When NULL values are involved, this routine will use the same semantics
**	that "adc_compare()" uses:  a NULL value will be considered greater
**	than any other value, and equal to another NULL value.
**
**	PLEASE NOTE:  As with "adc_compare()", no pattern matching for
**	-----------   the string datatypes is done within this routine.
**
**
** Inputs:
**	adf_scb				Pointer to an ADF session control block.
**	    .adf_errcb			ADF_ERROR struct.
**		.ad_ebuflen		The length, in bytes, of the buffer
**					pointed to by ad_errmsgp.
**		.ad_errmsgp		Pointer to a buffer to put formatted
**					error message in, if necessary.
**      atr                             Pointer to DB_ATTR.
**      d1                        	Pointer to first value.
**      d2                              Pointer to second value.
**
** Outputs:
**	adf_scb				Pointer to an ADF session control block.
**	    .adf_errcb			ADF_ERROR struct.  If an
**					error occurs the following fields will
**					be set.  NOTE: if .ad_ebuflen = 0 or
**					.ad_errmsgp = NULL, no error message
**					will be formatted.
**		.ad_errcode		ADF error code for the error.
**		.ad_errclass		Signifies the ADF error class.
**		.ad_usererr		If .ad_errclass is ADF_USER_ERROR,
**					this field is set to the corresponding
**					user error which will either map to
**					an ADF error code or a user-error code.
**		.ad_emsglen		The length, in bytes, of the resulting
**					formatted error message.
**		.adf_errmsgp		Pointer to the formatted error message.
**      status                          Status returned from
**					adc_compare(), if called.
**	
**	    The following DB_STATUS codes may be returned by adc_compare():
**	    E_DB_OK, E_DB_WARN, E_DB_ERROR, E_DB_SEVERE, E_DB_FATAL
**
**	    If a DB_STATUS code other than E_DB_OK is returned, the caller
**	    can look in the field adf_scb.adf_errcb.ad_errcode to determine
**	    the ADF error code.  The following is a list of possible ADF error
**	    codes that can be returned by this routine:
**
**          E_AD0000_OK                 Operation succeeded.
**          E_AD2004_BAD_DTID           Datatype id unknown to ADF.
**          E_AD2005_BAD_DTLEN          Internal length is illegal for
**					the given datatype.
**		(Others not yet defined)
**
** Returns:
**      i4  < 0   if 1st < 2nd
**          = 0   if 1st = 2nd
**          > 0   if 1st > 2nd
**
** Exceptions:
**       none
**
** Side Effects:
**       none
**
** History:
**      10-Feb-86 (thurston)
**          Initial creation.
**	03-apr-86 (thurston)
**	    Initial coding.  Also, added two more return statuses (stati?):
**          E_AD2004_BAD_DTID and E_AD2005_BAD_DTLEN.
**      11-jun-86 (jennifer)
**          Fixed bug compare result asigned to adt_cmp_result instead
**          of indirect through this pointer, i.e. *adt_cmp_result.
**      11-jun-86 (jennifer)
**	    Fixed bug where the first entry of attribute array (0)
**          was being used.  This entry is always garbage since 
**          attributes are numbered from 1.
**      27-jul-86 (ericj)
**	    Converted for new ADF error handling.
**	19-nov-86 (thurston)
**	    Fixed the comparison for text.
**	22-sep-88 (thurston)
**	    Added bit representation check as a first pass on each attr.  Also,
**	    added code to deal with nullable types here ... this could be a big
**	    win, since all nullable types were going through adc_compare(), now
**	    they need not.  Also, added cases for CHAR and VARCHAR.
**	21-oct-88 (thurston)
**	    Got rid of all of the `#ifdef BYTE_ALIGN' stuff by using the
**	    appropriate [I2,I4,F4,F8]ASSIGN_MACROs.  This also avoids a bunch
**	    of MEcopy() calls on BYTE_ALIGN machines.
**	21-Apr-89 (anton)
**	    Added local collation support
**	17-Jun-89 (anton)
**	    Moved local collation routines to ADU from CL
**	25-jul-89 (jrb)
**	    Added support for decimal datatype.
**	02-jan-90 (jrb)
**	    Fix alignment problem.
**	08-aug-91 (seg)
**	    "d1" and "d2" are dereferenced too often with the assumption
**	    that (PTR) == (char *) to fix.  Made them (char *).
**	28-mar-2001 (abbjo03)
**	    Add support for DB_NCHR_TYPE and DB_NVCHR_TYPE.
**	16-dec-04 (inkdo01)
**	    Add collation ID parm to aduucmp() calls.
**	02-Feb-2005 (jenjo02)
**	    Consolidated from the nine adt functions which duplicated
**	    this "compare" code. Runs the most optimal compare
**	    based on datatype for a single attribute.
**
**	    Optimized CHA/VCH compares to use MEcmp rather than
**	    CMcmpcase loop when possible.
**
**	    Replace giant switch statement with if-then-else
**	    ordered most likely to least likely, more or less.
**	    The switch was consuming 27% of the CPU used by this
**	    function.
**
**	    Added DB_STATUS *status as a function parameter so
**	    if adc_compare returns an error, it will be returned
**	    to the caller rather than as a bogus compare "result".
**	27-Apr-2005 (jenjo02 for stial01)
**	    Replaced computing compare value using arithmetic
**	    (d1 - d2) with logical compares ( d1 < d2...) as
**	    the arithmetic may over/underflow and return the
**	    wrong result.
**	13-May-2005 (thaju02)
**	    For differing length vchar, return value based on 
**	    comparison of longer length vchar to blank. (B114514)
**	19-Jun-2006 (gupsh01)
**	    Added support for new date/time types.
**	3-may-2007 (dougi)
**	    Tweak slightly to allow MEcmp() on collation/double byte
**	    if they're bytewise equal.
**	10-may-2007 (dougi)
**	    Add logic to handle ordering of c/text/char/varchar in UTF8
**	    server.
**	25-jul-2007 (gupsh01)	
**	    Although UTF8 is multibyte it is meant to be processed through
**	    UTF8 comparison code utilizing unicode comparison.
**	17-Aug-2007 (gupsh01)
**	    Fix the UTF8 handling.
*/
i4
adt_compare(
ADF_CB		    *adf_scb,
DB_ATTS		    *atr,		/* Attribute in question */
char		    *d1,		/* Ptr to 1st value */
char		    *d2,		/* Ptr to 2nd value */
DB_STATUS	    *status)		/* Status from adc_compare */

{
    i4			cur_cmp;	/* Result of latest attr cmp */
    i4			vi1, vi2;	/* Temp i4's used to cmp ints */
    i8			lli1, lli2;	/* Compare i8's */
    f8			vf1, vf2;	/* Temp f8's used to cmp flts */
    u_char	        *lc1, *lc2;
    u_char	        blank;
    i4			atr_bdt;	/* Base datatype of attr */
    i2			atr_len;	/* Length of cur attribute */
    i4			d1_isnull, d2_isnull;
    DB_DATA_VALUE	dv1, dv2;	/* Data value structs for call
					** to adc_compare(), if that is
					** necessary.
					*/
    u_char		*tc1, *tc2;	/* Temps used for string compare */
    u_char		*endtc1, *endtc2;
    UCS2		*tn1, *tn2;	/* Temps used for Nstring compare */
    UCS2		*endtn1, *endtn2;
	/*
	**  The following four lines provide temp storage to solve
	**  byte allignment problems on some archictectures.
	*/
    i2			i2_t1, i2_t2;
    i4			i4_t1, i4_t2;
    f4			f4_t1, f4_t2;
    f8			f8_t1, f8_t2;

#define	ADT_LT	(i4)-1
#define ADT_EQ	(i4)0
#define	ADT_GT	(i4)1

    *status = E_DB_OK;

    atr_len = atr->length;

    if ( (atr_bdt = atr->type) < 0 )
    {
	/* Nullable datatype */

	d1_isnull = (*((char *)d1 + atr_len - 1) & ADF_NVL_BIT);
	d2_isnull = (*((char *)d2 + atr_len - 1) & ADF_NVL_BIT);

	if ( !d1_isnull && !d2_isnull )
	{
	    /* Neither is the Null value, look at data */
	    atr_bdt = -atr_bdt;
	    atr_len--;
	}
	else if (d1_isnull && d2_isnull)
	    return(ADT_EQ);   /* both are Null values; 1st = 2nd */
	else if (d1_isnull)
	    return(ADT_GT);   /* 1st is Null value; 1st > 2nd */
	else
	    return(ADT_LT);  /* 2nd is Null value; 1st < 2nd */
    }

    /* "if then else" consumes ~27% less CPU than "switch" */

    if ( atr_bdt == DB_INT_TYPE )
    {
	/* If both operands aligned... */
	/* Extra casts to shut up compilers -- only care about low bits */
	if ( (((i4)(SCALARP)d1 | (i4)(SCALARP)d2) & atr_len-1) == 0 )
	{
	    if ( atr_len == 4 )
	    {
		if      (*(i4*)d1 < *(i4*)d2)	return(ADT_LT);
		else if (*(i4*)d1 > *(i4*)d2)	return(ADT_GT);
		else			  	return(ADT_EQ);
	    }
	    if ( atr_len == 8 )
	    {
		if      (*(i8*)d1 < *(i8*)d2)	return(ADT_LT);
		else if (*(i8*)d1 > *(i8*)d2)	return(ADT_GT);
		else			  	return(ADT_EQ);
	    }
	    if ( atr_len == 2 )
	    {
		if      (*(i2*)d1 < *(i2*)d2)	return(ADT_LT);
		else if (*(i2*)d1 > *(i2*)d2)	return(ADT_GT);
		else			  	return(ADT_EQ);
	    }
	
	    if      (*(i1*)d1 < *(i1*)d2)	return(ADT_LT);
	    else if (*(i1*)d1 > *(i1*)d2)	return(ADT_GT);
	    else			  	return(ADT_EQ);
	}
	/* One or both not aligned... */
	if (atr_len == 4)
	{
	    I4ASSIGN_MACRO(*d1, i4_t1);
	    I4ASSIGN_MACRO(*d2, i4_t2);
	    if      (i4_t1 < i4_t2)	return(ADT_LT);
	    else if (i4_t1 > i4_t2)	return(ADT_GT);
	    else			return(ADT_EQ);
	}
	if (atr_len == 8)
	{
	    I8ASSIGN_MACRO(*d1, lli1);
	    I8ASSIGN_MACRO(*d2, lli2);
	    if      (lli1 < lli2)	return(ADT_LT);
	    else if (lli1 > lli2)	return(ADT_GT);
	    else		  	return(ADT_EQ);
	}
	if (atr_len == 2)
	{
	    I2ASSIGN_MACRO(*d1, i2_t1);
	    I2ASSIGN_MACRO(*d2, i2_t2);
	    if      (i2_t1 < i2_t2)	return(ADT_LT);
	    else if (i2_t1 > i2_t2)	return(ADT_GT);
	    else			return(ADT_EQ);
	}
	if      (*(i1*)d1 < *(i1*)d2)	return(ADT_LT);
	else if (*(i1*)d1 > *(i1*)d2)	return(ADT_GT);
	else			  	return(ADT_EQ);
    }

    if ( atr_bdt == DB_FLT_TYPE || atr_bdt == DB_MNY_TYPE )
    {
	/* If both operands aligned... */
	/* Extra casts to shut up compilers, only care about low bits */
	if ( (((i4)(SCALARP)d1 | (i4)(SCALARP)d2) & atr_len-1) == 0 )
	{
	    if ( atr_len == 8 )
	    {
		if      (*(f8*)d1 < *(f8*)d2) return(ADT_LT);
		else if (*(f8*)d1 > *(f8*)d2) return(ADT_GT);
		else                  	  return(ADT_EQ);
	    }
	    if      (*(f4*)d1 < *(f4*)d2) return(ADT_LT);
	    else if (*(f4*)d1 > *(f4*)d2) return(ADT_GT);
	    else                  	  return(ADT_EQ);
	}

	/* One or both not aligned... */
	if ( atr_len == 8 )
	{
	    F8ASSIGN_MACRO(*d1, f8_t1);
	    F8ASSIGN_MACRO(*d2, f8_t2);
	    if      (f8_t1 < f8_t2) return(ADT_LT);
	    else if (f8_t1 > f8_t2) return(ADT_GT);
	    else   		    return(ADT_EQ);
	}
	F4ASSIGN_MACRO(*d1, f4_t1);
	F4ASSIGN_MACRO(*d2, f4_t2);
	if      (f4_t1 < f4_t2) return(ADT_LT);
	else if (f4_t1 > f4_t2) return(ADT_GT);
	else   		        return(ADT_EQ);
    }

    if ( atr_bdt == DB_BYTE_TYPE || atr_bdt == DB_TABKEY_TYPE ||
	      atr_bdt == DB_LOGKEY_TYPE )
    {
	return(MEcmp(d1, d2, atr_len));
    }

    if ( atr_bdt == DB_CHA_TYPE || atr_bdt == DB_VCH_TYPE )
    {
	if ( atr_bdt == DB_CHA_TYPE )
	{
	    /* Try the turbo compare. */
	    cur_cmp = MEcmp(d1, d2, atr_len);

	    /* If not equal and UTF8-enabled ... */
	    if (cur_cmp && (adf_scb->adf_utf8_flag & AD_UTF8_ENABLED))
		return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

	    /* If neither collation nor doublebyte or if byte-wise equal ... */
	    if ( !(adf_scb->adf_collation || 
		   Adf_globs->Adi_status & ADI_DBLBYTE) || cur_cmp == 0)
	    {
		return(cur_cmp);
	    }

	    tc1    = (u_char *) d1;
	    tc2    = (u_char *) d2;
	    endtc1 = tc1 + atr_len;
	    endtc2 = tc2 + atr_len;
	}
	else
	{
	    I2ASSIGN_MACRO(((DB_TEXT_STRING *)d1)->db_t_count, i2_t1);
	    I2ASSIGN_MACRO(((DB_TEXT_STRING *)d2)->db_t_count, i2_t2);
	    tc1 = (u_char *)d1 + DB_CNTSIZE;
	    tc2 = (u_char *)d2 + DB_CNTSIZE;

	    /* Try the turbo compare on the prefix. */
	    cur_cmp = MEcmp((char *)tc1, (char *)tc2, min(i2_t1, i2_t2));

	    /* If neither collation nor doublebyte... */
	    if ( !(adf_scb->adf_collation || 
		   Adf_globs->Adi_status & ADI_DBLBYTE) || 
			(adf_scb->adf_utf8_flag & AD_UTF8_ENABLED))
	    {
		i2	diff = i2_t1 - i2_t2;
	    
		/* If not equal or lengths differ and UTF8-enabled ... */
		if ((diff || cur_cmp) && 
			(adf_scb->adf_utf8_flag & AD_UTF8_ENABLED))
		    return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

		/* If short compare produces inequality or lengths are
		** the same ... */
		if ( cur_cmp || diff == 0 )
		{
		    return(cur_cmp);
		}

		/*
		** Equal for shorter length.
		** If longer trails all blanks, they're equal
		*/
		if ( diff > 0 )
		{
		    /* tc1 is longer */
		    tc1 += i2_t2;
		    while ( *(tc1++) == MIN_CHAR && --diff > 0 );

		    if (!diff)
			return( ADT_EQ );
		    else
		    {
			tc1--;
			if (*tc1 > MIN_CHAR)
			    return(ADT_GT);
			else
			    return(ADT_LT);
		    }
		}
		else
		{
		    /* tc2 is longer */
		    tc2 += i2_t1;
		    while ( *(tc2++) == MIN_CHAR && ++diff < 0 );

		    if (!diff)
			return( ADT_EQ );
		    else
		    {
			tc2--;
			if (MIN_CHAR > *tc2)
			    return(ADT_GT);
			else 
			    return(ADT_LT);
		    }
		}

	    }
	    else if (i2_t1 == i2_t2 && cur_cmp == 0)
		return(cur_cmp);	/* byte wise compare returns "=" */

	    endtc1 = tc1 + i2_t1;
	    endtc2 = tc2 + i2_t2;
	}

	if (adf_scb->adf_collation)
	    return(adugcmp((ADULTABLE *)adf_scb->adf_collation,
			 ADUL_BLANKPAD, tc1, endtc1, tc2, endtc2));

	/* Doublebyte is rather more tedious */
	blank = (u_char)MIN_CHAR;
	cur_cmp = ADT_EQ;
	
	while ( cur_cmp == ADT_EQ )
	{
	    if (tc1 < endtc1)
	    {
		lc1 = tc1;
		CMnext(tc1);
	    }
	    else
	    {
		lc1 = &blank;
	    }
	    
	    if (tc2 < endtc2)
	    {
		lc2 = tc2;
		CMnext(tc2);
	    }
	    else
	    {
		lc2 = &blank;
	    }
	    
	    /* if both pointing to blank or we happen to be comparing
	    ** a string to itself then break
	    */
	    if (lc1 == lc2)
		break;
	    
	    cur_cmp = CMcmpcase(lc1, lc2);
	}
	return(cur_cmp);
    }

    if ( atr_bdt == DB_NCHR_TYPE || atr_bdt == DB_NVCHR_TYPE )
    {
	if ( atr_bdt == DB_NCHR_TYPE )
	{
	    tn1 = (UCS2 *)d1;
	    tn2 = (UCS2 *)d2;
	    endtn1 = tn1 + atr_len / sizeof(UCS2);
	    endtn2 = tn2 + atr_len / sizeof(UCS2);
	}
	else
	{
	    tn1 = ((DB_NVCHR_STRING *)d1)->element_array;
	    tn2 = ((DB_NVCHR_STRING *)d2)->element_array;
	    I2ASSIGN_MACRO(((DB_NVCHR_STRING *)d1)->count, i2_t1);
	    I2ASSIGN_MACRO(((DB_NVCHR_STRING *)d2)->count, i2_t2);
	    endtn1 = tn1 + i2_t1;
	    endtn2 = tn2 + i2_t2;
	}
      
	*status = aduucmp(adf_scb, ADUL_BLANKPAD,
	    tn1, endtn1, tn2, endtn2, &cur_cmp, atr->collID);
	return (cur_cmp);
    }

    if ( atr_bdt == DB_CHR_TYPE )
    {
	if (adf_scb->adf_utf8_flag & AD_UTF8_ENABLED)
	    return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

	if (adf_scb->adf_collation)
	    return(adugcmp((ADULTABLE *)adf_scb->adf_collation,
			     ADUL_SKIPBLANK, (u_char *)d1,
			     atr_len + (u_char *)d1, (u_char *)d2,
			     atr_len + (u_char *)d2));
	return(STscompare((char *)d1, atr_len, (char *)d2, atr_len));
    }

    if ( atr_bdt == DB_TXT_TYPE )
    {
	if (adf_scb->adf_utf8_flag & AD_UTF8_ENABLED)
	    return(adt_utf8comp(adf_scb, atr, atr_bdt, atr_len, 
							d1, d2, status));

	I2ASSIGN_MACRO(((DB_TEXT_STRING *)d1)->db_t_count, i2_t1);
	I2ASSIGN_MACRO(((DB_TEXT_STRING *)d2)->db_t_count, i2_t2);
	tc1 = (u_char *)d1 + DB_CNTSIZE;
	tc2 = (u_char *)d2 + DB_CNTSIZE;
	endtc1 = tc1 + i2_t1;
	endtc2 = tc2 + i2_t2;

	if (adf_scb->adf_collation)
	    return(adugcmp((ADULTABLE *)adf_scb->adf_collation,
			     0, tc1, endtc1, tc2, endtc2));

	cur_cmp = ADT_EQ;
	while (cur_cmp == ADT_EQ && tc1 < endtc1  &&  tc2 < endtc2)
	{
	    if ( (cur_cmp = CMcmpcase(tc1, tc2)) == ADT_EQ )
	    {
		CMnext(tc1);
		CMnext(tc2);
	    }
	}
	
	/* If equal up to shorter, short strings < long */
	return( (cur_cmp) ? cur_cmp : (endtc1 - tc1) - (endtc2 - tc2) );
    }

    if ( atr_bdt == DB_DEC_TYPE )
    {
	/*  See if the bit representation is identical. */
	if ( MEcmp(d1, d2, atr_len) )
	{
	    i4	    pr;
	    i4	    sc;

	    pr = DB_P_DECODE_MACRO(atr->precision);
	    sc = DB_S_DECODE_MACRO(atr->precision);
	    return(MHpkcmp((PTR)d1, pr, sc, (PTR)d2, pr, sc));
	}
	return(ADT_EQ);
    }

    /* Bit-equivalent dates we can handle here */
    if (( atr_bdt == DB_DTE_TYPE || 
	 atr_bdt == DB_ADTE_TYPE ||
	 atr_bdt == DB_TMWO_TYPE ||
	 atr_bdt == DB_TMW_TYPE ||
	 atr_bdt == DB_TME_TYPE ||
	 atr_bdt == DB_TSWO_TYPE ||
	 atr_bdt == DB_TSW_TYPE ||
	 atr_bdt == DB_TSTMP_TYPE ||
	 atr_bdt == DB_INYM_TYPE ||
	 atr_bdt == DB_INDS_TYPE ) &&
	MEcmp(d1, d2, (u_i2)atr_len) == 0 )
    {
	return(ADT_EQ);
    }

    /* Will have to do it the slow way */
    dv1.db_datatype = dv2.db_datatype = (DB_DT_ID)atr_bdt;
    dv1.db_prec = dv2.db_prec = atr->precision;
    dv1.db_length = dv2.db_length = atr_len;
    dv1.db_collID = dv2.db_collID = atr->collID;
    dv1.db_data = d1;
    dv2.db_data = d2;
    *status = adc_compare(adf_scb, &dv1, &dv2, &cur_cmp);

    return(cur_cmp);
}
Exemplo n.º 14
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 );
}
Exemplo n.º 15
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 */
    }
}
Exemplo n.º 16
0
/*{
** Name: LGadd	- Add Database.
**
** Description:
**	Add database to logging system for a process.
**
**      This routine adds a database to the logging system.  This service
**	is used to inform the logging system that records recorded in the log
**	file should be associated with this database.  A database can be 
**	marked as journaled by setting the LG_JOURNAL flag.  The fact that a
**	database is journaled is used by the logging system to recognize the
**	need to copy log records from the log file to a journal file.
**
** NOTE on adding databases that are being recovered:
**	When a database requires REDO recovery, the LDB for that database
**	is marked LDB_RECOVER.  This routine will return LG_DB_INCONSISTENT
**	(signifying that the database is inconsistent) if anyone tries
**	to add the db while it is being recovered.  This is not a very
**	on-line solution.
**
**	A better solution is to make sure that servers that want to open
**	a database that is currently being recovered are forced to wait
**	until the db is fully recovered, then they should be able to
**	proceed.
**
** Inputs:
**      lg_id                           Log identifier.
**	flag				Zero or
**					    LG_JOURNAL: if a journaled DB.
** 					    LG_NOTDB: not a DB; administrative
** 					    LG_PRETEND_CONSISTENT: used by verifydb
** 					    LG_FCT: fast commit
** 					    LG_READONLY: a readonly database
**	buffer				Database information buffer.
**      l_buffer                        Length of buffer.
**
** Outputs:
**      db_id                           Database identifier. Unique
**                                      identifier associated with this
**                                      instantiation of the logging/locking
**                                      server.  After logging/locking 
**                                      restarted, a database can have
**                                      a different id.
**      sys_err                         Reason for error return status.
**	Returns:
**	    OK				Success.
**	    LG_BADPARAM			Bad parameters to call.
**	    LG_DB_INCONSISTENT		Inconsistent database.
**	    LG_EXCEED_LIMIT		Out of LDB's.
**	    LG_SHUTTING_DOWN		Shutdown has occured (or pending).
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	Summer, 1992 (bryanp)
**	    Working on the new portable logging and locking system.
**	18-jan-1993 (rogerk)
**	    Removed LG_WILLING_COMMIT flag - now only LG_ADDONLY is used
**	    during recovery processing.  Add ldb_j_last_la, ldb_d_last_la
**	    fields.
**	15-mar-1993 (rogerk)
**	    Reduced Logging - Phase IV:
**	    Removed LG_ADDONLY flag.  Recovery processing now adds db with
**		a normal LGadd call and alters it via LG_A_DBCONTEXT to
**		reestablish its context.
**	26-apr-1993 (bryanp)
**	    6.5 Cluster Support:
**		Add ldb_sback_lsn field to the LDB.
**		Make sure that lpd_type is set so that LPDs can be deallocated
**		    properly upon error.
**	26-jul-1993 (bryanp)
**	    When adding a database which is associated with a remote log file,
**		do not signal a local opening of the database. This occurs
**		when the CSP process on one node is recovering the work
**		performed by another node; in this case we do NOT wish to
**		signal to the RCP that a local open is being performed, since
**		in fact no local access is implied by adding this database.
**	    When adding the notdb again, increment the ldb_lpd_count even if
**		the ldb_buffer info doesn't match. The notdb is always the notdb
**	26-jul-1993 (rogerk)
**	    Changed journal and dump window tracking in the logging system.
**	    Use new journal and dump log address fields.
**	12-oct-1993 (tad)
**	    Bug #56449
**	    Changed %x to %p for pointer values.
**	30-Jan-1996 (jenjo02)
**	    Reorganized LG_add() such that if NOTDB is wanted, 
**	    the search of the ldb queue is bypassed; after all,
**	    we know it's buried in the LGD and easy to find.
**	11-Sep-1996 (jenjo02)
**	    Fix a bug in LG_add() search of lgd_ldb_q which was looping
**	    if more that 2 LDBs were extant.
** 	13-jun-1997 (wonst02)
** 	    Added LG_READONLY and LDB_READONLY for readonly databases.
**	12-nov-1998 (kitch01)
**		Bug 90140. If the database is currently pending a close then
**		mark the open as in CLOSE_WAIT. This will ensure that the close
**		is processed before this open and prevent locking errors on the journals
**      7-oct-2004 (thaju02)
**          Use SIZE_TYPE to allow memory pools > 2Gig.
        21-Jun-2006 (hanal04) Bug 116272
**          Take the lgd_mutex before the ldb_mutex in order to ensure
**          the acquisition order is consistent with LG_archive_complete()
**          and LG_event(). Flag LG_signal_event() that we already have the
**          lgd_mutex.
**	01-Nov-2006 (jonj)
**	    Use consistent ldb_q_mutex, ldb_mutex ordering thoughout the code.
**	    Don't put LDB on queue until it's completely initialized.
**	15-Jan-2010 (jonj)
**	    SIR 121619 MVCC: Initialize new ldb_active_lxbq.
**      09-aug-2010 (maspa05) b123189, b123960
**          Pass flag to indicate a readonly database LDB_RODB, so that it
**          gets picked up by LGshow
*/
STATUS
LGadd(
LG_LGID             external_lg_id,
i4		    flag,
char		    *buffer,
i4		    l_buffer,
LG_DBID		    *external_db_id,
CL_ERR_DESC	    *sys_err)
{
    register LGD        *lgd = (LGD *)LGK_base.lgk_lgd_ptr;
    register LPB	*lpb;
    register LDB	*ldb;
    register LFB	*lfb;
    register LPD	*lpd;
    LDB			*next_ldb;
    LPD			*next_lpd;
    SIZE_TYPE		end_offset;
    SIZE_TYPE		ldb_offset;
    SIZE_TYPE		*lpbb_table;
    SIZE_TYPE		*ldbb_table;
    i4			err_code;
    bool		initialize_ldb = FALSE;
    STATUS		status;
    LG_I4ID_TO_ID	lg_id;
    LG_ID		*db_id = (LG_ID*)external_db_id;
    LFB			*cur_db_lfb;
    i4			SignalEvent = 0;

    /*
    ** If the logging system is already in "shutdown" mode, then no new
    ** LGadd calls are permitted
    */
    LG_WHERE("LGadd")

    CL_CLEAR_ERR(sys_err);

    if ((lgd->lgd_status & (LGD_START_SHUTDOWN | LGD_IMM_SHUTDOWN)) != 0)
	return (LG_SHUTTING_DOWN);

    if (l_buffer == 0 ||
	l_buffer > sizeof(ldb->ldb_buffer))
    {
	uleFormat(NULL, E_DMA411_LGADD_BAD_LEN, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
		    0, l_buffer, 0, sizeof(ldb->ldb_buffer));
	return (LG_BADPARAM);
    }

    /*	Check the lg_id. */

    lg_id.id_i4id = external_lg_id;
    if (lg_id.id_lgid.id_id == 0 || (i4)lg_id.id_lgid.id_id > lgd->lgd_lpbb_count)
    {
	uleFormat(NULL, E_DMA40F_LGADD_BAD_ID, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
		    0, lg_id.id_lgid.id_id, 0, lgd->lgd_lpbb_count);
	return (LG_BADPARAM);
    }

    lpbb_table = (SIZE_TYPE *)LGK_PTR_FROM_OFFSET(lgd->lgd_lpbb_table);
    lpb = (LPB *)LGK_PTR_FROM_OFFSET(lpbb_table[lg_id.id_lgid.id_id]);

    if (status = LG_mutex(SEM_EXCL, &lpb->lpb_mutex))
	return(status);

    if (lpb->lpb_type != LPB_TYPE ||
	lpb->lpb_id.id_instance != lg_id.id_lgid.id_instance)
    {
	(VOID)LG_unmutex(&lpb->lpb_mutex);
	uleFormat(NULL, E_DMA410_LGADD_BAD_PROC, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 3,
		    0, lpb->lpb_type, 0, lpb->lpb_id.id_instance,
		    0, lg_id.id_lgid.id_instance);
	return (LG_BADPARAM);
    }

    /*
    **  Allocate an LPD, causing lpd_type to be set to LPD_TYPE.
    */

    if ((lpd = (LPD *)LG_allocate_cb(LPD_TYPE)) == 0) 
    {
	(VOID)LG_unmutex(&lpb->lpb_mutex);
	return (LG_EXCEED_LIMIT);
    }

    /*
    ** CLEANUP: error returns after this point must free the lpd before
    **		returning! 
    */

    lfb = (LFB *)LGK_PTR_FROM_OFFSET(lpb->lpb_lfb_offset);

    /*
    ** If this isn't a real user database, but is instead the "NOTDB"
    ** database which is used by system processes such as the DMFRCP and
    ** DMFACP daemons, then it has a special reserved LDB slot and does not
    ** get located by its database information buffer, therefore we
    ** can skip locking and scanning the ldb queue.
    */
    end_offset = LGK_OFFSET_FROM_PTR(&lgd->lgd_ldb_next);

    /*
    ** When both the lgd_ldb_q and ldb must be mutexed, always take
    ** the lgd_ldb_q_mutex, then ldb_mutex.
    */

    /* Lock and hold the ldb queue mutex */
    if (status = LG_mutex(SEM_EXCL, &lgd->lgd_ldb_q_mutex))
	return(status);

    if (flag & LG_NOTDB)
    {
	ldbb_table = (SIZE_TYPE *)LGK_PTR_FROM_OFFSET(lgd->lgd_ldbb_table);
	ldb = (LDB *)LGK_PTR_FROM_OFFSET(ldbb_table[1]);

	if (status = LG_mutex(SEM_EXCL, &ldb->ldb_mutex))
	    return(status);

	/*
	** IF the notdb has already been initialized, then we have some
	** caller who is adding the notdb with a different buffer, thus
	** we didn't match when we searched the database list for a
	** matching ldb_buffer field. Since we really don't care about the
	** ldb_buffer for the notdb (the notdb is the notdb, after all),
	** we'll treat this case as though the ldb buffer fields matched.
	*/
	if (ldb->ldb_type == LDB_TYPE)
	{
	    /*  Count new reference to LDB. */
	    ldb->ldb_lpd_count++;
	}
	else
	{
	    /*
	    ** first use of NOTDB; initialize it.
	    */
	    lgd->lgd_ldb_inuse++;
	    initialize_ldb = TRUE;
	}
    }
    else
    {
	/*
	** Scan database list to see if this database is already known. Each
	** database is identified by a "database information buffer", which DMF
	** passes in. This buffer contains items such as the database name, owner
	** name, etc. If the database information buffer passed to LGadd exactly
	** matches the database information buffer of an existing LDB, then this
	** database is already known (has already been added by another logging
	** system process).
	*/

	for (ldb_offset = lgd->lgd_ldb_next;
	    ldb_offset != end_offset;)
	{
	    ldb = (LDB *)LGK_PTR_FROM_OFFSET(ldb_offset);

	    if (ldb->ldb_l_buffer != l_buffer ||
		MEcmp(ldb->ldb_buffer, buffer, l_buffer))
	    {
		ldb_offset = ldb->ldb_next;
		continue;
	    }

	    if ( CXcluster_enabled() )
	    {
	        /*
		** Node recovery must use distinct ldb context per node log file
		*/
		cur_db_lfb = (LFB *)LGK_PTR_FROM_OFFSET(ldb->ldb_lfb_offset);

		if ((lfb->lfb_l_nodename || cur_db_lfb->lfb_l_nodename) &&
		    (lfb->lfb_l_nodename != cur_db_lfb->lfb_l_nodename ||
		    MEcmp(lfb->lfb_nodename, cur_db_lfb->lfb_nodename,
				    lfb->lfb_l_nodename)))
		{
		    ldb_offset = ldb->ldb_next;
#ifdef xDEBUG
		    TRdisplay("%@ RCP-P1: Recovering %~t, ignore ldb for %~t %x\n",
			lfb->lfb_l_nodename, lfb->lfb_nodename,
			cur_db_lfb->lfb_l_nodename, cur_db_lfb->lfb_nodename,
			flag & LG_CSP_RECOVER);
#endif

		    continue;
		}
	    }
	    
	    if (status = LG_mutex(SEM_EXCL, &ldb->ldb_mutex))
		return(status);

	    /*
	    ** Check again after semaphore wait.
	    ** If LDB is no longer a match (it was in the 
	    ** process of being eradicated while we waited for
	    ** the ldb_mutex), and start the search again from
	    ** the top of the queue.
	    */
	    if (ldb->ldb_type != LDB_TYPE ||
	        ldb->ldb_l_buffer != l_buffer ||
		MEcmp(ldb->ldb_buffer, buffer, l_buffer))
	    {
		(VOID)LG_unmutex(&ldb->ldb_mutex);
		ldb_offset = lgd->lgd_ldb_next;
		continue;
	    }
	    break;
	}

	if (ldb_offset != end_offset)
	{
	    /*
	    **  LDB exists. If the database is already known to be inconsistent,
	    **  then no new adds of the database are permitted, unless the caller
	    **  acknowledges that it "knows" that the database is inconsistent by
	    **  passing the "pretend consistent" flag (used by verifydb).
	    */

	    if (ldb->ldb_status & LDB_INVALID)
	    {
		if ( (flag & LG_PRETEND_CONSISTENT) == 0 )
		{
		    (VOID)LG_unmutex(&ldb->ldb_mutex);
		    (VOID)LG_unmutex(&lgd->lgd_ldb_q_mutex);
		    LG_deallocate_cb(LPD_TYPE, (PTR)lpd);
		    (VOID)LG_unmutex(&lpb->lpb_mutex);
		    return (LG_DB_INCONSISTENT);	
		}
	    }

	    /*
	    ** If the database reference count is zero, then the database
	    ** must be opened by the RCP before the server can use it.
	    ** Mark the status opendb_pending - this will suspend any thread
	    ** making an LGwrite call on this database (note that the first
	    ** thing a server does after opening a database is to write an
	    ** OPENDB log record) until the RCP has finished opening it.
	    **
	    ** If the database reference count is not zero, but the database
	    ** is undergoing REDO recovery, then we cannot allow new servers
	    ** to access the database until recovery is complete.  Set the
	    ** database status to opendb_pending and opn_wait.
	    **
	    ** NOTE that if we begin to support READ-ONLY databases and servers
	    ** are able to open databases without writing an OPENDB record, then
	    ** we must come up with a new method of suspending database openers
	    ** until recovery is complete.
	    */
		/* Bug 90140. If the database is currently pending a close then
		** mark the open as in CLOSE_WAIT. This will ensure that the close
		** is processed before this open and prevent locking errors on the journals
		*/
	    if (ldb->ldb_lpd_count == 0)
	    {
		if ((ldb->ldb_status & LDB_PURGE) == 0)
		{
		    if ((ldb->ldb_status & LDB_OPENDB_PEND) == 0)
		    {
			ldb->ldb_status |= LDB_OPENDB_PEND;
			if (ldb->ldb_status & LDB_CLOSEDB_PEND)
				ldb->ldb_status |= LDB_CLOSE_WAIT;
			if (flag & LG_PRETEND_CONSISTENT)
			    ldb->ldb_status |= LDB_PRETEND_CONSISTENT;
	    		if (flag & LG_READONLY)
			    ldb->ldb_status |= LDB_READONLY;
	    		if (flag & LG_RODB)
			    ldb->ldb_status |= LDB_RODB;
			SignalEvent = LGD_OPENDB;
		    }
		}
		else
		    ldb->ldb_status &= ~(LDB_PURGE);
	    }
	    else if (ldb->ldb_status & LDB_RECOVER)
	    {
		/*
		** The database is open, but is being recovered.
		** Set the opendb_pending and opn_wait flags - this will 
		** prevent any new transactions from proceeding on this 
		** database until recovery is complete.  Marking this
		** database as OPENDB_PEND will not cause the database to
		** be processed in count_opens because of the opn_wait flag.
		*/
		ldb->ldb_status |= (LDB_OPENDB_PEND | LDB_OPN_WAIT);
	    }
	    /*  Count new reference to LDB. */

	    ldb->ldb_lpd_count++;
	}
	else
	{
	    /*
	    ** This database is NOT known.
	    **
	    ** If the caller has passed special flags indicating that they
	    ** require that the newly-added database must have a particular DB_ID
	    ** assigned to it, then ensure that the new LDB gets the right ID.
	    **
	    ** Otherwise, just pick the next LDB off the free list.

	    */
	    /*
	    **  Allocate a new LDB 
	    **  returning with the ldb_mutex held
	    **  and lgd_ldb_inuse incremented.
	    */
	    if ((ldb = (LDB *)LG_allocate_cb(LDB_TYPE)) == 0)
	    {
		LG_deallocate_cb(LPD_TYPE, (PTR)lpd);
		(VOID)LG_unmutex(&lgd->lgd_ldb_q_mutex);
		(VOID)LG_unmutex(&lpb->lpb_mutex);
		return (LG_EXCEED_LIMIT);
	    }
	    initialize_ldb = TRUE;
	}
    }

#ifdef xDEBUG
    /*
    ** For a while, we were having problems with corruption of the LFB/LDB
    ** large block queues, and this debugging code helped to track those
    ** problems down.
    */
    if (ldb->ldb_id.id_id == 0)
    {
	TRdisplay("%@ LGadd: args were:(%d,%d).%x.%p.%x.%p\n",
		lg_id.id_lgid.id_id, lg_id.id_lgid.id_instance,
		flag, buffer, l_buffer, db_id);
	LG_debug_wacky_ldb_found(lgd, ldb);
	return (LG_BADPARAM);
    }
#endif

    /*
    ** NOTE: Be careful about adding error returns after this point,
    ** because any such error return must first free up BOTH the LPD AND
    ** the LDB, if an LDB was actually allocated.
    */

    /*
    **  Initialize the LDB, if one was allocated
    **  or if first use of NOTDB LDB.
    */
    if (initialize_ldb)
    {
	MEcopy((PTR)buffer, l_buffer, (PTR)ldb->ldb_buffer);
	ldb->ldb_l_buffer = l_buffer;
	ldb->ldb_type = LDB_TYPE;
	ldb->ldb_status = LDB_ACTIVE;
	ldb->ldb_stat.read = 0;
	ldb->ldb_stat.write = 0;
	ldb->ldb_stat.begin = 0;
	ldb->ldb_stat.wait = 0;
	ldb->ldb_stat.force = 0;
	ldb->ldb_stat.end = 0;
	ldb->ldb_lxbo_count = 0;
	ldb->ldb_lxb_count = 0;
	ldb->ldb_lpd_count = 1;
	ldb->ldb_lfb_offset = lpb->lpb_lfb_offset;
	ldb->ldb_j_first_la.la_sequence = 0;
	ldb->ldb_j_first_la.la_block    = 0;
	ldb->ldb_j_first_la.la_offset   = 0;
	ldb->ldb_j_last_la.la_sequence  = 0;
	ldb->ldb_j_last_la.la_block     = 0;
	ldb->ldb_j_last_la.la_offset    = 0;
	ldb->ldb_d_first_la.la_sequence = 0;
	ldb->ldb_d_first_la.la_block    = 0;
	ldb->ldb_d_first_la.la_offset   = 0;
	ldb->ldb_d_last_la.la_sequence  = 0;
	ldb->ldb_d_last_la.la_block     = 0;
	ldb->ldb_d_last_la.la_offset    = 0;
	ldb->ldb_sbackup.la_sequence    = 0;
	ldb->ldb_sbackup.la_block       = 0;
	ldb->ldb_sbackup.la_offset      = 0;
	ldb->ldb_sback_lsn.lsn_high     = 0;
	ldb->ldb_sback_lsn.lsn_low      = 0;
	ldb->ldb_eback_lsn.lsn_high     = 0;
	ldb->ldb_eback_lsn.lsn_low      = 0;

	/*
	** Assume no simulated MVCC journal writes.
	**
	** This may be changed by LGalter(LG_A_JFIB)
	*/
	MEfill(sizeof(ldb->ldb_jfib), 0, &ldb->ldb_jfib);

	/*
	** Set last_commit, last_lsn, and first_la to
	** the current values from the header.
	*/
	ldb->ldb_last_commit = lfb->lfb_header.lgh_last_lsn;
	ldb->ldb_last_lsn = lfb->lfb_header.lgh_last_lsn;
	ldb->ldb_first_la = lfb->lfb_header.lgh_end;

	/*
	** Initialize active transaction queue to empty.
	*/
	ldb->ldb_active_lxbq.lxbq_next = ldb->ldb_active_lxbq.lxbq_prev
		= LGK_OFFSET_FROM_PTR(&ldb->ldb_active_lxbq.lxbq_next);

	ldb->ldb_lgid_low = 0;
	ldb->ldb_lgid_high = 0;

	/*
	** Extract the external Database Id from the info buffer to
	** put in an accessable place of the ldb.
	*/
	I4ASSIGN_MACRO(ldb->ldb_buffer[DB_DB_MAXNAME+DB_OWN_MAXNAME], ldb->ldb_database_id);

	if (flag & LG_NOTDB)
	{
	    ldb->ldb_status |= LDB_NOTDB;
	}
	else
	{
	    if (flag & LG_JOURNAL)
		ldb->ldb_status |= LDB_JOURNAL;
	    if (flag & LG_PRETEND_CONSISTENT)
		ldb->ldb_status |= LDB_PRETEND_CONSISTENT;
	    if (flag & LG_READONLY)
		ldb->ldb_status |= LDB_READONLY;
	    if (flag & LG_RODB)
	        ldb->ldb_status |= LDB_RODB;
	}

	if ((ldb->ldb_status & LDB_NOTDB) == 0)
	{
	    if ((lfb->lfb_status & LFB_USE_DIIO) == 0)
	    {
		/*
		** signal to the RCP that local use of this database is
		** beginning. The database remains in pending-open state
		** until the RCP acknowledges the open.
		*/
		ldb->ldb_status |= LDB_OPENDB_PEND;
		SignalEvent = LGD_OPENDB;
	    }
	}
    }

    /*
    ** The LPD (Logging system Process-Database connection block) contains
    ** pointers to its associated database and process blocks, and contains
    ** a list of all transactions which this process has begun within this
    ** database:
    */

    lpd->lpd_ldb = LGK_OFFSET_FROM_PTR(ldb);
    lpd->lpd_lpb = LGK_OFFSET_FROM_PTR(lpb);

    lpd->lpd_lxbq.lxbq_next = lpd->lpd_lxbq.lxbq_prev =
	    LGK_OFFSET_FROM_PTR(&lpd->lpd_lxbq.lxbq_next);

    lpd->lpd_lxb_count = 0;

    /*	Change various counters. */

    lpb->lpb_lpd_count++;
    lgd->lgd_stat.add++;

    /*	Queue LPD to the LPB. */

    lpd->lpd_next = lpb->lpb_lpd_next;
    lpd->lpd_prev = LGK_OFFSET_FROM_PTR(&lpb->lpb_lpd_next);

    next_lpd = (LPD *)LGK_PTR_FROM_OFFSET(lpb->lpb_lpd_next);
    next_lpd->lpd_prev    = 
	    lpb->lpb_lpd_next = LGK_OFFSET_FROM_PTR(lpd);

    /*
    ** If the adding process uses fast commit, then mark the database
    ** as open with FC protocols.  Should a crash occur, all updates to
    ** this db since the last Consistency Point will need to be redone.
    */
    if ((flag & LG_FCT) && (lpb->lpb_status & LPB_FCT))
	ldb->ldb_status |= LDB_FAST_COMMIT;

    /* If opener wants MVCC, ensure that it is on, found or not */
    if ( flag & LG_MVCC )
	ldb->ldb_status |= LDB_MVCC;

    /*	Return identifier. */

    *db_id = lpd->lpd_id;

    if ( initialize_ldb )
    {
	/* Lastly, insert LDB on the active queue. */

	ldb->ldb_next = lgd->lgd_ldb_next;
	ldb->ldb_prev = end_offset;
	next_ldb = (LDB *)LGK_PTR_FROM_OFFSET(lgd->lgd_ldb_next);
	next_ldb->ldb_prev    = 
	    lgd->lgd_ldb_next = LGK_OFFSET_FROM_PTR(ldb);
    }

    /*
    ** Unwind the mutexes
    */
    (VOID)LG_unmutex(&ldb->ldb_mutex); 
    (VOID)LG_unmutex(&lgd->lgd_ldb_q_mutex); 
    (VOID)LG_unmutex(&lpb->lpb_mutex); 

    /* If any events to signal, do so */
    if ( SignalEvent )
	LG_signal_event(SignalEvent, 0, FALSE);

    return (OK);
}
Exemplo n.º 17
0
/*
** {
** Name: adu_redeem	- Redeem an ADF_COUPON
**
** Description:
**      This routine redeems an ADF_COUPON, i.e. it materializes the object
**	represented by the coupon.  Since objects represented by coupons
**	may not fit in memory, this routine must deal with returning partial
**	results.  In such cases, it will store its partial status in its fourth
**	argument, which is to be returned for each call. 
**
** Inputs:
**      adf_scb                  Standard ADF session control block
**      result_dv                Ptr to DB_DATA_VALUE into which to
**                               place the result.
**      coupon_dv                Ptr to DB_DATA_VALUE which contains
**                               the input to redeem.
**      workspace_dv             Ptr to DB_DATA_VALUE which points to
**                               the workspace.  This workspace is
**                               expected to be maintained across
**                               calls to this routine for any given
**                               coupon.  (I.e. it can be "new" only
**                               when "continuation" (next param) is
**                               zero.
**      continuation             Is this a continuation of a previous
**                               call.
**
** Outputs:
**      adf_scb->adf_errcb       Filled as appropriate.
**      result_dv->db_length     Filled with the length of the result
**                               area actually used.
**      *workspace->db_data      Filled with info to be used by
**                               subsequent invocations of this routine.
**	Returns:
**          E_DB_ERROR           In case of error
**          E_DB_INFO/E_AD0002_INCOMPLETE
**                               When more calls are necessary
**          E_DB_OK              When complete.
**
**	Exceptions:
**	    None.
**
** Side Effects:
**	    None.
**
** History:
**      07-dec-1989 (fred)
**          Prototyped.
**      06-oct-1992 (fred)
**          Altered to work with timezone integration.  As a temporary measure,
**	    this routine was using the ADF_CB.adf_4rsvd field to store
**	    some context across calls.  In that this field disappeared, a new,
**	    more appropriately named field was added (adf_lo_context).  This
**	    new ADF_CB field is now used in this file.
**	30-Oct-1992 (fred)
**	    Fixed to correctly handle being called with a length too short
**	    for the original header.
**	20-Nov-1992 (fred)
**	    Rewritten for better clarity & better delineation of
**	    function in support of OME large objects.
**      18-Oct-1993 (fred)
**          Moved check for FEXI function so that STAR, which has
**          none, can send null blobs sometimes.  It helps get a tiny
**          bit of support in to STAR.
**      13-Apr-1994 (fred)
**          Altered to hand status from FEXI call straight back.  By
**          not losing the actual status, interrupts may avoid logging
**          too much stuff.
**      14-Sep-1995 (shust01/thaju02)
**          fixed problem of endless loop when we are finished, but we
**	    come in just to get the NULL byte.  work->adw_shared.shd_o_used 
**	    had old size (which was max value), so we never end.  Set
**	    work->adw_shared.shd_o_used = 0.
**	24-Oct-2001 (thaju02)
**	    If adc_lvch_xform() was unable to fit the 2-byte segment
**	    length in the result buffer, decrement result length
**	    with unused byte and flush segment. (B104122)
[@history_template@]...
*/
DB_STATUS
adu_redeem(
ADF_CB            *adf_scb,
DB_DATA_VALUE	   *result_dv,
DB_DATA_VALUE      *coupon_dv,
DB_DATA_VALUE      *workspace_dv,
i4            continuation)
{
    ADP_LO_WKSP 	*work = (ADP_LO_WKSP *) workspace_dv->db_data;
    DB_DT_ID		dtid;
    ADP_PERIPHERAL	*p = (ADP_PERIPHERAL *) result_dv->db_data;
    DB_STATUS		status;
    i4			done = FALSE;
    i4                  flush;
    i4			for_gca = 1;
    i4                  loop_around;

    if (result_dv->db_datatype != coupon_dv->db_datatype)
	return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
	
    dtid = ADI_DT_MAP_MACRO(abs(result_dv->db_datatype));
    if (    dtid <= 0
	 || dtid  > ADI_MXDTS
	 || Adf_globs->Adi_dtptrs[dtid] == NULL
	 || !Adf_globs->Adi_dtptrs[dtid]->adi_under_dt
       )
	return(adu_error(adf_scb, E_AD2004_BAD_DTID, 0));

    if ((!continuation) || (work->adw_fip.fip_state == ADW_F_STARTING))
    {
	if (!continuation)
	    work->adw_fip.fip_state = ADW_F_INITIAL;
	status = adu_rdm1_setup(adf_scb, result_dv, coupon_dv, work, for_gca);
	if (status || work->adw_fip.fip_done)
	    return(status);
    }
    else if (work->adw_fip.fip_state == ADW_F_DONE_NEED_NULL)
    {
	/*
	**  This is an indication that we finished, but didn't
	**  send the NULL byte, and must do so now...
	*/
	
	work->adw_shared.shd_o_used = 0;
	status = adu_rdm2_finish(adf_scb, result_dv, coupon_dv, work, for_gca);
	return(status);
    }
    else
    {
	if (Adf_globs->Adi_fexi[ADI_01PERIPH_FEXI].adi_fcn_fexi == NULL)
	    return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
	work->adw_shared.shd_o_used = 0;
	work->adw_shared.shd_o_length = result_dv->db_length;
	work->adw_shared.shd_o_area = (char *) result_dv->db_data;
	work->adw_fip.fip_pop_cb.pop_continuation = 0;

	work->adw_fip.fip_pop_cb.pop_coupon = coupon_dv;
    }

    for (flush = 0;
	    !done
		&& (!flush)
		&& (work->adw_shared.shd_l1_check <
		    	    	    	work->adw_fip.fip_l1_value);
	/* No update action */)
    
    {
	switch (work->adw_shared.shd_exp_action)
	{
	case ADW_FLUSH_SEGMENT:
	case ADW_START:
	    if (for_gca)
	    {
		/*
		** Since we got a segment back, insert the `here
	        ** comes another segment indicator'.
		*/

		i4		one = 1;

		if ( (work->adw_shared.shd_o_length -
		                         work->adw_shared.shd_o_used)
		       < sizeof(one))
		{
		    /* Then the next segment marker won't fit.  Dump */
		    /* the current segment and move on... */

		    /* fix_me -- better error... */
		
		    return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
		}

		I4ASSIGN_MACRO(one,
		     work->adw_shared.shd_o_area[work->adw_shared.shd_o_used]);
		work->adw_shared.shd_o_used += sizeof(one);
	    }
	    /* Fall thru -- if out of input data, get some */

	case ADW_FLSH_SEG_NOFIT_LIND:
	case ADW_NEXT_SEGMENT:
	    
	    if (   (work->adw_shared.shd_exp_action == ADW_NEXT_SEGMENT)
		&& (work->adw_shared.shd_inp_tag == ADP_P_COUPON))
	    {
		/*
		**  For [DBMS style] coupons, each segment is in a row
		**  unto itself, regardless of the length of the row.
		**  Since this routine is datatype independent, it
		**  cannot tell when a segment is up, and thus must
		**  rely on the called routine.  Thus, if the callee
		**  asks for a new segment when processing a DBMS
		**  coupon, this routine will assume that the current
		**  set of data has been all used up...
		*/

		work->adw_shared.shd_i_used =
		    work->adw_shared.shd_i_length;
	    }

	    /* Fall thru... */

	case ADW_GET_DATA:
	    if (work->adw_shared.shd_i_used == work->adw_shared.shd_i_length)
	    {
		/*
		** If no unmoved segment data, then get some more.
		*/
		
		if (work->adw_fip.fip_done)
		{
		    done = TRUE;
		    status = E_DB_OK;
		}
		else
		{
		    status =
			(*Adf_globs->Adi_fexi[ADI_01PERIPH_FEXI].adi_fcn_fexi)
			    (ADP_GET, &work->adw_fip.fip_pop_cb);
		    if (status)
		    {
			if (work->adw_fip.fip_pop_cb.pop_error.err_code
			    == E_AD7001_ADP_NONEXT)
			{
			    work->adw_fip.fip_done = TRUE;
			    
			    if (status == E_DB_WARN)
				status = E_DB_OK;
			    else
				break;
			}
			else
			{
			    return(adu_error(adf_scb,
				   work->adw_fip.fip_pop_cb.pop_error.err_code,
					     0));
			}
		    }
		    
		    work->adw_shared.shd_i_used = 0;
		    work->adw_shared.shd_i_length =
			work->adw_fip.fip_seg_dv.db_length;
		    work->adw_shared.shd_i_area =
			work->adw_fip.fip_seg_dv.db_data;

		}
	    }
	    break;

	case ADW_CONTINUE:  /* This shouldn't happen */
	default:            /* Nor should anything else */
	    return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
	    break;
	}
	if (done)
	    break;

	status = adc_xform(adf_scb, (PTR)work);
	if (DB_FAILURE_MACRO(status))
	{
	    return(adu_error(adf_scb, E_AD7003_ADP_BAD_RECON, 0));
	}
	if (work->adw_shared.shd_exp_action == ADW_FLUSH_SEGMENT)
	{
	    flush = 1;
	}

	/* B104122 */
	if (work->adw_shared.shd_exp_action == ADW_FLSH_SEG_NOFIT_LIND)
	{
	    result_dv->db_length = work->adw_shared.shd_o_used;
	    flush = 1;
	}

	/* B?????? */
	if (work->adw_shared.shd_exp_action == ADW_FLUSH_INCOMPLETE_SEGMENT)
	{
	    result_dv->db_length = work->adw_shared.shd_o_used;
	    work->adw_shared.shd_exp_action = ADW_FLUSH_SEGMENT;
	    flush = 1;
	}

	work->adw_fip.fip_pop_cb.pop_continuation = 0;
    }

    if (work->adw_shared.shd_l1_check == work->adw_fip.fip_l1_value)
    {
	done = TRUE;
    }

    if (work->adw_fip.fip_test_mode)
    {
	work->adw_fip.fip_test_sent += work->adw_shared.shd_o_used;
	
	if ((work->adw_fip.fip_test_length
	         - work->adw_fip.fip_test_sent
	         - work->adw_fip.fip_null_bytes
	         - (for_gca * sizeof(i4)))
	     <= 0)
	{
	    /*
	    **	Then, for test purposes, we've sent all that we can.
	    **	Emulate completion.
	    */

	    work->adw_fip.fip_done = done = TRUE;
	    work->adw_shared.shd_i_used = work->adw_shared.shd_i_length;
	    work->adw_shared.shd_l1_check = work->adw_fip.fip_l1_value;
	    work->adw_shared.shd_o_used = work->adw_fip.fip_test_length
		                             - work->adw_fip.fip_test_sent
		                             - sizeof(i4)    /* end marker */
			                     - work->adw_fip.fip_null_bytes;
	                                        /* null indicator */
	    work->adw_fip.fip_test_sent =
		work->adw_fip.fip_test_length - sizeof(i4)
		                              - work->adw_fip.fip_null_bytes;
	}

    }
    
    if (done && ((work->adw_shared.shd_exp_action == ADW_NEXT_SEGMENT)
		 || (work->adw_shared.shd_exp_action == ADW_FLUSH_SEGMENT)))
    {
	/*
	** If we think we are done and have used all the input,...
	*/

	status = adu_rdm2_finish(adf_scb, result_dv, coupon_dv, work, for_gca);
    }
    else
    {
	/*
	** Otherwise, if we are surpassing the amount of data which
	** be available...
	*/

	if (work->adw_shared.shd_l1_check > work->adw_fip.fip_l1_value)
	{
	    /*
	    ** FIX_ME -- better error message...
	    ** Then we would be sending an inconsistent blob.
	    ** That would be bad.
	    */

	    return(adu_error(adf_scb, E_AD7004_ADP_BAD_BLOB,0));
	}
	adf_scb->adf_errcb.ad_errcode  = E_AD0002_INCOMPLETE;
	status = E_DB_INFO;
    }
    return(status);
}
Exemplo n.º 18
0
/*{
** Name: adu_rdm1_setup	- Setup for Redeem an ADF_COUPON
**
** Description:
**      This routine performs the initialization for the redeeming of
**      a coupon.  This amount primarily to initializing the
**      ADP_LO_WKSP function instance private and shared (adw_fip &
**      adw_shared, respectively).  This routine also moves the
**      appropriate peripheral header into the output area.
**
**      Since this routine moves the peripheral header to the output
**      area, in the case where the original call to this routine has
**      insufficient space for the output header, this routine may be
**      called more than once.  We note this since it is "unusual" for
**      the initialization routine to be called more than one time for
**      an object.  In the case where the original space is of
**      insufficent size, then this routine will return an indication
**      that the output area is full, and will move nothing into it.
**      Thus, this routine considers it a call-protocol error to be
**      called a second time with insufficient space.
**
** Inputs:
**      adf_scb                     The session's control block (ptr).
**      result_dv                   Pointer to DB_DATA_VALUE for
**                                      result.
**      coupon_dv                   Pointer to DB_DATA_VALUE
**                                      describing the input coupon to
**                                      be redeemed.
**      workspace_dv                Pointer to DB_DATA_VALUE
**                                      describing redeem's workspace.
**      continuation                Continuation indicator.  0
**                                      indicates the first call, else
**                                      not the first call.
**
** Outputs:
**      adf_scb->adf_error          Filled as appropriate.
**      *result_dv->db_data         Setup with beginning of peripheral
**                                      data type.
**      *workspace_dv->db_data      Initialized for ongoing redeem work.
**	Returns:
**	    DB_STATUS
**	Exceptions:
**	    None.
**
** Side Effects:
**	    None.
**
** History:
**      02-dec-1992 (fred)
**          Coded.  Created from adu_redeem prototype in support of
**          OME large objects.
**       8-Apr-1993 (fred)
**          Fixed bug in zero length large object handling.  For large
**          objects of zero length which are not nullable, the length
**          should not include the null-value-byte.
**      12-Oct-1993 (fred)
**          Removed call to ADP_INFORMATION -- subsumed by
**          adi_per_under(). 
**      10-sep-1998 (schte01)
**          Modified I4ASSIGN for axp_osf to pass the value, not the address
**          of the value, to be assigned. This worked under the -oldc
**          compiler option and got compile errors under -newc.
**	28-jul-1999 (thaju02)
**	    If the coupon stipulates that the data is not null, then
**	    the minimum result buffer length must be large enough to
**	    hold one byte of data along with all necessary info
**	    (ADP_HDR_SIZE + nextsegmarker(i4) + 2byteseglenindicator
**	    + 1byteofdata). Given a buffer with only 18 bytes of space
**	    available, 12 bytes are filled with peripheral header info
**	    in adu_rdm1_setup and 4 bytes are filled with the next
**	    segment marker in adu_redeem. In adc_lvch_xform, the 2 
**	    byte segment length indicator is initially set to zero 
**	    in the result buffer. If there is no space left in the 
**	    result buffer for segment data, we flush the buffer. In 
**	    the front end, upon receiving this result buffer, the 
**	    next segment marker indicates that there is data following, 
**	    yet the length is zero; terminal monitor infinitely loops. 
**	    (b98104)
**      12-aug-99 (stial01)
**          adu_rdm1_setup() 'blob_work' arg to adi_per_under should be  
**          NULL before redeem.
**      24-may-2000 (stial01)
**          adu_rdm1_setup() clear null indicator if not null (B101656)
**
[@history_template@]...
*/
DB_STATUS static
adu_rdm1_setup(ADF_CB             *adf_scb,
	       DB_DATA_VALUE      *result_dv,
	       DB_DATA_VALUE      *coupon_dv,
	       ADP_LO_WKSP        *work,
	       i4                 for_gca)
{
    DB_STATUS	    	status;  
    ADP_PERIPHERAL      *p = (ADP_PERIPHERAL *) result_dv->db_data;
    DB_DT_ID            dtid =
	ADI_DT_MAP_MACRO(abs(result_dv->db_datatype));
    i4			min_size;
    bool		isnull = 0;

    if (coupon_dv->db_datatype < 0)
	work->adw_fip.fip_null_bytes = 1;
    else
	work->adw_fip.fip_null_bytes = 0;

    if (ult_check_macro(&Adf_globs->Adf_trvect, ADF_011_RDM_TO_V_STYLE,
			&dummy1, &dummy2))
    {
	work->adw_fip.fip_test_mode = 1;
	work->adw_fip.fip_test_length = ADP_TST_VLENGTH +
	                                   work->adw_fip.fip_null_bytes;
	work->adw_fip.fip_test_sent = 0;
    }
    else
    {
	work->adw_fip.fip_test_mode = 0;
    }

    work->adw_shared.shd_exp_action = ADW_START;
    work->adw_fip.fip_done = FALSE;

    /*
    ** Fool the main routine into getting us an input segment.  Make
    ** look like the input segement is all used up.
    */
    
    work->adw_shared.shd_type = coupon_dv->db_datatype;
    work->adw_shared.shd_i_area = (char *) 0;
    work->adw_shared.shd_i_used = work->adw_shared.shd_i_length = 0;

    work->adw_shared.shd_o_used = ADP_HDR_SIZE;
    work->adw_shared.shd_o_length = result_dv->db_length;
    work->adw_shared.shd_o_area = (char *) result_dv->db_data;

    if (work->adw_shared.shd_o_length > MAXI2)
    {
	TRdisplay("adu_rdm1_setup shd_o_length %d MAX %d\n",
		work->adw_shared.shd_o_length, MAXI2);
	return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
    }
    work->adw_shared.shd_l0_check = work->adw_shared.shd_l1_check = 0;

    work->adw_fip.fip_pop_cb.pop_continuation = ADP_C_BEGIN_MASK;
    work->adw_fip.fip_pop_cb.pop_user_arg = (PTR) 0;
    
    work->adw_fip.fip_pop_cb.pop_type = (ADP_POP_TYPE);
    work->adw_fip.fip_pop_cb.pop_length = sizeof(ADP_POP_CB);
    work->adw_fip.fip_pop_cb.pop_ascii_id = ADP_POP_ASCII_ID;
    work->adw_fip.fip_pop_cb.pop_temporary = ADP_POP_PERMANENT;
    work->adw_fip.fip_pop_cb.pop_coupon = coupon_dv;
    work->adw_fip.fip_pop_cb.pop_segment = &work->adw_fip.fip_seg_dv;
    work->adw_fip.fip_pop_cb.pop_underdv = &work->adw_fip.fip_under_dv;
    status = adi_per_under(adf_scb,
			   result_dv->db_datatype,
			   &work->adw_fip.fip_under_dv);

    if (status)
    {
	return(adu_error(adf_scb, E_AD7000_ADP_BAD_INFO, 0));
    }

    STRUCT_ASSIGN_MACRO(work->adw_fip.fip_under_dv,
			work->adw_fip.fip_seg_dv);
    work->adw_fip.fip_seg_dv.db_data = (char *) ((char *) work +
						 sizeof(ADP_LO_WKSP));

    if (ADI_ISNULL_MACRO(coupon_dv) ||
       ((((ADP_PERIPHERAL *)coupon_dv->db_data)->per_length0 == 0)
       && (((ADP_PERIPHERAL *) coupon_dv->db_data)->per_length1 == 0))) 
	isnull = 1;

    if (isnull)
	/* hdr + segment indicator + sizeof(null byte) */
        min_size = ADP_HDR_SIZE + sizeof(i4) + work->adw_fip.fip_null_bytes; 
    else	
	/* hdr + segment indicator + segment length + segment single byte */
        min_size = ADP_HDR_SIZE + sizeof(i4) + sizeof(i2) + sizeof(char); 

    if (result_dv->db_length >= min_size)
    {
	if (for_gca)
	    work->adw_shared.shd_out_tag = ADP_P_GCA;
	else
	    work->adw_shared.shd_out_tag = ADP_P_DATA;
	
	I4ASSIGN_MACRO(work->adw_shared.shd_out_tag, p->per_tag);
	
	work->adw_shared.shd_out_segmented =
	    (work->adw_shared.shd_out_tag != ADP_P_DATA);

	I4ASSIGN_MACRO( ((ADP_PERIPHERAL *)
			 coupon_dv->db_data)->per_tag,
		       work->adw_shared.shd_inp_tag);
	work->adw_shared.shd_inp_segmented =
	    (work->adw_shared.shd_inp_tag != ADP_P_DATA);

	I4ASSIGN_MACRO( ((ADP_PERIPHERAL *)
			 coupon_dv->db_data)->per_length0,
		       p->per_length0);
	I4ASSIGN_MACRO(p->per_length0, work->adw_fip.fip_l0_value);
	I4ASSIGN_MACRO(((ADP_PERIPHERAL *)
			coupon_dv->db_data)->per_length1,
		       p->per_length1);
	I4ASSIGN_MACRO(p->per_length1, work->adw_fip.fip_l1_value);
	work->adw_fip.fip_state = ADW_F_RUNNING;
    }
    else if (work->adw_fip.fip_state != ADW_F_STARTING)
    {
	work->adw_fip.fip_state = ADW_F_STARTING;
	result_dv->db_length = 0;
	adf_scb->adf_errcb.ad_errcode = E_AD0002_INCOMPLETE;
	return(E_DB_INFO);
    }
    else
    {
	return(adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0));
    }

    if (isnull)
    {
	if (work->adw_fip.fip_test_mode)
	{
	    ((DB_TEXT_STRING *) p)->db_t_count = (i2) 0;

	    if (result_dv->db_length >=
		    (work->adw_fip.fip_test_length -
		              work->adw_fip.fip_test_sent))

	    {
		
		result_dv->db_length = work->adw_fip.fip_test_length -
		     work->adw_fip.fip_test_sent;
		work->adw_fip.fip_test_sent = work->adw_fip.fip_test_length;
	    }
	    else
	    {
		work->adw_fip.fip_state = ADW_F_DONE_NEED_NULL;
		work->adw_fip.fip_test_sent += result_dv->db_length;
		adf_scb->adf_errcb.ad_errcode = E_AD0002_INCOMPLETE;
		return(E_DB_INFO);
	    }
	}
	else
	{
	    i4	    zero = 0;

	    /*
	    **  Insert GCA mark that says there is no segment.
	    */
	
#if defined(axp_osf) || defined(ris_u64) || defined(LP64) || \
    defined(axp_lnx)
	    /*
	    **	We want to init the GCA field after the header, but
	    **	on axp_osf this is not the same as the start of the
	    **	coupon, because 8-byte alignment causes a slack 4-byte
	    **	integer to be between the header and the coupon.  See
	    **	adu_redeem above for a different way this field is set
	    **	to 1 when we have real data (not null).  The addressing
	    **	of this field should really be standardized in such a
	    **	way that contiguous layout of 4-byte aligned fields is
	    **	not assumed.
	    */
            I4ASSIGN_MACRO(zero,*((char *)p + ADP_HDR_SIZE)); 
#endif
	    I4ASSIGN_MACRO(zero, p->per_value);
	    
	    result_dv->db_length = ADP_NULL_PERIPH_SIZE;
	    if (work->adw_shared.shd_type > 0)
		result_dv->db_length -= 1;
        }
	if (ADI_ISNULL_MACRO(coupon_dv))
	    ADF_SETNULL_MACRO(result_dv);
	else
	    ADF_CLRNULL_MACRO(result_dv);
	adf_scb->adf_errcb.ad_errcode = E_DB_OK;
	work->adw_fip.fip_done = TRUE;
	return(E_DB_OK);
    }

    if (work->adw_fip.fip_test_mode)
    {
	i4	    	segment_count;
	i4	    	length1;
	i2		count;
	
	I4ASSIGN_MACRO(p->per_length1, length1);
	
	I4ASSIGN_MACRO(p->per_length0, segment_count);
	
	if (!segment_count)
	    segment_count = ADP_TST_SEG_CNT;
	
	count = min(	ADP_TST_VLENGTH,
		    (i2) (length1
			  + (segment_count *
			     (sizeof(i4) + sizeof(i2)))
			  + sizeof(i4) /* no more segments */
			  + work->adw_shared.shd_o_used)
		    ) - sizeof(i2);
	I2ASSIGN_MACRO(count, ((DB_TEXT_STRING *) p)->db_t_count);
    }
    return(E_DB_OK);
}
Exemplo n.º 19
0
/*
** {
** Name: QEA_RUPDATE		- update the current cursor
**
**  External QEF call:	    status = qef_call(QEQ_REPLACE, &qef_rcb);
**
** Description:
**      The current row in the named cursor (QP) is
**  updated and sent to DMF 
**
** Inputs:
**	action			Update current row of cursor action.
**      qef_rcb
**	assoc_dsh		DSH for QP for cursor to be updated.
**	reset
**	state			DSH_CT_INITIAL if this is an action call
**				DSH_CT_CONTINUE for call back after processing
**				a rule action list.
**
** Outputs:
**      qef_rcb
**	    .qef_remnull	SET if an aggregate computation found a NULL val
**	    .qef_rowcount	number of rows replaced
**	    .qef_targcount	number of attempted replaces 
**	    .error.err_code	one of the following
**				E_QE0000_OK
**				E_QE0017_BAD_CB
**				E_QE0018_BAD_PARAM_IN_CB
**				E_QE0019_NON_INTERNAL_FAIL
**				E_QE0002_INTERNAL_ERROR
**				E_QE0008_CURSOR_NOT_OPENED
**				E_QE0021_NO_ROW
**				E_QE0009_NO_PERMISSION
**				E_QE000A_READ_ONLY
**				E_QE0012_DUPLICATE_KEY
**				E_QE0010_DUPLIATE_ROW
**				E_QE0011_AMBIGUOUS_REPLACE
**				E_QE0013_INTEGRITY_FAILED
**				E_QE0024_TRANSACTION_ABORTED
**				E_QE0034_LOCK_QUOTA_EXCEEDED
**				E_QE0035_LOCK_RESOURCE_BUSY
**				E_QE0036_LOCK_TIMER_EXPIRED
**				E_QE002A_DEADLOCK
**	Returns:
**	    E_DB_{OK,WARN,ERROR,FATAL}
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	11-JUN-86 (daved)
**          written
**	22-may-87 (daved)
**	    catch cursor not positioned errors
**	14-oct-87 (puree)
**	    make sure that qen_error is called in case of E_DB_ERROR from
**	    qeq_validate.
**	02-feb-88 (puree)
**	    added reset flag to qeq_validate and all qea_xxxx call sequence.
**	29-aug-88 (puree)
**	    implement replace cursor by tid if the cursor was position on
**	    a secondary index table and by current position if the cursor
**	    is positioned on the base table.
**	    fix duplicate handling error.
**	12-oct-88 (puree)
**	    If a table validation fails during cursor replace, abort the
**	    cursor.
**	23-feb-89 (paul)
**	    Clean up qef_cb state before returning.
**	17-apr-89 (paul)
**	    Processing cursor updates integrated into qeq_query. Update cursor
**	    logic moved from qeq.c to this file (qearupd.c). This routine is
**	    a simplified version of what was previously called qeq_replace.
**	25-sep-89 (paul)
**	    Added support for using TIDs as parameters to procedures invoked
**	    from rules.
**	25-jan-90 (nancy) -- set status to E_DB_OK when replace cursor
**	    causes dups and duplicate handling is set to SKIP_DUPS.
**	29-jan-90 (nancy) -- fix bug 8388 (8575), use assoc dsh for replace
**	    by tid.
**	29-jun-90 (davebf)
**	    Handle rows which were accessed by TID only  (bug 31113)
**       5-Nov-1993 (fred)
**          Remove any remaining large object temporaries.
**       7-Apr-1994 (fred)
**          Commented out large object removal pending better way...
**	7-nov-95 (inkdo01)
**	    Changes to replace QEN_ADF structure instances by pointers in
**	    QEF_AHD structures.
**	29-dec-03 (inkdo01)
**	    DSH is now parameter, "function" replaces "reset".
**	5-feb-04 (inkdo01)
**	    Add support for partitioned tables.
**	12-mar-04 (inkdo01)
**	    Fix to handle bigtids on byte-swapped machines.
**	19-mar-04 (inkdo01)
**	    Fix for bigtids and rules.
**	12-may-04 (inkdo01)
**	    Call qeq_part_open unconditionally - it'll determine whether
**	    partition cbs are already prepared.
**	8-Jul-2004 (schka24)
**	    Still some tid byte-ordering confusion on x86, make tid handling
**	    more portable.
**	26-aug-04 (inkdo01)
**	    Add global base array support for update buffer.
**	24-Feb-05 (hweho01)
**	    The copying of tid needs to be handled differently if   
**          TID_SWAP is defined, so the tid value can be preserved. 
**          Star #13864021.
**	28-Feb-2005 (schka24)
**	    Rework the above fix, it turns out that the underlying problem
**	    was the 4byte-tidp flag not getting set.  Now that it's set
**	    properly, obey it here.  Also, do partition opens against the
**	    cursor query, not the RUP -- it's the one with the valid list..
**	18-Jul-2005 (schka24)
**	    Well, I fixed by-tid updates, but not true in-place updates!
**	    Use new ahd_ruporig machinery to get at the current partition
**	    number for in-place updating.
**	13-Dec-2005 (kschendel)
**	    Can count on qen-ade-cx now.
**	16-Jan-2006 (kschendel)
**	    Access qen-status thru xaddrs.
**	20-june-06 (dougi)
**	    Add support for BEFORE triggers.
**	1-Nov-2006 (kschendel)
**	    Some fixes to BEFORE triggers, make sure things are set up.
**	7-mar-2007 (dougi)
**	    Slight change to address the DMR_CB (broken by BEFORE changes).
**	8-Sep-2008 (kibro01) b120693
**	    Remove unused action parameter from qeq_part_open
**	09-Sep-2009 (thaju02) B122374
**	    If BEFORE trigger has been executed, do not use ahd_upd_colmap.
**	    ahd_upd_colmap may not reflect cols updated by the rule/proc.
**	15-Jan-2010 (jonj)
**	    SIR 121619 MVCC: If E_DM0029_ROW_UPDATE_CONFLICT returned,
**	    invalidate the QP and retry.
**	1-Jul-2010 (kschendel) b124004
**	    Minor changes for RUP from scrollable keyset cursors;  the
**	    fetched row is always in dsh-qef-output.
*/
DB_STATUS
qea_rupdate(
QEF_AHD		    *act,
QEF_RCB		    *qef_rcb,
QEE_DSH		    *dsh,
QEE_DSH		    *assoc_dsh,
i4		    function,
i4		    state )
{
    i4		err;
    DB_STATUS		status	= E_DB_OK;
    QEF_CB		*qef_cb = dsh->dsh_qefcb;
    ADF_CB		*adfcb = dsh->dsh_adf_cb;
    DMR_CB		*dmr_cb, *pdmr_cb;
    QEN_ADF		*qen_adf;
    ADE_EXCB		*ade_excb;
    PTR			*assoc_cbs = assoc_dsh->dsh_cbs;
    PTR			output, save_addr;
    char		*tidinput;  /* location of tid */
    DB_TID8		oldbigtid, newbigtid;
    u_i2		oldpartno = 0;
    u_i2		newpartno = 0;
    i4			odmr_cb_ix;	/* CB number of DMR_CB */
    i4			orig_node;
    
    status = E_DB_OK;
    
    for (;;)
    {
	/* A cursor update affects only a single row. If we are called back  */
	/* after rules processing simply return. */
	if (state == DSH_CT_CONTINUE)
	    break;

	/* Address the DMR_CB used to access the row.  The odmr_cb_ix is in
	** the associated (cursor) QP context.  We'll adjust for partitioning
	** a bit later.
	*/
	odmr_cb_ix = act->qhd_obj.qhd_qep.ahd_odmr_cb;
	dmr_cb = (DMR_CB*) assoc_cbs[odmr_cb_ix];
	if (status == DSH_CT_CONTINUE3)
	{
	    /* Resuming from a BEFORE trigger, reset variables */
	    MEcopy(dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid],
			sizeof(DB_TID8), (PTR) &newbigtid);
	    MEcopy(dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid],
			sizeof(DB_TID8), (PTR) &oldbigtid);
	    oldpartno = oldbigtid.tid.tid_partno;
	    newpartno = newbigtid.tid.tid_partno;
	    output = dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row];
	    if (act->qhd_obj.qhd_qep.ahd_part_def != NULL)
		dmr_cb = (DMR_CB *) assoc_cbs[odmr_cb_ix + oldpartno + 1];
	}
	else
	{
	    /* Normal path */
	    dsh->dsh_qef_remnull = 0;
	    dsh->dsh_qef_rowcount = 0;

	    /* Use fetch row for holding update row if need be */
	    output = assoc_dsh->dsh_row[assoc_dsh->dsh_qp_ptr->qp_fetch_ahd->qhd_obj.qhd_qep.ahd_ruprow];

	    /* make sure we have a positioned record */
	    if (assoc_dsh->dsh_positioned == FALSE)
	    {
		/* no record could be valid in this action's updatable control block.
		** Nor do we know what we will be looking at when we access the
		** update control block index number
		*/
		dsh->dsh_error.err_code = E_QE0021_NO_ROW;
		status = E_DB_ERROR;
		break;
	    }

	    /* check that this query plan has update privilege */
	    if ((assoc_dsh->dsh_qp_ptr->qp_status & QEQP_UPDATE) == 0)
	    {
		/* no permission */
		dsh->dsh_error.err_code = E_QE0009_NO_PERMISSION;
		status = E_DB_ERROR;
		break;
    	    }

	    if (qef_cb->qef_c1_distrib & DB_3_DDB_SESS)	/* distributed? */
	    {
		/* DDB processing */

		status = qeq_c5_replace(qef_rcb, dsh);
		if (status == E_DB_OK)
		    dsh->dsh_qef_rowcount = 1;
		else
		    dsh->dsh_qef_rowcount = 0;
		return(status);
	    }

	    /* LDB processing */

	    /* process the qualification expression */
	    qen_adf     = act->qhd_obj.qhd_qep.ahd_constant;
	    if (qen_adf != NULL)
	    {
		ade_excb = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos];
		if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY)
		    dsh->dsh_row[qen_adf->qen_uoutput] = output;
		else ade_excb->excb_bases[ADE_ZBASE + qen_adf->qen_uoutput] = output;
		status = qen_execute_cx(dsh, ade_excb);
		if (status != E_DB_OK)
		    break;

		/* handle condition where qualification failed. */
		if (ade_excb->excb_value != ADE_TRUE)
		{
		    dsh->dsh_qef_targcount = 1;
		    dsh->dsh_qef_rowcount = 0;
		    break;
		}
	    }

	    /* REPLACE THE TUPLE
	    ** if the cursor is positioned on the base table (ahd_tidoffset is
	    ** -1), replace the tuple at the current position.  Otherwise the
	    ** cursor must have been positioned via a secondary index.  Get
	    ** the tid, re-fetch the original row by tid, and replace the
	    ** base table tuple by the tid.
	    */

	    if (act->qhd_obj.qhd_qep.ahd_tidoffset == -1)
	    {
		/* If partitioned, dig the current partition number out of
		** the node status for the orig (or kjoin/tjoin) node that
		** fetched the row in the first place.  OPC has kindly put
		** the node number of same into ahd_ruporig.
		*/
		if (act->qhd_obj.qhd_qep.ahd_part_def != NULL)
		{
		    orig_node = act->qhd_obj.qhd_qep.ahd_ruporig;
		    if (orig_node == -1)
		    {
			TRdisplay("%@ qea_rupd: missing ahd_ruporig\n");
			dsh->dsh_error.err_code = E_QE0002_INTERNAL_ERROR;
			status = E_DB_ERROR;
			break;
		    }
		    oldpartno = assoc_dsh->dsh_xaddrs[orig_node]->
						qex_status->node_ppart_num;
		    dmr_cb = (DMR_CB *) assoc_cbs[odmr_cb_ix + oldpartno + 1];
		}
		dmr_cb->dmr_flags_mask = DMR_CURRENT_POS;
	    }
	    else
	    {
		/* set the tid */
		tidinput  = 
		    (char *) assoc_dsh->dsh_row[act->qhd_obj.qhd_qep.ahd_tidrow]
				 + act->qhd_obj.qhd_qep.ahd_tidoffset;

		if (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_4BYTE_TIDP)
		{
		    I4ASSIGN_MACRO(*tidinput, oldbigtid.tid_i4.tid );
		    oldbigtid.tid_i4.tpf = 0;
		}
		else
		{
		    I8ASSIGN_MACRO(*tidinput, oldbigtid);
		}
		oldpartno = oldbigtid.tid.tid_partno;
		newpartno = oldpartno;
	
		/* Check for partitioning and set up DMR_CB. */
		if (act->qhd_obj.qhd_qep.ahd_part_def)
		{
		    /* Open against "get" action.  The RUP action dmtix and
		    ** flags are the same as the cursor's, thanks to OPC.
		    */
		    status = qeq_part_open(qef_rcb, assoc_dsh, NULL, 0, 
			odmr_cb_ix,
			act->qhd_obj.qhd_qep.ahd_dmtix, oldpartno);
			
		    if (status != E_DB_OK)
		    {
			dsh->dsh_error.err_code = assoc_dsh->dsh_error.err_code;
			return(status);
		    }
		    pdmr_cb = (DMR_CB *)assoc_cbs[odmr_cb_ix + oldpartno+1];

		    STRUCT_ASSIGN_MACRO(dmr_cb->dmr_data, pdmr_cb->dmr_data);
		    dmr_cb = pdmr_cb;
		}
		dmr_cb->dmr_tid = oldbigtid.tid_i4.tid;
		dmr_cb->dmr_flags_mask = DMR_BY_TID;
	
		/* get the tuple to be updated. */
		save_addr = dmr_cb->dmr_data.data_address;
		dmr_cb->dmr_data.data_address = output;
		status = dmf_call(DMR_GET, dmr_cb);
		dmr_cb->dmr_data.data_address = save_addr;
		if (status != E_DB_OK)
		{
		    dsh->dsh_error.err_code = dmr_cb->error.err_code;
		    return (status);
		}
	    }

	    /* If we have rules, save a copy of the row before updating */
	    if (act->qhd_obj.qhd_qep.ahd_after_act != NULL ||
		act->qhd_obj.qhd_qep.ahd_before_act != NULL)
	    {
		MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize,
		    dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_row]);
		oldbigtid.tid_i4.tpf = 0;
		oldbigtid.tid_i4.tid = dmr_cb->dmr_tid;
		oldbigtid.tid.tid_partno = oldpartno;
	    }

	    /* process the update expression */
	    qen_adf     = act->qhd_obj.qhd_qep.ahd_current;
	    ade_excb    = (ADE_EXCB*) dsh->dsh_cbs[qen_adf->qen_pos];	
	    if (dsh->dsh_qp_ptr->qp_status & QEQP_GLOBAL_BASEARRAY)
		dsh->dsh_row[qen_adf->qen_uoutput] = output;
	    else ade_excb->excb_bases[ADE_ZBASE+qen_adf->qen_uoutput] = output;

	    status = qen_execute_cx(dsh, ade_excb);
	    if (status != E_DB_OK)
		break;

	    /* Check for partitioning and see if we changed target partition. */
	    if (act->qhd_obj.qhd_qep.ahd_part_def && 
		(act->qhd_obj.qhd_qep.ahd_qepflag & AHD_PCOLS_UPDATE))
	    {
		status = adt_whichpart_no(adfcb,
			act->qhd_obj.qhd_qep.ahd_part_def, 
			output, &newpartno);
		if (status != E_DB_OK)
		    return(status);
	    }
	    /* Process BEFORE triggers (if any). */
	    if (act->qhd_obj.qhd_qep.ahd_before_act != NULL)
	    {
		/*
		** Place the TID in a known location so it can be used
		** as a parameter to the procedure fired by the rule.
		*/
		newbigtid.tid_i4.tpf = 0;
		newbigtid.tid_i4.tid = dmr_cb->dmr_tid;
		newbigtid.tid.tid_partno = newpartno;
		MEcopy ((PTR)&newbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid]);   
		MEcopy ((PTR)&oldbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid]);   

		MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize,
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]);
		dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_ptr = act;
		dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_status =
			DSH_CT_CONTINUE3;
		dsh->dsh_depth_act++;
		dsh->dsh_act_ptr = act->qhd_obj.qhd_qep.ahd_before_act;
		dsh->dsh_error.err_code = E_QE0120_RULE_ACTION_LIST;
		status = E_DB_ERROR;
		break;
	    }
	}    /* end of !DSH_CT_CONTINUE3 */

	state = DSH_CT_INITIAL;			/* signal resumption after
						** BEFORE trigger */

	if (act->qhd_obj.qhd_qep.ahd_qepflag & AHD_PCOLS_UPDATE &&
		oldpartno != newpartno)
	{
	    /* Partition has changed for row in partitioned table.
	    ** Delete from 1st partition and insert into next.
	    ** We have to hope that DMF can keep it all straight.
	    */
	    status = dmf_call(DMR_DELETE, dmr_cb);
	    if (status != E_DB_OK)
	    {
		if (dmr_cb->error.err_code == E_DM0055_NONEXT)
		    dsh->dsh_error.err_code = 4599;
		else
		    dsh->dsh_error.err_code = dmr_cb->error.err_code;
		break;
	    }

	    /* Get output partition DMR_CB, then do DMR_PUT.
	    ** Don't change the fetching DSH's current dmr-cb in case
	    ** we're running a true in-place cursor.
	    */
	    status = qeq_part_open(qef_rcb, assoc_dsh, NULL, 0, 
		odmr_cb_ix,
		act->qhd_obj.qhd_qep.ahd_dmtix, newpartno);
			
	    if (status != E_DB_OK)
	    {
		dsh->dsh_error.err_code = assoc_dsh->dsh_error.err_code;
		return(status);
	    }
	    dmr_cb = (DMR_CB *)assoc_cbs[odmr_cb_ix + newpartno+1];

	    dsh->dsh_qef_targcount = 1;
	    /* Final preparation of new partition DMR_CB. */
	    dmr_cb->dmr_flags_mask = 0;
	    dmr_cb->dmr_val_logkey = 0;
	    dmr_cb->dmr_data.data_address = output;
	    dmr_cb->dmr_data.data_in_size  =
				act->qhd_obj.qhd_qep.ahd_repsize;
	    if (act->qhd_obj.qhd_qep.ahd_duphandle != QEF_SKIP_DUP)
		dmr_cb->dmr_flags_mask |= DMR_DUP_ROLLBACK;
	    status = dmf_call(DMR_PUT, dmr_cb);

	}
	else
	{
	    dsh->dsh_qef_targcount = 1;
	    if ((act->qhd_obj.qhd_qep.ahd_upd_colmap) && 
		(act->qhd_obj.qhd_qep.ahd_before_act == NULL))
		dmr_cb->dmr_attset = 
			(char *)act->qhd_obj.qhd_qep.ahd_upd_colmap;
	    else
		dmr_cb->dmr_attset = (char *)0;

	    if (act->qhd_obj.qhd_qep.ahd_duphandle != QEF_SKIP_DUP)
		dmr_cb->dmr_flags_mask |= DMR_DUP_ROLLBACK;
	    status = dmf_call(DMR_REPLACE, dmr_cb);
	}
	    
	if (status == E_DB_OK || 
		((dmr_cb->error.err_code == E_DM0046_DUPLICATE_RECORD ||
		  dmr_cb->error.err_code == E_DM0045_DUPLICATE_KEY    ||
		  dmr_cb->error.err_code == E_DM0048_SIDUPLICATE_KEY) &&
		 act->qhd_obj.qhd_qep.ahd_duphandle == QEF_SKIP_DUP))
	{
	    if (status == E_DB_OK)
	    {
	    	dsh->dsh_qef_rowcount = 1;
		/* Look for rules to apply */
		if (act->qhd_obj.qhd_qep.ahd_after_act != NULL)
		{
		    /*
		    ** Place the TID in a known location so it can be used
		    ** as a parameter to the procedure fired by the rule.
		    */
		    newbigtid.tid_i4.tpf = 0;
		    newbigtid.tid_i4.tid = dmr_cb->dmr_tid;
		    newbigtid.tid.tid_partno = newpartno;
		    MEcopy ((PTR)&newbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_tid]);   
		    MEcopy ((PTR)&oldbigtid, sizeof(DB_TID8),
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_b_tid]);   

		    MEcopy(output, act->qhd_obj.qhd_qep.ahd_repsize,
			dsh->dsh_row[act->qhd_obj.qhd_qep.u1.s1.ahd_a_row]);
		    dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_ptr = act;
		    dsh->dsh_ctx_act[dsh->dsh_depth_act].dsh_ct_status =
			DSH_CT_CONTINUE;
		    dsh->dsh_depth_act++;
		    dsh->dsh_act_ptr = act->qhd_obj.qhd_qep.ahd_after_act;
		    dsh->dsh_error.err_code = E_QE0120_RULE_ACTION_LIST;
		    status = E_DB_ERROR;
		    break;
		}
	    }
	    else
	    {
		dsh->dsh_qef_rowcount = 0;
		status = E_DB_OK;
	    }	
	    break;	    
	}
	
	if (dmr_cb->error.err_code == E_DM0055_NONEXT)
	    dsh->dsh_error.err_code = 4599;
	else
	if ( dmr_cb->error.err_code == E_DM0029_ROW_UPDATE_CONFLICT )
	{
	    dsh->dsh_qp_status |= DSH_QP_OBSOLETE;
	    dsh->dsh_error.err_code = E_QE0023_INVALID_QUERY;
	    status = E_DB_WARN;
	}
	else
	    dsh->dsh_error.err_code = dmr_cb->error.err_code;
	break;
    }

    return (status);
}
Exemplo n.º 20
0
DB_STATUS
adu_dbconst(
ADF_CB		    *adf_scb,
ADK_MAP		    *kmap,
DB_DATA_VALUE       *rdv)
{
    ADK_CONST_BLK	*k = adf_scb->adf_constants;
    bool		kcalced = FALSE;
    PTR			kptr = NULL;
    DB_ERROR		err;
    ADF_DBMSINFO	*dbi  = kmap->adk_dbi;
    i4			kbit  = kmap->adk_kbit;
    DB_STATUS		db_stat;
    bool		datetimetype = FALSE;
    DB_DT_ID		date_dt;
    u_i4		val;
    /* Beware that some of the dbmsinfo functions care not about
    ** caller lengths and will update the DBV regardless so
    ** we arrange to get the constants written directy and if
    ** need be, we conver on return. */
    DB_DATA_VALUE tmp_rdv = *rdv;
    i8 tmp_buf[1024/sizeof(i8)]; /* Make temporary aligned */

    switch (kbit)	    /* look for datetime constants */
    {
    case ADK_CURR_DATE:		/* _current_date */
	datetimetype = TRUE;
	date_dt = DB_ADTE_TYPE;
	break;

    case ADK_CURR_TIME:		/* _current_time */
	datetimetype = TRUE;
	date_dt = DB_TMW_TYPE;
	break;

    case ADK_CURR_TSTMP:	/* _current_timestamp */
	datetimetype = TRUE;
	date_dt = DB_TSW_TYPE;
	break;

    case ADK_LOCAL_TIME:	/* _local_time*/
	datetimetype = TRUE;
	date_dt = DB_TME_TYPE;
	break;

    case ADK_LOCAL_TSTMP:	/* _local_timestamp */
	datetimetype = TRUE;
	date_dt = DB_TSTMP_TYPE;
	break;
    }

    if (k != NULL)
    {
	switch (kbit)	    /* switch on known query constants */
	{
	  case ADK_BINTIM:	/* _bintim */
	    tmp_rdv.db_data = (PTR) &k->adk_bintim;
	    tmp_rdv.db_length = sizeof(k->adk_bintim);
	    break;

	  case ADK_CPU_MS:	/* _cpu_ms */
	    tmp_rdv.db_data = (PTR) &k->adk_cpu_ms;
	    tmp_rdv.db_length = sizeof(k->adk_cpu_ms);
	    break;

	  case ADK_ET_SEC:	/* _et_sec */
	    tmp_rdv.db_data = (PTR) &k->adk_et_sec;
	    tmp_rdv.db_length = sizeof(k->adk_et_sec);
	    break;

	  case ADK_DIO_CNT:	/* _dio_cnt */
	    tmp_rdv.db_data = (PTR) &k->adk_dio_cnt;
	    tmp_rdv.db_length = sizeof(k->adk_dio_cnt);
	    break;

	  case ADK_BIO_CNT:	/* _bio_cnt */
	    tmp_rdv.db_data = (PTR) &k->adk_bio_cnt;
	    tmp_rdv.db_length = sizeof(k->adk_bio_cnt);
	    break;

	  case ADK_PFAULT_CNT:	/* _pfault_cnt */
	    tmp_rdv.db_data = (PTR) &k->adk_pfault_cnt;
	    tmp_rdv.db_length = sizeof(k->adk_pfault_cnt);
	    break;

	  case ADK_CURR_DATE:	/* _current_date */
	    tmp_rdv.db_data = (PTR) &k->adk_curr_date;
	    tmp_rdv.db_length = sizeof(k->adk_curr_date);
	    break;

	  case ADK_CURR_TIME:	/* _current_time */
	    tmp_rdv.db_data = (PTR) &k->adk_curr_time;
	    tmp_rdv.db_length = sizeof(k->adk_curr_time);
	    break;

	  case ADK_CURR_TSTMP:	/* _current_timestamp */
	    tmp_rdv.db_data = (PTR) &k->adk_curr_tstmp;
	    tmp_rdv.db_length = sizeof(k->adk_curr_tstmp);
	    break;

	  case ADK_LOCAL_TIME:	/* _local_time*/
	    tmp_rdv.db_data = (PTR) &k->adk_local_time;
	    tmp_rdv.db_length = sizeof(k->adk_local_time);
	    break;

	  case ADK_LOCAL_TSTMP:	/* _local_timestamp */
	    tmp_rdv.db_data = (PTR) &k->adk_local_tstmp;
	    tmp_rdv.db_length = sizeof(k->adk_local_tstmp);
	    break;

	  default:
	    return (adu_error (adf_scb, E_AD9998_INTERNAL_ERROR,
		2, 0, "dbmsinfo kbit"));
	}
	
	if (k->adk_set_mask & kbit) /* Has this value been calculated yet? */
	    kcalced = TRUE;
    }
    else
	tmp_rdv.db_data = (PTR)tmp_buf;


    if (!kcalced)
    {
	/* Must calculate value from scratch */

	if (datetimetype)
	{
	    AD_NEWDTNTRNL       dn;
	    struct timevect     tv;
	    DB_STATUS           db_stat;
	    i4			sec_time_zone;
	    HRSYSTIME		hrsystime;

	    TMhrnow(&hrsystime);

	    MEfill ((u_i2) sizeof(i4)*10, NULLCHAR, (PTR) &tv);

	    adu_cvtime((i4) hrsystime.tv_sec, (i4)hrsystime.tv_nsec, &tv);

	    MEfill((u_i2) sizeof(AD_NEWDTNTRNL), NULLCHAR, (PTR) &dn);
	    /* Interpret the time vector */
	    dn.dn_year    = (i2)tv.tm_year + 1900;
	    dn.dn_month   = (i2)tv.tm_mon + 1;
	    dn.dn_day     = tv.tm_mday;
	    dn.dn_seconds = tv.tm_hour * 3600 + tv.tm_min * 60 + tv.tm_sec;
	    dn.dn_nsecond = tv.tm_nsec;
	    dn.dn_dttype  = date_dt;

	    sec_time_zone = TMtz_search(adf_scb->adf_tzcb, TM_TIMETYPE_GMT,
				 (i4) hrsystime.tv_sec);

	    AD_TZ_SETNEW(&dn, sec_time_zone);

	    dn.dn_status = AD_DN_ABSOLUTE;
	    switch (date_dt)
	    {
	    case DB_ADTE_TYPE:	/* _current_date */
		dn.dn_seconds = 0;
		dn.dn_nsecond = 0;
		dn.dn_status2 |= AD_DN2_ADTE_TZ;
		dn.dn_status |= AD_DN_YEARSPEC|AD_DN_MONTHSPEC|AD_DN_DAYSPEC;
		break;

	    case DB_TME_TYPE:	/* _local_time*/
		dn.dn_status2 |= AD_DN2_TZ_OFF_LCL;
		/*FALLTHROUGH*/
	    case DB_TMW_TYPE:	/* _current_time */
		dn.dn_status |= AD_DN_TIMESPEC;
		dn.dn_status2 |= AD_DN2_NO_DATE;
		break;

	    case DB_TSTMP_TYPE:	/* _local_timestamp */
		dn.dn_status2 |= AD_DN2_TZ_OFF_LCL;
		/*FALLTHROUGH*/
	    case DB_TSW_TYPE:	/* _current_timestamp */
		dn.dn_status |= AD_DN_YEARSPEC|AD_DN_MONTHSPEC|AD_DN_DAYSPEC;
		dn.dn_status |= AD_DN_TIMESPEC;
		break;
	    }

	    /* Convert straight into constant data area */
	    if (db_stat = adu_7from_dtntrnl (adf_scb, &tmp_rdv, &dn))
		return (db_stat);
	}
	else if (dbi == NULL  ||  dbi->dbi_func == NULL)
	{
	    /* If no function ptr in dbmsinfo array, set default value */
	    if (db_stat = adc_getempty(adf_scb, &tmp_rdv))
		return (db_stat);
	}
	else
	{
	    /* Get the value from the proper dbmsinfo function */

	    /*
	    ** NOTE: If the dbmsinfo routines ever change the size of
	    ** of the returned object, it will be assumed that the length
	    ** will match the adk_* buffer length. If not, there will
	    ** be a risk of uninitialised data slipping in.
	    */
	    if (db_stat = (*dbi->dbi_func)(dbi, NULL, &tmp_rdv, &err))
		return (db_stat);
	}

	/* We now have the calculated result written directly to the
	** constant buffers if they exist or to the tmp_buf.
	** Either way, we don't need to write the constant again, we just
	** need to convert out to the return buffer/dbv.
	*/

	/* Don't forget to set the `already calculated' bit */
	if (k)
	    k->adk_set_mask |= kbit;
    }

    /* We have the value requested, so just set result and return */
    if (rdv->db_datatype == DB_INT_TYPE)
    {	/* Currently, all query constants are uints or dates */
	u_i8 val;
	switch (tmp_rdv.db_length)
	{
	case 8:
	    val = (u_i8)*(u_i8*)tmp_rdv.db_data;
	    break;
	case 4:
	    val = (u_i8)*(u_i4*)tmp_rdv.db_data;
	    break;
	case 2:
	    val = (u_i8)*(u_i2*)tmp_rdv.db_data;
	    break;
	case 1:
	    val = (u_i8)*(u_i1*)tmp_rdv.db_data;
	    break;
	}
	switch (rdv->db_length)
	{
	case 8:
	    I8ASSIGN_MACRO(val, *(u_i8 *)rdv->db_data);
	    break;
	case 4:
	    {
		u_i4 val4 = (u_i4)val;
		I4ASSIGN_MACRO(val4, *(u_i4 *)rdv->db_data);
	    }
	    break;
	case 2:
	    {
		u_i2 val2 = (u_i2)val;
		I2ASSIGN_MACRO(val2, *(i2*)rdv->db_data);
	    }
	    break;
	case 1:
	    *(u_i1 *)rdv->db_data = (u_i1)val;
	    break;
	default:
	    return (adu_error (adf_scb, E_AD9998_INTERNAL_ERROR,
		2, 0, "dbmsinfo isz"));
	}
    }
    else if (tmp_rdv.db_length != rdv->db_length)
    {
	return (adu_error (adf_scb, E_AD9998_INTERNAL_ERROR,
		2, 0, "dbmsinfo len"));
    }
    else
    {
	MEcopy(tmp_rdv.db_data, rdv->db_length, rdv->db_data);
    }
    return (E_DB_OK);
}