230 lines
7.6 KiB
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;
|
|
}
|