コード例 #1
0
ファイル: omi_prc_def.c プロジェクト: 5HT/mumps
int
omi_prc_def(omi_conn *cptr, char *xend, char *buff, char *bend)
{
    GBLREF bool	 undef_inhibit;

    char	*bptr;
    omi_li	 len;
    int		 rv;
    mval	 vo, vd, vg;

    bptr = buff;

/*  Global Ref */
    OMI_LI_READ(&len, cptr->xptr);
/*  Set up a condition handler */
    ESTABLISH_RET(omi_dbms_ch,0);
    rv = omi_gvextnam(cptr, len.value, cptr->xptr);
/*  If true, there was an error finding the global reference in the DBMS */
    if (rv < 0)
    {
	REVERT;
	return rv;
    }
    cptr->xptr += len.value;

/*  Bounds checking */
    if (cptr->xptr > xend)
    {
	REVERT;
	return -OMI_ER_PR_INVMSGFMT;
    }

/*  We want to make sure there is plenty of space in the string pool
 *  for all three operations ($ORDER, $GET, $DATA) */
    if (cptr->exts & OMI_XTF_NEWOP)
	stp_gcol(0);

/*  $DATA */
    op_gvdata(&vd);
    if (!(vd.mvtype & MV_INT))
    {
	REVERT;
	return -OMI_ER_DB_UNRECOVER;
    }

    if (cptr->exts & OMI_XTF_NEWOP)
    {
/*	$GET */
	undef_inhibit = TRUE;
	rv = op_gvget(&vg);
/*	$ORDER */
	op_gvorder(&vo);
	OMI_SI_WRIT(vo.str.len, bptr);
	if (vo.str.len)
	{
	    memcpy(bptr, vo.str.addr, vo.str.len);
	    bptr += vo.str.len;
	}
    }

/*  $DATA (buffer write) */
    OMI_SI_WRIT(vd.m[1] / MV_BIAS, bptr);

    if (cptr->exts & OMI_XTF_NEWOP)
    {
/*	$GET (buffer write) */
	OMI_SI_WRIT((rv ? 1 : 0), bptr);
	if (!rv || !vg.str.len)
	    OMI_LI_WRIT(0, bptr);
	else
	{
	    OMI_LI_WRIT(vg.str.len, bptr);
	    memcpy(bptr, vg.str.addr, vg.str.len);
	    bptr += vg.str.len;
	}
    }

    REVERT;

    return (int)(bptr - buff);

}
コード例 #2
0
void gvzwr_fini(zshow_out *out, int pat)
{
	char 		m[SIZEOF(mident_fixed)];
	mval 		local, data;
	gv_key		*old;
	gvnh_reg_t	*gvnh_reg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	if (!gv_currkey)
		gvinit();
	ESTABLISH(gvzwrite_ch);
	zwr_output = out;
	assert(INVALID_GV_TARGET == reset_gv_target);
	reset_gv_target = gv_target;
	DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
	gvzwrite_block->gd_reg = gv_cur_region;
	gvzwrite_block->old_targ = (unsigned char *)gv_target;
	old = (gv_key *)malloc(SIZEOF(gv_key) + gv_currkey->end);
	gvzwrite_block->old_key = (unsigned char *)old;
	memcpy(gvzwrite_block->old_key, gv_currkey, SIZEOF(gv_key) + gv_currkey->end);
	gvzwrite_block->gv_last_subsc_null = TREF(gv_last_subsc_null);
	gvzwrite_block->gv_some_subsc_null = TREF(gv_some_subsc_null);
	if (!pat)
	{
		local = *gvzwrite_block->pat;
		if (local.str.len)  /* New reference. Will get new gv_target.. */
		{
			gv_target = NULL;
			gv_currkey->base[0] = '\0';
			op_gvname(VARLSTCNT(1) &local);
 			op_gvdata(&data);
			if (!(MV_FORCE_INTD(&data)))
			{
				if (!undef_inhibit)
					sgnl_gvundef();
			} else
			{
				gvzwrite_block->fixed = (gvzwrite_block->fixed ? TRUE : FALSE);
				gvzwr_var(MV_FORCE_INTD(&data), 0);
			}
		} else	/* Old (naked) reference. Keep previous gv_target reference */
		{
			if (gv_currkey->prev == 0)
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GVNAKED);
			gv_currkey->end = gv_currkey->prev;
			gv_currkey->base[gv_currkey->end] = 0;
			gv_currkey->prev = 0;
			/* If gvnh_reg corresponds to a spanning global, then determine
			 * gv_cur_region/gv_target/gd_targ_* variables based on updated gv_currkey.
			 */
			gvnh_reg = TREF(gd_targ_gvnh_reg);	/* set by op_gvname in previous call */
			GV_BIND_SUBSNAME_FROM_GVNH_REG_IF_GVSPAN(gvnh_reg, gd_header, gv_currkey);
			op_gvdata(&data);
			if (!(MV_FORCE_INTD(&data)))
			{
				if (!undef_inhibit)
					sgnl_gvundef();
			} else
			{
				gvzwrite_block->fixed = (gvzwrite_block->fixed ? TRUE : FALSE);
				gvzwr_var((int4)MV_FORCE_INTD(&data), 0);
			}
		}
	} else
	{
		gv_target = NULL;
		gv_currkey->base[0] = '\0';
		local.mvtype = MV_STR;
		local.str.addr = &m[0];
		local.str.len = 1;
		m[0] = '%';

		gvzwrite_block->fixed = FALSE;
		for (; ;)
		{
			op_gvname(VARLSTCNT(1) &local);
			if (do_pattern(&local, gvzwrite_block->pat))
			{
				op_gvdata(&data);
				if ((MV_FORCE_INTD(&data)))
				{
					gvzwr_var((int4)MV_FORCE_INTD(&data), 0);
				}
			}
			op_gvorder(&local);
			if (local.str.len)
			{
				assert(local.str.len <= MAX_MIDENT_LEN + 1);
				local.str.addr++;
				local.str.len--;
				memcpy(&m[0], local.str.addr, local.str.len);
				local.str.addr = &m[0];
			} else
				break;
		}
	}
	gvzwrite_clnup();	/* this routine is called by gvzwrite_ch() too */
	REVERT;
	return;
}
コード例 #3
0
void op_zprevious(mval *v)
{
	int4			n;
	int			min_reg_index, reg_index, res;
	mname_entry		gvname;
	mval			tmpmval, *datamval;
	enum db_acc_method	acc_meth;
	boolean_t		found, ok_to_change_currkey;
	gd_binding		*gd_map_start, *map, *prev_map;
	gd_addr			*gd_targ;
	gvnh_reg_t		*gvnh_reg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(gv_currkey->prev || !TREF(gv_last_subsc_null));
	if (gv_currkey->prev)
	{	/* If last subscript is a NULL subscript, modify gv_currkey such that a gvcst_search of the resulting gv_currkey
		 * will find the last available subscript. But in case of dba_usr, (the custom implementation of $ZPREVIOUS which
		 * is overloaded for DDP now but could be more in the future) it is better to hand over gv_currkey as it is so
		 * the custom implementation can decide what to do with it.
		 */
		acc_meth = REG_ACC_METH(gv_cur_region);
		ok_to_change_currkey = (dba_usr != acc_meth);
		if (TREF(gv_last_subsc_null) && ok_to_change_currkey)
		{	/* Replace the last subscript with the highest possible subscript value i.e. the byte sequence
			 * 	0xFF (STR_SUB_MAXVAL), 0xFF, 0xFF ...  as much as possible i.e. until gv_currkey->top permits.
			 * This subscript is guaranteed to be NOT present in the database since a user who tried to set this
			 * exact subscripted global would have gotten a GVSUBOFLOW error (because GT.M sets aside a few bytes
			 * of padding space). And yet this is guaranteed to collate AFTER any existing subscript. Therefore we
			 * can safely do a gvcst_zprevious on this key to get at the last existing key in the database.
			 *
			 * With    standard null collation, the last subscript will be 0x01
			 * Without standard null collation, the last subscript will be 0xFF
			 * Assert that is indeed the case as this will be used to restore the replaced subscript at the end.
			 */
			assert(gv_cur_region->std_null_coll || (STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]));
			assert(!gv_cur_region->std_null_coll || (SUBSCRIPT_STDCOL_NULL == gv_currkey->base[gv_currkey->prev]));
			assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->prev + 1]);
			assert(gv_currkey->end == gv_currkey->prev + 2);
			assert(gv_currkey->end < gv_currkey->top); /* need "<" (not "<=") to account for terminating 0x00 */
			GVZPREVIOUS_APPEND_MAX_SUBS_KEY(gv_currkey, gv_target);
		}
		if ((dba_bg == acc_meth) || (dba_mm == acc_meth))
		{
			gvnh_reg = TREF(gd_targ_gvnh_reg);
			if (NULL == gvnh_reg)
				found = (gv_target->root ? gvcst_zprevious() : FALSE);
			else
				INVOKE_GVCST_SPR_XXX(gvnh_reg, found = gvcst_spr_zprevious());
		} else if (dba_cm == acc_meth)
			found = gvcmx_zprevious();
		else
			found = gvusr_zprevious();
		v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK)
				* by this to-be-overwritten mval */
		if (found)
		{
			gv_altkey->prev = gv_currkey->prev;
			if (!IS_STP_SPACE_AVAILABLE(MAX_KEY_SZ))
			{
				if ((0xFF != gv_altkey->base[gv_altkey->prev])
						&& (SUBSCRIPT_STDCOL_NULL != gv_altkey->base[gv_altkey->prev]))
					n = MAX_FORM_NUM_SUBLEN;
				else
				{
					n = gv_altkey->end - gv_altkey->prev;
					assert(n > 0);
				}
				v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this (BYPASSOK)
						 * to-be-overwritten mval */
				ENSURE_STP_FREE_SPACE(n);
			}
			v->str.addr = (char *)stringpool.free;
			v->str.len = MAX_KEY_SZ;
			stringpool.free = gvsub2str(&gv_altkey->base[gv_altkey->prev], &(v->str), FALSE);
			v->str.len = INTCAST((char *)stringpool.free - v->str.addr);
			assert(v->str.addr < (char *)stringpool.top && v->str.addr >= (char *)stringpool.base);
			assert(v->str.addr + v->str.len <= (char *)stringpool.top &&
				v->str.addr + v->str.len >= (char *)stringpool.base);
		} else
			v->str.len = 0;
		v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
		if (TREF(gv_last_subsc_null) && ok_to_change_currkey)
		{	/* Restore gv_currkey to what it was at function entry time */
			gv_currkey->base[gv_currkey->prev + 1] = KEY_DELIMITER;
			if (gv_cur_region->std_null_coll)
				gv_currkey->base[gv_currkey->prev] = SUBSCRIPT_STDCOL_NULL;
			assert(gv_cur_region->std_null_coll || (STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]));
			gv_currkey->end = gv_currkey->prev + 2;
			gv_currkey->base[gv_currkey->end] = KEY_DELIMITER;
		}
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
	} else
	{	/* the following section is for $ZPREVIOUS(^gname) */
		assert(2 <= gv_currkey->end);
		assert(gv_currkey->end < (MAX_MIDENT_LEN + 2));	/* until names are not in midents */
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
		gd_targ = TREF(gd_targ_addr);
		gd_map_start = gd_targ->maps;
		map = gv_srch_map(gd_targ, (char *)&gv_currkey->base[0], gv_currkey->end - 1);
		assert(map > (gd_map_start + 1));
		/* If ^gname starts at "map" start search from map-1 since $ZPREVIOUS(^gname) is sought */
		BACK_OFF_ONE_MAP_ENTRY_IF_EDGECASE(gv_currkey->base, gv_currkey->end - 1, map);
		found = FALSE;
		/* The first map entry corresponds to local locks. The second map entry does not contain any globals.
		 * Therefore, any search for globals needs to only look after these maps. Hence the "gd_map_start + 1" below.
		 */
		for ( ; map > gd_map_start + 1; map = prev_map)
		{
			prev_map = map - 1;
			gv_cur_region = map->reg.addr;
			if (!gv_cur_region->open)
				gv_init_reg(gv_cur_region);
			change_reg();
			acc_meth = REG_ACC_METH(gv_cur_region);
			/* search region, entries in directory tree could have empty GVT in which case move on to previous entry */
			for ( ; ; )
			{
				assert(0 == gv_currkey->prev);	/* or else gvcst_zprevious could get confused */
				if ((dba_bg == acc_meth) || (dba_mm == acc_meth))
				{
					gv_target = cs_addrs->dir_tree;
					found = gvcst_zprevious();
				} else  if (dba_cm == acc_meth)
					found = gvcmx_zprevious();
				else
					found = gvusr_zprevious();
				if ('#' == gv_altkey->base[0]) /* don't want to give any hidden ^#* global, e.g "^#t" */
					found = FALSE;
				if (!found)
					break;
				assert(1 < gv_altkey->end);
				assert(gv_altkey->end < (MAX_MIDENT_LEN + 2));	/* until names are not in midents */
				res = memcmp(gv_altkey->base, prev_map->gvkey.addr, gv_altkey->end);
				assert((0 != res) || (gv_altkey->end <= prev_map->gvkey_len));
				if (0 > res)
				{	/* The global name we found is less than the maximum value in the previous map
					 * so this name is not part of the current map for sure. Move on to previous map.
					 */
					found = FALSE;
					break;
				}
				gvname.var_name.addr = (char *)gv_altkey->base;
				gvname.var_name.len = gv_altkey->end - 1;
				if (dba_cm == acc_meth)
					break;
				COMPUTE_HASH_MNAME(&gvname);
				GV_BIND_NAME_AND_ROOT_SEARCH(gd_targ, &gvname, gvnh_reg);	/* updates "gv_currkey" */
				assert((NULL != gvnh_reg->gvspan) || (gv_cur_region == map->reg.addr));
				if (NULL != gvnh_reg->gvspan)
				{	/* gv_target would NOT have been initialized by GV_BIND_NAME in this case.
					 * So finish that initialization.
					 */
					datamval = &tmpmval;
					/* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH
					 * 	(e.g. setting gv_cur_region for spanning globals)
					 */
					GV_BIND_SUBSNAME_IF_GVSPAN(gvnh_reg, gd_targ, gv_currkey, gvnh_reg->gd_reg);
					op_gvdata(datamval);
					if (MV_FORCE_INT(datamval))
						break;
				} else
				{	/* else gv_target->root would have been initialized by GV_BIND_NAME_AND_ROOT_SEARCH */
					if ((0 != gv_target->root) && (0 != gvcst_data()))
						break;
				}
			}
			if (found)
				break;
			/* If previous map corresponding to a spanning global, then do not update gv_currkey as that would
			 * effectively cause the spanning global to be skipped. If gvkey_len == gvname_len + 1 it is NOT
			 * a spanning global map entry.
			 */
			assert(prev_map->gvkey_len >= (prev_map->gvname_len + 1));
			if ((prev_map > (gd_map_start + 1)) && (prev_map->gvkey_len == (prev_map->gvname_len + 1)))
			{
				assert(strlen(prev_map->gvkey.addr) == prev_map->gvname_len);
				gv_currkey->end = prev_map->gvname_len + 1;
				assert(gv_currkey->end <= (MAX_MIDENT_LEN + 1));
				memcpy(gv_currkey->base, prev_map->gvkey.addr, gv_currkey->end);
				assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
				gv_currkey->base[gv_currkey->end] = KEY_DELIMITER;
				assert(gv_currkey->top > gv_currkey->end);	/* ensure we are within allocated bounds */
			}
		}
		/* Reset gv_currkey as we have potentially skipped one or more regions so we no
		 * longer can expect gv_currkey/gv_cur_region/gv_target to match each other.
		 */
		gv_currkey->end = 0;
		gv_currkey->base[0] = KEY_DELIMITER;
		v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK)
				* by this to-be-overwritten mval */
		if (found)
		{
			if (!IS_STP_SPACE_AVAILABLE(gvname.var_name.len + 1))
			{
				v->str.len = 0;	/* so stp_gcol ignores otherwise incompletely setup mval (BYPASSOK) */
				INVOKE_STP_GCOL(gvname.var_name.len + 1);
			}
			v->str.addr = (char *)stringpool.free;
			*stringpool.free++ = '^';
			memcpy(stringpool.free, gvname.var_name.addr, gvname.var_name.len);
			stringpool.free += gvname.var_name.len;
			v->str.len = gvname.var_name.len + 1;
			assert(v->str.addr < (char *)stringpool.top && v->str.addr >= (char *)stringpool.base);
			assert(v->str.addr + v->str.len <= (char *)stringpool.top &&
				v->str.addr + v->str.len >= (char *)stringpool.base);
		} else
			v->str.len = 0;
		v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
		/* No need to restore gv_currkey (to what it was at function entry) as it is already set to NULL */
	}
	return;
}
コード例 #4
0
ファイル: gvzwr_fini.c プロジェクト: 5HT/mumps
void gvzwr_fini(zshow_out *out, int pat)
{
	char 		m[sizeof(mident_fixed)];
	mval 		local, data;
	gv_key		*old;

	error_def(ERR_GVNAKED);

	if (!gv_currkey)
		gvinit();

	ESTABLISH(gvzwrite_ch);

	zwr_output = out;
	assert(INVALID_GV_TARGET == reset_gv_target);
	reset_gv_target = gv_target;
	DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC;
	gvzwrite_block.gd_reg = gv_cur_region;
	gvzwrite_block.old_targ = (unsigned char *)gv_target;
	old = (gv_key *)malloc(sizeof(gv_key) + gv_currkey->end);
	gvzwrite_block.old_key = (unsigned char *)old;
	memcpy(gvzwrite_block.old_key, gv_currkey, sizeof(gv_key) + gv_currkey->end);
	gvzwrite_block.old_map = gd_map;
	gvzwrite_block.old_map_top = gd_map_top;
	if (!pat)
	{
		local = *gvzwrite_block.pat;
		if (local.str.len)  /* New reference. Will get new gv_target.. */
		{
			gv_target = NULL;
			gv_currkey->base[0] = '\0';
			op_gvname(VARLSTCNT(1) &local);
 			op_gvdata(&data);
			if (!(MV_FORCE_INTD(&data)))
				sgnl_gvundef();
			else
			{
				gvzwrite_block.fixed = (gvzwrite_block.fixed ? TRUE : FALSE);
				gvzwr_var(MV_FORCE_INTD(&data), 0);
			}
		} else               /* Old (naked) reference. Keep previous gv_target reference */
		{
			if (gv_currkey->prev == 0)
				rts_error(VARLSTCNT(1) ERR_GVNAKED);

			gv_currkey->end = gv_currkey->prev;
			gv_currkey->base[ gv_currkey->end ] = 0;
			gv_currkey->prev = 0;
			op_gvdata(&data);
			if (!(MV_FORCE_INTD(&data)))
				sgnl_gvundef();
			else
			{
				gvzwrite_block.fixed = (gvzwrite_block.fixed ? TRUE : FALSE);
				gvzwr_var((int4)MV_FORCE_INTD(&data), 0);
			}
		}
	} else
	{
		gv_target = NULL;
		gv_currkey->base[0] = '\0';
		local.mvtype = MV_STR;
		local.str.addr = &m[0];
		local.str.len = 1;
		m[0] = '%';

		gvzwrite_block.fixed = FALSE;
		for (; ;)
		{
			op_gvname(VARLSTCNT(1) &local);
			if (do_pattern(&local, gvzwrite_block.pat))
			{
				op_gvdata(&data);
				if ((MV_FORCE_INTD(&data)))
				{
					gvzwr_var((int4)MV_FORCE_INTD(&data), 0);
				}
			}
			op_gvorder(&local);
			if (local.str.len)
			{
				assert(local.str.len <= MAX_MIDENT_LEN + 1);
				local.str.addr++;
				local.str.len--;
				memcpy(&m[0], local.str.addr, local.str.len);
				local.str.addr = &m[0];
			} else
				break;
		}
	}
	gvzwrite_clnup();	/* this routine is called by gvzwrite_ch() too */
	REVERT;
	return;
}
コード例 #5
0
ファイル: omi_prc_ordr.c プロジェクト: ChristyV/fis-gtm
int omi_prc_ordr(omi_conn *cptr, char *xend, char *buff, char *bend)
{
	char		*bptr;
	int			 rv;
	omi_li		 len;
	mval		 vo, vd, vg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	bptr = buff;
	/* Global Ref */
	OMI_LI_READ(&len, cptr->xptr);
	/* Condition handler for DBMS operations */
	ESTABLISH_RET(omi_dbms_ch,0);
	rv = omi_gvextnam(cptr, len.value, cptr->xptr);
	/* If true, there was an error finding the global reference in the DBMS */
	if (rv < 0)
	{
		REVERT;
		return rv;
	}
	cptr->xptr += len.value;

	/* Bounds checking */
	if (cptr->xptr > xend)
	{
		REVERT;
		return -OMI_ER_PR_INVMSGFMT;
	}

	/* We want to make sure there is plenty of space in the string pool for all three operations ($ORDER, $GET, $DATA) */
	if (cptr->exts & OMI_XTF_NEWOP)
		INVOKE_STP_GCOL(0);

	/* $ORDER */
	op_gvorder(&vo);
	/* $ORDER (buffer write) */
	OMI_SI_WRIT(vo.str.len, bptr);
	if (vo.str.len)
	{
		memcpy(bptr, vo.str.addr, vo.str.len);
		bptr += vo.str.len;
	}
	/* Bunching */
	if (cptr->exts & OMI_XTF_NEWOP)
	{
		if (vo.str.len)
		{
			if (!gv_currkey->prev)
			{
				if (*vo.str.addr != '^')
				{
					REVERT;
					return -OMI_ER_PR_INVGLOBREF;
				}
				vo.str.addr++;	vo.str.len--;
				GV_BIND_NAME_AND_ROOT_SEARCH(cptr->ga, &vo.str);
				vo.str.addr--;	vo.str.len++;
				TREF(gv_last_subsc_null) = FALSE;
			} else
			{
				if (gv_currkey->top != gv_altkey->top)
				{
					REVERT
					return -OMI_ER_DB_UNRECOVER;
				}
				memcpy(gv_currkey, gv_altkey, gv_altkey->end + SIZEOF(gv_key));
				TREF(gv_last_subsc_null) = FALSE;
			}

			/* $DATA */
			op_gvdata(&vd);
			if (!(vd.mvtype & MV_INT))
			{
				REVERT;
				return -OMI_ER_DB_UNRECOVER;
			}
			/* $GET */
			undef_inhibit = TRUE;
			rv = op_gvget(&vg);
			/* $DATA (buffer write) */
			OMI_SI_WRIT(vd.m[1] / MV_BIAS, bptr);
			/* $GET (buffer write) */
			OMI_SI_WRIT((rv ? 1 : 0), bptr);
			if (!rv || !vg.str.len)
				OMI_LI_WRIT(0, bptr);
			else
			{
				OMI_LI_WRIT(vg.str.len, bptr);
				memcpy(bptr, vg.str.addr, vg.str.len);
				bptr += vg.str.len;
			}
		} else
		{	/* Otherwise $ORDER returned a null */
コード例 #6
0
ファイル: gv_select.c プロジェクト: h4ck3rm1k3/FIS-GT.M
void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist *gl_head,
	int *reg_max_rec, int *reg_max_key, int *reg_max_blk)
{
	bool				stashed = FALSE;
	int				num_quote, len;
	char				*ptr, *ptr1, *c;
	mstr				gmap[256], *gmap_ptr, gmap_beg, gmap_end;
	mval				val, curr_gbl_name;
	glist				*gl_tail, *gl_ptr;
	htab_desc        		*ext_hash;
	mname                           ht_mname;
	ht_entry                        *h;

	error_def(ERR_FREEZE);
	error_def(ERR_DBRDONLY);
	error_def(ERR_SELECTSYNTAX);
	error_def(ERR_MUNOFINISH);
	error_def(ERR_MUNOACTION);

	memset(gmap, 0, sizeof(gmap));
	for (ptr = cli_buff; *ptr; ptr = ptr1)
	{
		for (ptr1 = ptr; ; ptr1++)
		{
			if (',' == *ptr1)
			{
				len = ptr1 - ptr;
				ptr1++;
				break;
			}
			else if (!*ptr1)
			{
				len = ptr1 - ptr;
				break;
			}
		}
		gmap_beg.addr = ptr;
		c = gmap_beg.addr + len - 1;
		num_quote = 0;
		while ('"' == *c)
		{
			len--;
			c--;
			num_quote++;
		}
		if (0 >= len)
		{
			gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
			mupip_exit(ERR_MUNOACTION);
		}
		c = gmap_beg.addr;
		while (0 < num_quote)
		{
			if ('"' == *c)
			{
				c++;
				len--;
			}
			else
			{
				gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
				mupip_exit(ERR_MUNOACTION);
			}
			num_quote--;
		}
		gmap_beg.addr = c;
		if ('^' == *c)
		{
			gmap_beg.addr++;
			len--;
		}
		gmap_beg.len = len;
		c = mu_extr_ident(&gmap_beg);
		len -= (c - gmap_beg.addr);
		assert(len >= 0);
		if (0 == len)
			gmap_end = gmap_beg;
		else if (gmap_beg.len == 1 && '*' == *c)
		{
			gmap_beg.addr = (char*)&percent_lit;
			gmap_beg.len = sizeof(percent_lit);
			gmap_end.addr =  (char*)&tilde_lit;
			gmap_end.len = sizeof(tilde_lit);
		}
		else if (1 == len && '*' == *c)
		{
			gmap_end = gmap_beg;
			gmap_beg.len--;
			*c = '~';
		}
		else if (':' != *c)
		{
			gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
			mupip_exit(ERR_MUNOACTION);
		}
		else
		{
			gmap_beg.len = c - gmap_beg.addr;
			c++;
			gmap_end.addr = c;
			gmap_end.len = len - 1;
			if ('^' == *c)
			{
				gmap_end.addr++;
				gmap_end.len--;
			}
			c = mu_extr_ident(&gmap_end);
			if (c - gmap_end.addr != gmap_end.len || mstrcmp(&gmap_beg, &gmap_end) > 0)
			{
				gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
				mupip_exit(ERR_MUNOACTION);
			}
		}
		global_map(gmap, &gmap_beg, &gmap_end);
	}

	if (freeze)
	{
		ext_hash = (htab_desc *)malloc(sizeof(htab_desc));
                ht_init(ext_hash, 0);
                memset(&ht_mname.txt[0], 0, sizeof(mname));
	}
	gl_head->next = NULL;
	gl_tail = gl_head;
	*reg_max_rec = 0;
        *reg_max_key = 0;
        *reg_max_blk = 0;
	for (gmap_ptr = gmap; gmap_ptr->addr ; gmap_ptr++)
	{
		curr_gbl_name.mvtype = MV_STR;
		curr_gbl_name.str = *gmap_ptr++;
		op_gvname(VARLSTCNT(1) &curr_gbl_name);
		if (dba_cm == gv_cur_region->dyn.addr->acc_meth)
		{	util_out_print("Can not select globals from region !AD across network",TRUE,gv_cur_region->rname_len,
					gv_cur_region->rname);
			mupip_exit(ERR_MUNOFINISH);

		}
		if (dba_bg != gv_cur_region->dyn.addr->acc_meth && dba_mm != gv_cur_region->dyn.addr->acc_meth)
		{
			assert(gv_cur_region->dyn.addr->acc_meth == dba_usr);
			util_out_print("Can not select globals from non-GTC region !AD",TRUE,gv_cur_region->rname_len,
					gv_cur_region->rname);
			mupip_exit(ERR_MUNOFINISH);
		}
		op_gvdata(&val);
		if (0 == val.m[1])
		{
			op_gvname(VARLSTCNT(1) &curr_gbl_name);
			op_gvorder(&curr_gbl_name);
			if (!curr_gbl_name.str.len)
				break;
			assert('^' == *curr_gbl_name.str.addr);
			curr_gbl_name.str.addr++;
			curr_gbl_name.str.len--;
		}
		for (;;)
		{
			if (mstrcmp(&curr_gbl_name.str, gmap_ptr) > 0)
				break;
			if (freeze)
                        {
                                memcpy(&ht_mname.txt[0], &gv_cur_region, sizeof(int4));
                                h = ht_put(ext_hash, &ht_mname, &stashed);
                                if (stashed)
                                {
                                        if (cs_addrs->hdr->freeze)
                                        {
                                                gtm_putmsg(VARLSTCNT(4) ERR_FREEZE, 2, gv_cur_region->rname_len,
							gv_cur_region->rname);
                                                mupip_exit(ERR_MUNOFINISH);
                                        }
					/* Cannot proceed for read-only data files */
					if (gv_cur_region->read_only)
					{
						util_out_print("Cannot freeze the database",TRUE);
						gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2,
							DB_LEN_STR(gv_cur_region));
						mupip_exit(ERR_MUNOFINISH);
					}
                                        while (FALSE == region_freeze(gv_cur_region, TRUE, FALSE))
                                                hiber_start(1000);
					wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH);
                                }
                        }
			assert(curr_gbl_name.str.len > 0);
			gl_ptr = (glist*)malloc(sizeof(glist) - 1 + curr_gbl_name.str.len);
			gl_ptr->name.mvtype = MV_STR;
			gl_ptr->name.str.addr = (char*)gl_ptr->nbuf;
			gl_ptr->name.str.len = curr_gbl_name.str.len;
			memcpy(gl_ptr->nbuf, curr_gbl_name.str.addr, curr_gbl_name.str.len);
			gl_ptr->next = 0;
			gl_tail->next = gl_ptr;
			gl_tail = gl_ptr;
			if (*reg_max_rec < cs_data->max_rec_size) *reg_max_rec = cs_data->max_rec_size;
                        if (*reg_max_key < cs_data->max_key_size) *reg_max_key = cs_data->max_key_size;
                        if (*reg_max_blk < cs_data->blk_size) *reg_max_blk = cs_data->blk_size;
			op_gvname(VARLSTCNT(1) &gl_tail->name);
			op_gvorder(&curr_gbl_name);
			if (0 == curr_gbl_name.str.len)
			{
				(gmap_ptr + 1)->addr = 0;
				break;
			}
			assert('^' == *curr_gbl_name.str.addr);
			curr_gbl_name.str.addr++;
			curr_gbl_name.str.len--;
		}
	}
}
コード例 #7
0
ファイル: op_merge.c プロジェクト: CeperaCPP/fis-gtm
void op_merge(void)
{
	boolean_t		found, check_for_null_subs, is_base_var;
	lv_val			*dst_lv;
	mval 			*mkey, *value, *subsc;
	int			org_glvn1_keysz, org_glvn2_keysz, delta2, dollardata_src, dollardata_dst, sbs_depth;
	unsigned char		*ptr, *ptr2;
	unsigned char  		buff[MAX_ZWR_KEY_SZ];
	unsigned char		nullcoll_src, nullcoll_dst;
	zshow_out		output;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(MAX_STRLEN >= MAX_ZWR_KEY_SZ);
	assert ((merge_args == (MARG1_LCL | MARG2_LCL)) ||
		(merge_args == (MARG1_LCL | MARG2_GBL)) ||
		(merge_args == (MARG1_GBL | MARG2_LCL)) ||
		(merge_args == (MARG1_GBL | MARG2_GBL)));
	assert(!lvzwrite_block || 0 == lvzwrite_block->curr_subsc);
	/* Need to protect value from stpgcol */
	PUSH_MV_STENT(MVST_MVAL);
	value = &mv_chain->mv_st_cont.mvs_mval;
	value->mvtype = 0; /* initialize mval in the M-stack in case stp_gcol gets called before value gets initialized below */
	if (MARG2_IS_GBL(merge_args))
	{	/* Need to protect mkey returned from gvcst_queryget from stpgcol */
		PUSH_MV_STENT(MVST_MVAL);
		mkey = &mv_chain->mv_st_cont.mvs_mval;
		mkey->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before mkey gets initialized below */
		gvname_env_restore(mglvnp->gblp[IND2]);
		/* now $DATA will be done for gvn2. op_gvdata input parameters are set in the form of some GBLREF */
		op_gvdata(value);
		dollardata_src = MV_FORCE_INT(value);
		if (0 == dollardata_src)
		{	/* nothing in source global */
			UNDO_ACTIVE_LV;
			POP_MV_STENT();	/* value */
			POP_MV_STENT(); /* mkey */
			if (MARG1_IS_GBL(merge_args))
				gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
			merge_args = 0;	/* Must reset to zero to reuse the Global */
			return;
		}
		if (NULL == TREF(gv_mergekey2))
		{	/* We need to initialize gvn2 (right hand side). */
			GVKEY_INIT(TREF(gv_mergekey2), DBKEYSIZE(MAX_KEY_SZ));
		}
		org_glvn1_keysz = mglvnp->gblp[IND1]->s_gv_currkey->end + 1;
		org_glvn2_keysz = gv_currkey->end + 1;
		(TREF(gv_mergekey2))->end = gv_currkey->end;
		(TREF(gv_mergekey2))->prev = gv_currkey->prev;
		memcpy((TREF(gv_mergekey2))->base, gv_currkey->base, gv_currkey->end + 1);
		if (MARG1_IS_GBL(merge_args))
		{	/*==================== MERGE ^gvn1=^gvn2 =====================*/
			if (mglvnp->gblp[IND2]->s_gv_target->nct != mglvnp->gblp[IND1]->s_gv_target->nct)
				rts_error(VARLSTCNT(1) ERR_NCTCOLLDIFF);
			/* if self merge then NOOP*/
			if (!merge_desc_check()) /* will not proceed if one is descendant of another */
			{
				gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
				POP_MV_STENT();	/* value */
				merge_args = 0;	/* Must reset to zero to reuse the Global */
				return;
			}
			nullcoll_src = mglvnp->gblp[IND2]->s_gv_cur_region->std_null_coll;
			nullcoll_dst = mglvnp->gblp[IND1]->s_gv_cur_region->std_null_coll;
			if (1 == dollardata_src || 11 == dollardata_src)
			{
				found = op_gvget(value);  /* value of ^glvn2 */
				if (found)
				{	/* SET ^gvn1=^gvn2 */
					gvname_env_restore(mglvnp->gblp[IND1]);
					op_gvput(value);
					/* Note: If ^gvn1's null_sub=ALLOWEXISTING and say ^gvn1("")=^gvn,
					 * this will give NULL_SUBC error
					 */
				}
			}
			check_for_null_subs = (NEVER != mglvnp->gblp[IND2]->s_gv_cur_region->null_subs) &&
				(ALWAYS != mglvnp->gblp[IND1]->s_gv_cur_region->null_subs);
			/* Traverse descendant of ^gvn2 and copy into ^gvn1 */
			for (; ;)
			{
				if (outofband)
				{
					gvname_env_restore(mglvnp->gblp[IND1]); /* naked indicator is restored into gv_currkey */
					outofband_action(FALSE);
				}
				/* Restore last key under ^gvn2 we worked */
				gvname_env_restore(mglvnp->gblp[IND2]);
				assert(0 == gv_currkey->base[gv_currkey->end - 1] && 0 == gv_currkey->base[gv_currkey->end]);
				/* following is an attempt to find immidiate right sibling */
				gv_currkey->base[gv_currkey->end] = 1;
				gv_currkey->base[gv_currkey->end + 1] = 0;
				gv_currkey->base[gv_currkey->end + 2] = 0;
				gv_currkey->end += 2;
				/* Do atomic $QUERY and $GET of current glvn2:
				 * mkey is a mstr which contains $QUERY result in database format (So no conversion necessary)
				 * value is a mstr which contains $GET result
				 */
				if (!op_gvqueryget(mkey, value))
					break;
				assert(MV_IS_STRING(mkey));
				if (mkey->str.len < org_glvn2_keysz)
					break;
				if (0 != *((unsigned char *)mkey->str.addr + (TREF(gv_mergekey2))->end - 1) ||
					memcmp(mkey->str.addr, (TREF(gv_mergekey2))->base, (TREF(gv_mergekey2))->end - 1))
					break; 					/* mkey is not under the sub-tree */
				delta2 = mkey->str.len - org_glvn2_keysz; 	/* length increase of source key */
				assert (0 < delta2);
				/* Save the new source key for next iteration */
				memcpy(mglvnp->gblp[IND2]->s_gv_currkey->base + org_glvn2_keysz - 2,
					mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2);
				mglvnp->gblp[IND2]->s_gv_currkey->end = mkey->str.len - 1;
				/* Create the destination key for this iteration (under ^glvn1) */
				gvname_env_restore(mglvnp->gblp[IND1]);
				if (gv_cur_region->max_key_size < org_glvn1_keysz + delta2)
					ISSUE_GVSUBOFLOW_ERROR(gv_currkey);
				assert(gv_currkey->end == org_glvn1_keysz - 1);
				memcpy(gv_currkey->base + org_glvn1_keysz - 2,
					mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2);
				gv_currkey->end = org_glvn1_keysz + delta2 - 1;
				if (nullcoll_src != nullcoll_dst)
				{
					if (0 == nullcoll_dst)
					{	/* Standard to GTM null subscript conversion*/
						STD2GTMNULLCOLL((unsigned char *)gv_currkey->base + org_glvn1_keysz - 1,
								delta2 - 1);
					} else
					{	/*  GTM to standard null subscript conversion */
						GTM2STDNULLCOLL((unsigned char *)gv_currkey->base + org_glvn1_keysz - 1,
								delta2 - 1);
					}
				}
				/* check null subscripts in destination key, note that we have already restored, destination global
				 * and curresponding region, key information
				 */
				if (check_for_null_subs)
				{
					ptr2 = gv_currkey->base + gv_currkey->end - 1;
					for (ptr = gv_currkey->base + org_glvn1_keysz - 2; ptr < ptr2; )
					{
						if (KEY_DELIMITER == *ptr++ && KEY_DELIMITER == *(ptr + 1) &&
							(0 == gv_cur_region->std_null_coll ? (STR_SUB_PREFIX == *ptr) :
							(SUBSCRIPT_STDCOL_NULL == *ptr)))
							/* Note: For sgnl_gvnulsubsc/rts_error
							 * 	 we do not restore proper naked indicator.
							 * The standard states that the effect of a MERGE command
							 * on the naked indicator is that the naked indicator will be changed
							 * as if a specific SET command would have been executed.
							 * The standard also states that the effect on the naked indicator
							 * will only take be visible after the MERGE command has completed.
							 * So, if there is an error during the execution of a MERGE command,
							 * the standard allows the naked indicator to reflect any intermediate
							 * state. This provision was made intentionally, otherwise it would
							 * have become nearly impossible to create a fully standard
							 * implementation. : From Ed de Moel : 2/1/2
							 */
							sgnl_gvnulsubsc();
					}
				}
				/* Now put value of ^glvn2 descendant into corresponding descendant under ^glvn1 */
				op_gvput(value);
			}
			gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
		} else
		{	/*==================== MERGE lvn1=^gvn2 =====================*/
			assert(MARG1_IS_LCL(merge_args));
			assert(mglvnp->lclp[IND1]);
			/* Need to protect subsc created from global variable subscripts from stpgcol */
			PUSH_MV_STENT(MVST_MVAL);
			subsc = &mv_chain->mv_st_cont.mvs_mval;
			/* Restore ^gvn2 we will work */
			gvname_env_save(mglvnp->gblp[IND2]);
			if (1 == dollardata_src || 11 == dollardata_src)
			{	/* SET lvn1=^gvn2 */
				found = op_gvget(value);
				if (found)
					mglvnp->lclp[IND1]->v = *value;
			}
			for (; ;)
			{
				if (outofband)
				{
					gvname_env_restore(mglvnp->gblp[IND2]);	 /* naked indicator is restored into gv_currkey */
					outofband_action(FALSE);
				}
				assert(0 == gv_currkey->base[gv_currkey->end - 1] && 0 == gv_currkey->base[gv_currkey->end]);
				/* following is an attempt to find immidiate right sibling */
				gv_currkey->base[gv_currkey->end] = 1;
				gv_currkey->base[gv_currkey->end + 1] = 0;
				gv_currkey->base[gv_currkey->end + 2] = 0;
				gv_currkey->end += 2;
				/* Do $QUERY and $GET of current glvn2. Result will be in mkey and value respectively.
				 * mkey->str contains data as database format. So no conversion necessary
				 */
				if (!op_gvqueryget(mkey, value))
					break;
				if (mkey->str.len < (TREF(gv_mergekey2))->end + 1)
					break;
				ptr = (unsigned char *)mkey->str.addr +  (TREF(gv_mergekey2))->end - 1;
				if (0 != *ptr || memcmp(mkey->str.addr, (TREF(gv_mergekey2))->base, (TREF(gv_mergekey2))->end - 1))
					break;
				assert(MV_IS_STRING(mkey));
				delta2 = mkey->str.len - org_glvn2_keysz; /* length increase of key */
				assert (0 < delta2);
				/* Create next key for ^glvn2 */
				memcpy(gv_currkey->base + org_glvn2_keysz - 2, mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2);
				gv_currkey->end = mkey->str.len - 1;
				/* Now add subscripts to create the entire key */
				dst_lv =  mglvnp->lclp[IND1];
				is_base_var = LV_IS_BASE_VAR(dst_lv);
				ptr = (unsigned char *)gv_currkey->base + org_glvn2_keysz - 1;
				assert(*ptr);
				do
				{
					LV_SBS_DEPTH(dst_lv, is_base_var, sbs_depth);
					if (MAX_LVSUBSCRIPTS <= sbs_depth)
						rts_error(VARLSTCNT(3) ERR_MERGEINCOMPL, 0, ERR_MAXNRSUBSCRIPTS);
					ptr2 = gvsub2str(ptr, buff, FALSE);
					subsc->mvtype = MV_STR;
					subsc->str.addr = (char *)buff;
					subsc->str.len = INTCAST(ptr2 - buff);
					s2pool(&subsc->str);
					dst_lv = op_putindx(VARLSTCNT(2) dst_lv, subsc);
					while (*ptr++);	/* skip to start of next subscript */
					is_base_var = FALSE;
				} while (*ptr);
				/* We created the key. Pre-process the node in case a container is being replaced,
				 * then assign the value directly. Note there is no need to worry about MV_ALIASCONT
				 * propagation since the source in this case is a global var.
				 */
				DECR_AC_REF(dst_lv, TRUE);
				dst_lv->v = *value;
			}
			gvname_env_restore(mglvnp->gblp[IND2]);	 /* naked indicator is restored into gv_currkey */
			POP_MV_STENT();     /* subsc */
		}
		POP_MV_STENT();     /* mkey */
	} else
	{	/* source is local */
		op_fndata(mglvnp->lclp[IND2], value);
		dollardata_src = MV_FORCE_INT(value);
		if (0 == dollardata_src)
		{
			UNDO_ACTIVE_LV;
			POP_MV_STENT();	/* value */
			if (MARG1_IS_GBL(merge_args))
				gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
			merge_args = 0;	/* Must reset to zero to reuse the Global */
			return;
		}
		/* not memsetting output to 0 here can cause garbage value of output.out_var.lv.child which in turn can
		 * cause a premature return from lvzwr_var resulting in op_merge() returning without having done the merge.
		 */
		memset(&output, 0, SIZEOF(output));
		if (MARG1_IS_LCL(merge_args))
		{	/*==================== MERGE lvn1=lvn2 =====================*/
			assert(mglvnp->lclp[IND1]);
			/* if self merge then NOOP */
			if (!merge_desc_check()) /* will not proceed if one is descendant of another */
			{
				POP_MV_STENT();	/* value */
				merge_args = 0;	/* Must reset to zero to reuse the Global */
				return;
			}
			output.buff = (char *)buff;
			output.ptr = output.buff;
			output.out_var.lv.lvar = mglvnp->lclp[IND1];
			zwr_output = &output;
			lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
			lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
			lvzwr_var(mglvnp->lclp[IND2], 0);
			/* assert that destination got all data of the source and its descendants */
			DEBUG_ONLY(op_fndata(mglvnp->lclp[IND1], value));
			DEBUG_ONLY(dollardata_dst = MV_FORCE_INT(value));
			assert((dollardata_src & dollardata_dst) == dollardata_src);
		} else
		{	/*==================== MERGE ^gvn1=lvn2 =====================*/
			assert(MARG1_IS_GBL(merge_args) && MARG2_IS_LCL(merge_args));
			gvname_env_save(mglvnp->gblp[IND1]);
			output.buff = (char *)buff;
			output.ptr = output.buff;
			output.out_var.gv.end = gv_currkey->end;
			output.out_var.gv.prev = gv_currkey->prev;
			zwr_output = &output;
			lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
			lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
			lvzwr_var(mglvnp->lclp[IND2], 0);
			gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
		}
	}
	POP_MV_STENT();	/* value */
	merge_args = 0;	/* Must reset to zero to reuse the Global */
}