fis-gtm/sr_port/op_fnorder.c

135 lines
4.2 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 "lv_val.h"
#include "collseq.h"
#include "stringpool.h"
#include "do_xform.h"
#include "numcmp.h"
#include "mvalconv.h"
#include "promodemo.h" /* for "demote" prototype used in LV_NODE_GET_KEY */
#define MINUS_ONE -MV_BIAS
error_def(ERR_NUMOFLOW);
void op_fnorder(lv_val *src, mval *key, mval *dst)
{
mval tmp_sbs;
int length;
boolean_t is_canonical, is_fnnext, get_first;
lvTree *lvt;
lvTreeNode *node;
uint4 mvt; /* Local copy of mvtype, bit ands use a int4, so do conversion once */
mstr *str;
int4 intval;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
is_fnnext = TREF(in_op_fnnext);
TREF(in_op_fnnext) = FALSE;
if (src && (lvt = LV_GET_CHILD(src))) /* caution: assignment */
{
MV_FORCE_DEFINED(key);
/* If last subscript is null, $ORDER returns the first subscript in that level.
* With the obsoleted $NEXT function, a subscript of -1 also triggers the same behavior.
*/
get_first = FALSE;
if (MV_IS_STRING(key) && (0 == key->str.len))
get_first = TRUE;
else if (is_fnnext)
{
mvt = key->mvtype;
if (!(mvt & (MV_NM | MV_NUM_APPROX)))
{ /* Not currently in numeric form. Is it cannonical? */
if (val_iscan(key))
{ /* Yes, convert it to numeric */
(void)s2n(key);
mvt = key->mvtype;
if (!(mvt & MV_NM))
rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
} else /* No, not numeric. Note the fact for future reference */
mvt = key->mvtype |= MV_NUM_APPROX;
}
if (MV_IS_TRUEINT(key, &intval) && (MINUS_ONE == key->m[1]))
get_first = TRUE;
}
if (get_first)
node = lvAvlTreeFirst(lvt);
else
{
is_canonical = MV_IS_CANONICAL(key);
if (!is_canonical)
{
assert(!TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype));
if (TREF(local_collseq))
{
ALLOC_XFORM_BUFF(key->str.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), XFORM, &key->str, &tmp_sbs.str, &length);
tmp_sbs.str.len = length;
s2pool(&(tmp_sbs.str));
key = &tmp_sbs;
}
} else
{ /* Need to set canonical bit before calling tree search functions.
* But input mval could be read-only so cannot modify that even if temporarily.
* So take a copy of the mval and modify that instead.
*/
tmp_sbs = *key;
key = &tmp_sbs;
MV_FORCE_NUM(key);
TREE_KEY_SUBSCR_SET_MV_CANONICAL_BIT(key); /* used by the lvTreeKeyNext function */
}
node = lvAvlTreeKeyNext(lvt, key);
}
/* If STDNULLCOLL, skip to the next subscript should the current subscript be "" */
if (TREF(local_collseq_stdnull) && (NULL != node) && LV_NODE_KEY_IS_NULL_SUBS(node))
{
assert(LVNULLSUBS_OK == TREF(lv_null_subs));
node = lvAvlTreeNext(node);
}
} else
node = NULL;
if (NULL == node)
{
if (!is_fnnext)
{
dst->mvtype = MV_STR;
dst->str.len = 0;
} else
MV_FORCE_MVAL(dst, -1);
} else
{
LV_NODE_GET_KEY(node, dst); /* Get node key into "dst" depending on the structure type of "node" */
/* Code outside lv_tree.c does not currently know to make use of MV_CANONICAL bit so reset it
* until the entire codebase gets fixed to maintain MV_CANONICAL bit accurately at which point,
* this RESET can be removed */
TREE_KEY_SUBSCR_RESET_MV_CANONICAL_BIT(dst);
if (TREF(local_collseq) && MV_IS_STRING(dst))
{
ALLOC_XFORM_BUFF(dst->str.len);
assert(NULL != TREF(lcl_coll_xform_buff));
tmp_sbs.str.addr = TREF(lcl_coll_xform_buff);
tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz);
do_xform(TREF(local_collseq), XBACK, &dst->str, &tmp_sbs.str, &length);
tmp_sbs.str.len = length;
s2pool(&(tmp_sbs.str));
dst->str = tmp_sbs.str;
}
}
}