312 lines
12 KiB
C
312 lines
12 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_stdio.h"
|
|
|
|
#include "lv_val.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "zwrite.h"
|
|
#include "mlkdef.h"
|
|
#include "zshow.h"
|
|
#include "collseq.h"
|
|
#include "stringpool.h"
|
|
#include "op.h"
|
|
#include "outofband.h"
|
|
#include "do_xform.h"
|
|
#include "numcmp.h"
|
|
#include "patcode.h"
|
|
#include "mvalconv.h"
|
|
#include "follow.h"
|
|
#include "gtm_string.h"
|
|
#include "alias.h"
|
|
#include "promodemo.h" /* for "demote" prototype used in LV_NODE_GET_KEY */
|
|
|
|
#define eb_less(u, v) (numcmp(u, v) < 0)
|
|
|
|
#define COMMON_STR_PROCESSING(NODE) \
|
|
{ \
|
|
mstr key_mstr; \
|
|
mval tmp_sbs; \
|
|
\
|
|
assert(MV_STR & mv.mvtype); \
|
|
if (TREF(local_collseq)) \
|
|
{ \
|
|
key_mstr = mv.str; \
|
|
mv.str.len = 0; /* protect from "stp_gcol", if zwr_sub->subsc_list[n].actual points to mv */ \
|
|
ALLOC_XFORM_BUFF(key_mstr.len); \
|
|
tmp_sbs.mvtype = MV_STR; \
|
|
tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz); \
|
|
assert(NULL != TREF(lcl_coll_xform_buff)); \
|
|
tmp_sbs.str.addr = TREF(lcl_coll_xform_buff); \
|
|
do_xform(TREF(local_collseq), XBACK, &key_mstr, &tmp_sbs.str, &length); \
|
|
tmp_sbs.str.len = length; \
|
|
s2pool(&(tmp_sbs.str)); \
|
|
mv.str = tmp_sbs.str; \
|
|
} \
|
|
do_lev = TRUE; \
|
|
if (n < lvzwrite_block->subsc_count) \
|
|
{ \
|
|
if (zwr_sub->subsc_list[n].subsc_type == ZWRITE_PATTERN) \
|
|
{ \
|
|
if (!do_pattern(&mv, zwr_sub->subsc_list[n].first)) \
|
|
do_lev = FALSE; \
|
|
} else if (zwr_sub->subsc_list[n].subsc_type != ZWRITE_ALL) \
|
|
{ \
|
|
if (zwr_sub->subsc_list[n].first) \
|
|
{ \
|
|
if (!MV_IS_CANONICAL(zwr_sub->subsc_list[n].first) && \
|
|
(!follow(&mv, zwr_sub->subsc_list[n].first) && \
|
|
(mv.str.len != zwr_sub->subsc_list[n].first->str.len || \
|
|
memcmp(mv.str.addr, zwr_sub->subsc_list[n].first->str.addr, \
|
|
mv.str.len)))) \
|
|
do_lev = FALSE; \
|
|
} \
|
|
if (do_lev && zwr_sub->subsc_list[n].second) \
|
|
{ \
|
|
if (MV_IS_CANONICAL(zwr_sub->subsc_list[n].second) || \
|
|
(!follow(zwr_sub->subsc_list[n].second, &mv) && \
|
|
(mv.str.len != zwr_sub->subsc_list[n].second->str.len || \
|
|
memcmp(mv.str.addr, \
|
|
zwr_sub->subsc_list[n].second->str.addr, \
|
|
mv.str.len)))) \
|
|
do_lev = FALSE; \
|
|
} \
|
|
} \
|
|
} \
|
|
if (do_lev) \
|
|
lvzwr_var((lv_val *)NODE, n + 1); \
|
|
}
|
|
|
|
#define COMMON_NUMERIC_PROCESSING(NODE) \
|
|
{ \
|
|
do_lev = TRUE; \
|
|
if (n < lvzwrite_block->subsc_count) \
|
|
{ \
|
|
if (zwr_sub->subsc_list[n].subsc_type == ZWRITE_PATTERN) \
|
|
{ \
|
|
if (!do_pattern(&mv, zwr_sub->subsc_list[n].first)) \
|
|
do_lev = FALSE; \
|
|
} else if (zwr_sub->subsc_list[n].subsc_type != ZWRITE_ALL) \
|
|
{ \
|
|
if (zwr_sub->subsc_list[n].first) \
|
|
{ \
|
|
if (!MV_IS_CANONICAL(zwr_sub->subsc_list[n].first) \
|
|
|| eb_less(&mv, zwr_sub->subsc_list[n].first)) \
|
|
do_lev = FALSE; \
|
|
} \
|
|
if (do_lev && zwr_sub->subsc_list[n].second) \
|
|
{ \
|
|
if (MV_IS_CANONICAL(zwr_sub->subsc_list[n].second) \
|
|
&& eb_less(zwr_sub->subsc_list[n].second, &mv)) \
|
|
do_lev = FALSE; \
|
|
} \
|
|
} \
|
|
} \
|
|
if (do_lev) \
|
|
lvzwr_var((lv_val *)NODE, n + 1); \
|
|
}
|
|
|
|
GBLREF lvzwrite_datablk *lvzwrite_block;
|
|
GBLREF int4 outofband;
|
|
GBLREF zshow_out *zwr_output;
|
|
GBLREF int merge_args;
|
|
GBLREF zwr_hash_table *zwrhtab; /* How we track aliases during zwrites */
|
|
|
|
LITREF mval literal_null;
|
|
|
|
error_def(ERR_UNDEF);
|
|
|
|
/* lv subscript usage notes:
|
|
* 1. The sub field in lvzwrite_datablk is an array allocated at MAX_LVSUBSCRIPTS.
|
|
* 2. The subscripts that appear at any given time are those for the current node being processed.
|
|
* 3. Nodes are setup by lvzwr_arg().
|
|
*
|
|
* Example - take the following nodes:
|
|
* A(1,1)=10
|
|
* A(1,2)=20
|
|
*
|
|
* The simplified processing that occurs is as follows:
|
|
* 1. lvzwr_fini() sets curr_name which is the base var name (A)
|
|
* 2. First level lvzwr_var is called with level (aka n) == 0
|
|
* 3. Since A has no value, nothing is printed. Notices that there are children so lvzwr_arg()
|
|
* is called recursively with level 1.
|
|
* 4. Sets up the level 1 subscript (key = 1).
|
|
* 5. Since A(1) has no value, nothing is printed. Notices that there are children so lvzwr_arg()
|
|
* is called recursively withe level 2.
|
|
* 6. Sets up the level 2 subscript (key = 1).
|
|
* 7. A(1,1) does have a value so lvzwr_out() is called to print the current key (from these
|
|
* subscripts) and its value.
|
|
* 8. No more subscripts at this level so pops back to level 1.
|
|
* 9. There is another child at this level so calls lvzwr_arg() recursively with level 2.
|
|
* 10. Replaces the level 2 subscript with the new key value (key = 2).
|
|
* 11. A(1,2) does have a value so lvzwr_out() is called to print the current key.
|
|
* 12. no more children at any level so everything pops back.
|
|
*/
|
|
void lvzwr_var(lv_val *lv, int4 n)
|
|
{
|
|
mval mv;
|
|
int length;
|
|
lv_val *var;
|
|
char *top;
|
|
int4 i;
|
|
boolean_t do_lev, verify_hash_add, htent_added, value_printed_pending;
|
|
zwr_sub_lst *zwr_sub;
|
|
ht_ent_addr *tabent_addr;
|
|
zwr_alias_var *zav, *newzav;
|
|
lvTree *lvt;
|
|
lvTreeNode *node, *nullsubsnode, *parent;
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
assert(lvzwrite_block);
|
|
if (lv == zwr_output->out_var.lv.child)
|
|
return;
|
|
if (outofband)
|
|
{
|
|
lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
|
|
outofband_action(FALSE);
|
|
}
|
|
lvzwrite_block->curr_subsc = n;
|
|
zwr_sub = (zwr_sub_lst *)lvzwrite_block->sub;
|
|
zwr_sub->subsc_list[n].actual = (mval *)NULL;
|
|
/* Before we process this var, there are some special cases to check for first when
|
|
* this is a base var (0 == lvzwrite_block->subsc_count) and the var is an alias.
|
|
*
|
|
* 1. Check if we have seen it before (the lvval is in the zwr_alias_var hash table), then we
|
|
* need to process this var with lvzwr_out NOW and we will only be processing the base
|
|
* var, not any of the subscripts. This is because all those subscripts (and the value
|
|
* of the base var itself) have been dealt with previously when we first saw this
|
|
* lvval. So in that case, call lvzwr_out() to output the association after which we are
|
|
* done with this var.
|
|
* 2. If we haven't seen it before, set a flag so we verify if the base var gets processed by
|
|
* lvzwr_out or not (i.e. whether it has a value and the "subscript" or lack there of is
|
|
* either wildcarded or whatever so that it actually gets dumped by lvzwr_out (see conditions
|
|
* below). If not, then *we* need to add the lvval to the hash table to signify we have seen
|
|
* it before so the proper associations to this alias var can be printed at a later time
|
|
* when/if they are encountered.
|
|
*/
|
|
verify_hash_add = FALSE; /* By default we don't need to verify add */
|
|
value_printed_pending = FALSE; /* Force the "value_printed" flag on if TRUE */
|
|
zav = NULL;
|
|
if (!merge_args && LV_IS_BASE_VAR(lv) && IS_ALIASLV(lv))
|
|
{
|
|
assert(0 == n); /* Verify base var lv_val */
|
|
if (tabent_addr = (ht_ent_addr *)lookup_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lv))
|
|
{ /* We've seen it before but check if it was actually printed at that point */
|
|
zav = (zwr_alias_var *)tabent_addr->value;
|
|
assert(zav);
|
|
if (zav->value_printed)
|
|
{
|
|
lvzwr_out(lv);
|
|
lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
|
|
return;
|
|
} else
|
|
value_printed_pending = TRUE; /* We will set value_printed flag true later */
|
|
} else
|
|
verify_hash_add = TRUE;
|
|
}
|
|
if ((0 == lvzwrite_block->subsc_count) && (0 == n))
|
|
zwr_sub->subsc_list[n].subsc_type = ZWRITE_ASTERISK;
|
|
if (LV_IS_VAL_DEFINED(lv)
|
|
&& (!lvzwrite_block->subsc_count || ((0 == n) && ZWRITE_ASTERISK == zwr_sub->subsc_list[n].subsc_type)
|
|
|| ((0 != n) && !(lvzwrite_block->mask >> n))))
|
|
{ /* Print value for *this* node */
|
|
lvzwr_out(lv);
|
|
}
|
|
if (verify_hash_add && !lvzwrite_block->zav_added)
|
|
{ /* lvzwr_out processing didn't add a zav for this var. Take care of that now so we
|
|
* recognize it as a "dealt with" alias when/if it is encountered later.
|
|
*/
|
|
newzav = als_getzavslot();
|
|
newzav->zwr_var = *lvzwrite_block->curr_name;
|
|
newzav->value_printed = TRUE;
|
|
htent_added = add_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lv, newzav, &tabent_addr);
|
|
assert(htent_added);
|
|
}
|
|
/* If we processed a base var above to print an alias association but it hadn't been printed yet,
|
|
* we had to wait until after lvzwr_out() was called before we could set the flag that indicated
|
|
* the printing had occurred. Do that now. Note that it is only when this flag is set we are
|
|
* certain to have a good value in zav.
|
|
*/
|
|
if (value_printed_pending)
|
|
{
|
|
assert(zav);
|
|
zav->value_printed = TRUE;
|
|
}
|
|
if (lvzwrite_block->subsc_count && (n >= lvzwrite_block->subsc_count)
|
|
&& (ZWRITE_ASTERISK != zwr_sub->subsc_list[lvzwrite_block->subsc_count - 1].subsc_type))
|
|
return;
|
|
|
|
if (n < lvzwrite_block->subsc_count && ZWRITE_VAL == zwr_sub->subsc_list[n].subsc_type)
|
|
{
|
|
var = op_srchindx(VARLSTCNT(2) lv, zwr_sub->subsc_list[n].first);
|
|
zwr_sub->subsc_list[n].actual = zwr_sub->subsc_list[n].first;
|
|
if (var && (LV_IS_VAL_DEFINED(var) || n < lvzwrite_block->subsc_count -1))
|
|
{
|
|
lvzwr_var(var, n + 1);
|
|
zwr_sub->subsc_list[n].actual = (mval *)NULL;
|
|
lvzwrite_block->curr_subsc = n;
|
|
} else
|
|
{
|
|
if (lvzwrite_block->fixed)
|
|
{
|
|
unsigned char buff[512], *end;
|
|
|
|
lvzwrite_block->curr_subsc++;
|
|
end = lvzwr_key(buff, SIZEOF(buff));
|
|
zwr_sub->subsc_list[n].actual = (mval *)NULL;
|
|
lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
|
|
rts_error(VARLSTCNT(4) ERR_UNDEF, 2, end - buff, buff);
|
|
}
|
|
}
|
|
} else if (lvt = LV_GET_CHILD(lv))
|
|
{ /* If node has children, process them now */
|
|
zwr_sub->subsc_list[n].actual = &mv;
|
|
/* In case of standard null collation, first process null subscript if it exists */
|
|
if (TREF(local_collseq_stdnull))
|
|
{
|
|
nullsubsnode = lvAvlTreeLookupStr(lvt, (treeKeySubscr *)&literal_null, &parent);
|
|
if (NULL != nullsubsnode)
|
|
{
|
|
assert(MVTYPE_IS_STRING(nullsubsnode->key_mvtype) && !nullsubsnode->key_len);
|
|
/* Process null subscript first */
|
|
LV_STR_NODE_GET_KEY(nullsubsnode, &mv); /* Get node key into "mv" */
|
|
COMMON_STR_PROCESSING(nullsubsnode);
|
|
}
|
|
} else
|
|
nullsubsnode = NULL;
|
|
for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node))
|
|
{
|
|
if (node == nullsubsnode)
|
|
{
|
|
assert(TREF(local_collseq_stdnull));
|
|
continue; /* skip null subscript as it has already been processed */
|
|
}
|
|
LV_NODE_GET_KEY(node, &mv); /* Get node key into "mv" depending on the structure type of "node" */
|
|
if (!MVTYPE_IS_STRING(mv.mvtype))
|
|
{ /* "node" is of type "lvTreeNodeNum *" */
|
|
COMMON_NUMERIC_PROCESSING(node);
|
|
} else
|
|
{ /* "node" is of type "lvTreeNode *" */
|
|
COMMON_STR_PROCESSING(node);
|
|
}
|
|
}
|
|
zwr_sub->subsc_list[n].actual = (mval *)NULL;
|
|
lvzwrite_block->curr_subsc = n;
|
|
}
|
|
}
|