fis-gtm/sr_port/op_gvorder.c

230 lines
7.6 KiB
C

/****************************************************************
* *
* Copyright 2001, 2012 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_string.h"
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "stringpool.h"
#include "op.h"
#include "gvcst_protos.h" /* for gvcst_order,gvcst_data prototype */
#include "change_reg.h"
#include "gvsub2str.h"
#include "gvcmx.h"
#include "gvusr.h"
GBLREF gv_namehead *gv_target;
GBLREF gv_key *gv_currkey;
GBLREF gv_key *gv_altkey;
GBLREF gd_region *gv_cur_region;
GBLREF gd_addr *gd_header;
GBLREF gd_binding *gd_map;
GBLREF gd_binding *gd_map_top;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF spdesc stringpool;
/* op_zprevious should generally be maintained in parallel */
void op_gvorder (mval *v)
{
int4 n;
gd_binding *map;
mstr name;
enum db_acc_method acc_meth;
boolean_t found, ok_to_change_currkey;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
acc_meth = gv_cur_region->dyn.addr->acc_meth;
/* Modify gv_currkey such that a gvcst_search of the resulting gv_currkey will find the next available subscript.
* But in case of dba_usr (the custom implementation of $ORDER which is overloaded for DDP 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.
*/
ok_to_change_currkey = (dba_usr != acc_meth);
if (ok_to_change_currkey)
{ /* Modify gv_currkey to reflect the next possible key value in collating order */
if (!TREF(gv_last_subsc_null) || gv_cur_region->std_null_coll)
{
*(&gv_currkey->base[0] + gv_currkey->end - 1) = 1;
*(&gv_currkey->base[0] + gv_currkey->end + 1) = 0;
gv_currkey->end += 1;
} else
{
assert(STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]);
assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
assert(2 == (gv_currkey->end - gv_currkey->prev));
*(&gv_currkey->base[0] + gv_currkey->prev) = 01;
}
}
if (gv_currkey->prev)
{
if (acc_meth == dba_bg || acc_meth == dba_mm)
{
if (gv_target->root == 0) /* global does not exist */
found = FALSE;
else
found = gvcst_order();
} else if (acc_meth == dba_cm)
found = gvcmx_order();
else
found = gvusr_order();
v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by (BYPASSOK)
* this to-be-overwritten mval */
if (found)
{
gv_altkey->prev = gv_currkey->prev;
if (!(IS_STP_SPACE_AVAILABLE(MAX_KEY_SZ)))
{
if (*(&gv_altkey->base[0] + gv_altkey->prev) != 0xFF)
n = MAX_FORM_NUM_SUBLEN;
else
{
n = gv_altkey->end - gv_altkey->prev;
assert (n > 0);
}
ENSURE_STP_FREE_SPACE(n);
}
v->str.addr = (char *)stringpool.free;
stringpool.free = gvsub2str (&gv_altkey->base[0] + gv_altkey->prev, stringpool.free, 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 (ok_to_change_currkey)
{ /* Restore gv_currkey to what it was at function entry time */
if (!TREF(gv_last_subsc_null) || gv_cur_region->std_null_coll)
{
assert(1 == gv_currkey->base[gv_currkey->end - 2]);
assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end-1]);
assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
gv_currkey->base[gv_currkey->end - 2] = KEY_DELIMITER;
gv_currkey->end--;
} else
{
assert(01 == gv_currkey->base[gv_currkey->prev]);
gv_currkey->base[gv_currkey->prev] = STR_SUB_PREFIX;
}
}
} else /* the following section is for $O(^gname) */
{
assert (2 < gv_currkey->end);
assert (gv_currkey->end < (MAX_MIDENT_LEN + 3)); /* until names are not in midents */
map = gd_map + 1;
while (map < gd_map_top &&
(memcmp(gv_currkey->base, map->name,
gv_currkey->end == (MAX_MIDENT_LEN + 2) ? MAX_MIDENT_LEN : gv_currkey->end - 1) >= 0))
{
map++;
}
for (; map < gd_map_top; ++map)
{
gv_cur_region = map->reg.addr;
if (!gv_cur_region->open)
gv_init_reg(gv_cur_region);
change_reg();
acc_meth = gv_cur_region->dyn.addr->acc_meth;
for (; ;) /* search region, entries in directory tree could be empty */
{
if (acc_meth == dba_bg || acc_meth == dba_mm)
{
gv_target = cs_addrs->dir_tree;
found = gvcst_order ();
} else if (acc_meth == dba_cm)
found = gvcmx_order ();
else
found = gvusr_order();
if (!found)
break;
assert (1 < gv_altkey->end);
assert (gv_altkey->end < (MAX_MIDENT_LEN + 2)); /* until names are not in midents */
if (memcmp(gv_altkey->base, map->name, gv_altkey->end - 1) > 0)
{
found = FALSE;
break;
}
name.addr = (char *)&gv_altkey->base[0];
name.len = gv_altkey->end - 1;
if (acc_meth == dba_cm)
break;
GV_BIND_NAME_AND_ROOT_SEARCH(gd_header, &name);
if (gv_cur_region != map->reg.addr)
{
found = FALSE;
break;
}
/* For effective truncates, we want to be able to move empty data blocks in reorg */
if ((gv_target->root != 0) && (TREF(want_empty_gvts) || gvcst_data() != 0))
break;
*(&gv_currkey->base[0] + gv_currkey->end - 1) = 1;
*(&gv_currkey->base[0] + gv_currkey->end + 1) = 0;
gv_currkey->end += 1;
}
if (found)
break;
else
{
assert(SIZEOF(map->name) == SIZEOF(mident_fixed));
gv_currkey->end = mid_len((mident_fixed *)map->name);
assert(gv_currkey->end <= MAX_MIDENT_LEN);
memcpy(&gv_currkey->base[0], map->name, gv_currkey->end);
gv_currkey->base[ gv_currkey->end - 1 ] -= 1;
gv_currkey->base[ gv_currkey->end ] = 0xFF; /* back off 1 spot from map */
gv_currkey->base[ gv_currkey->end + 1] = 0;
gv_currkey->base[ gv_currkey->end + 2] = 0;
gv_currkey->end += 2;
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] = 0;
v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by (BYPASSOK)
* this to-be-overwritten mval */
if (found)
{
if (!IS_STP_SPACE_AVAILABLE(name.len + 1))
{
v->str.len = 0; /* so stp_gcol ignores otherwise incompletely setup mval (BYPASSOK) */
INVOKE_STP_GCOL(name.len + 1);
}
#ifdef mips
/* the following line works around a tandem compiler bug. */
v->str.addr = (char *)0;
#endif
v->str.addr = (char *)stringpool.free;
*stringpool.free++ = '^';
memcpy (stringpool.free, name.addr, name.len);
stringpool.free += name.len;
v->str.len = 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 */
}
return;
}