135 lines
4.2 KiB
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;
|
|
}
|
|
}
|
|
}
|