fis-gtm/sr_port/lvzwr_var.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;
}
}