fis-gtm/sr_unix/bin_load.c

822 lines
28 KiB
C

/****************************************************************
* *
* Copyright 2001, 2013 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 "gtm_ctype.h"
#include "gtm_stdlib.h"
#include "stringpool.h"
#include "stp_parms.h"
#include "gdsroot.h"
#include "gdskill.h"
#include "gdsblk.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "muextr.h"
#include "error.h"
#include "copy.h"
#include "collseq.h"
#include "util.h"
#include "op.h"
#include "gvsub2str.h"
#include "mupip_exit.h"
#include "file_input.h"
#include "load.h"
#include "mvalconv.h"
#include "mu_gvis.h"
#include "gtmmsg.h"
#include "gtm_utf8.h"
#ifdef GTM_CRYPT
#include "io.h"
#include "gtmcrypt.h"
#endif
#include <rtnhdr.h>
#include "gv_trigger.h"
#include "gvcst_protos.h" /* for gvcst_root_search in GV_BIND_NAME_AND_ROOT_SEARCH macro */
#include "format_targ_key.h"
#include "zshow.h"
GBLREF bool mupip_DB_full;
GBLREF bool mu_ctrly_occurred;
GBLREF bool mu_ctrlc_occurred;
GBLREF bool mupip_error_occurred;
GBLREF spdesc stringpool;
GBLREF gd_addr *gd_header;
GBLREF gv_key *gv_altkey;
GBLREF gv_key *gv_currkey;
GBLREF gv_namehead *gv_target;
GBLREF int4 gv_keysize;
GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
#ifdef GTM_CRYPT
GBLREF io_pair io_curr_device;
#endif
error_def(ERR_CORRUPT);
error_def(ERR_GVIS);
error_def(ERR_TEXT);
error_def(ERR_LDBINFMT);
error_def(ERR_LOADCTRLY);
error_def(ERR_LOADEOF);
error_def(ERR_MUNOFINISH);
error_def(ERR_COLLTYPVERSION);
error_def(ERR_COLLATIONUNDEF);
error_def(ERR_OLDBINEXTRACT);
error_def(ERR_LOADINVCHSET);
error_def(ERR_LDSPANGLOINCMP);
#define BIN_PUT 0
#define BIN_BIND 1
#define ERR_COR 2
#define BIN_KILL 3
#ifdef GTM_CRYPT
# define EMPTY_GTMCRYPT_HASH16 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
# define EMPTY_GTMCRYPT_HASH32 EMPTY_GTMCRYPT_HASH16 EMPTY_GTMCRYPT_HASH16
# define EMPTY_GTMCRYPT_HASH EMPTY_GTMCRYPT_HASH32 EMPTY_GTMCRYPT_HASH32
# define GC_BIN_LOAD_ERR(GTMCRYPT_ERRNO) \
{ \
io_log_name *io_log; \
\
if (0 != GTMCRYPT_ERRNO) \
{ \
io_log = io_curr_device.in->name; \
GTMCRYPT_REPORT_ERROR(GTMCRYPT_ERRNO, gtm_putmsg, io_log->len, io_log->dollar_io); \
mupip_error_occurred = TRUE; \
if (NULL != tmp_gvkey) \
{ \
free(tmp_gvkey); \
tmp_gvkey = NULL; \
} \
return; \
} \
}
#endif
#define DEFAULT_SN_HOLD_BUFF_SIZE MAX_IO_BLOCK_SIZE
#define KILL_INCMP_SN_IF_NEEDED \
{ \
if (!sn_incmp_gbl_already_killed) \
{ \
COPY_KEY(sn_savekey, gv_currkey); \
COPY_KEY(gv_currkey, sn_gvkey); \
bin_call_db(BIN_KILL, 0, 0); \
COPY_KEY(gv_currkey, sn_savekey); \
sn_incmp_gbl_already_killed = TRUE; \
} \
}
#define DISPLAY_INCMP_SN_MSG \
{ \
file_offset = file_offset_base + ((unsigned char *)rp - ptr_base); \
if (file_offset != last_sn_error_offset) \
{ \
last_sn_error_offset = file_offset; \
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDSPANGLOINCMP); \
util_out_print("!_!_at File offset : [0x!XL]", TRUE, file_offset); \
if (sn_gvkey->end && expected_sn_chunk_number) \
{ \
sn_key_str_end = format_targ_key(&sn_key_str[0], MAX_ZWR_KEY_SZ, sn_gvkey, TRUE); \
util_out_print("!_!_Expected Spanning Global variable : !AD", TRUE, \
sn_key_str_end - &sn_key_str[0], sn_key_str); \
} \
sn_key_str_end = format_targ_key(&sn_key_str[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE); \
util_out_print("!_!_Global variable from record: !AD", TRUE, \
sn_key_str_end - &sn_key_str[0], sn_key_str); \
} \
}
#define DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK \
{ \
util_out_print("!_!_File offset : [0x!XL]", TRUE, file_offset_base + ((unsigned char *)rp - ptr_base)); \
util_out_print("!_!_Rest of Block :", TRUE); \
zwr_out_print((char *)rp, btop - (unsigned char *)rp); \
util_out_print(0, TRUE); \
}
#define DISPLAY_CURRKEY \
{ \
sn_key_str_end = format_targ_key(&sn_key_str[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE); \
util_out_print("!_!_Key: !AD", TRUE, sn_key_str_end - &sn_key_str[0], sn_key_str); \
}
#define DISPLAY_VALUE(STR) \
{ \
util_out_print(STR, TRUE); \
zwr_out_print(v.str.addr, v.str.len); \
util_out_print(0, TRUE); \
}
#define DISPLAY_PARTIAL_SN_HOLD_BUFF \
{ \
util_out_print("!_!_Partial Value :", TRUE); \
zwr_out_print(sn_hold_buff, sn_hold_buff_pos); \
util_out_print(0, TRUE); \
}
/* starting extract file format 3, we have an extra record for each gvn, that contains the
* collation information of the database at the time of extract. This record is transparent
* to the user, so the semantics of the command line options, 'begin' and 'end' to MUPIP LOAD
* will remain same. The collation header is identified in the binary extract by the fact
* that its size is 4 bytes and no valid data record can have length 4.
*/
void bin_call_db(int, INTPTR_T, INTPTR_T);
void zwr_out_print(char * buff, int len);
#define ZWR_BASE_STRIDE 1024
#define UOP_BASE_STRIDE 1024
void zwr_out_print(char * buff, int bufflen)
{
char zwrbuff[ZWR_BASE_STRIDE * MAX_ZWR_EXP_RATIO], savechar;
int zwrlen;
int buffpos, left, stride;
int uopbuffpos, uopleft, uopstride;
buffpos = 0;
while (left = bufflen - buffpos)
{
if (buffpos)
FPRINTF(stderr,"_");
stride = (left > ZWR_BASE_STRIDE) ? ZWR_BASE_STRIDE : left;
format2zwr((sm_uc_ptr_t)(buff + buffpos), stride, (unsigned char *) zwrbuff, &zwrlen);
uopbuffpos = 0;
while (uopleft = zwrlen - uopbuffpos)
{
uopstride = (uopleft > UOP_BASE_STRIDE) ? UOP_BASE_STRIDE : uopleft;
savechar = *(zwrbuff + uopstride);
*(zwrbuff + uopstride) = '\0';
FPRINTF(stderr,"%s", zwrbuff + uopbuffpos);
*(zwrbuff + uopstride) = savechar;
uopbuffpos += uopstride;
}
buffpos += stride;
}
FPRINTF(stderr,"\n");
}
void bin_load(uint4 begin, uint4 end)
{
unsigned char *ptr, *cp1, *cp2, *btop, *gvkey_char_ptr, *tmp_ptr, *tmp_key_ptr, *c, *ctop, *ptr_base;
unsigned char hdr_lvl, src_buff[MAX_KEY_SZ + 1], dest_buff[MAX_ZWR_KEY_SZ],
cmpc_str[MAX_KEY_SZ + 1], dup_key_str[MAX_KEY_SZ + 1], sn_key_str[MAX_KEY_SZ + 1], *sn_key_str_end;
unsigned char *end_buff;
unsigned short rec_len, next_cmpc, numsubs;
int len;
int current, last, length, max_blk_siz, max_key, status;
int tmp_cmpc, sn_chunk_number, expected_sn_chunk_number = 0, sn_hold_buff_pos, sn_hold_buff_size;
uint4 iter, max_data_len, max_subsc_len, key_count, gblsize;
ssize_t rec_count, global_key_count, subsc_len,extr_std_null_coll, last_sn_error_offset=0,
file_offset_base=0, file_offset=0;
boolean_t need_xlation, new_gvn, utf8_extract;
boolean_t is_hidden_subscript, ok_to_put = TRUE, putting_a_sn = FALSE, sn_incmp_gbl_already_killed = FALSE;
rec_hdr *rp, *next_rp;
mval v, tmp_mval;
mstr mstr_src, mstr_dest;
collseq *extr_collseq, *db_collseq, *save_gv_target_collseq;
coll_hdr extr_collhdr, db_collhdr;
gv_key *tmp_gvkey = NULL; /* null-initialize at start, will be malloced later */
gv_key *sn_gvkey = NULL; /* null-initialize at start, will be malloced later */
gv_key *sn_savekey = NULL; /* null-initialize at start, will be malloced later */
char std_null_coll[BIN_HEADER_NUMSZ + 1], *sn_hold_buff = NULL, *sn_hold_buff_temp = NULL;
# ifdef GTM_CRYPT
gtmcrypt_key_t *encr_key_handles;
char *inbuf;
int4 index;
int in_len, gtmcrypt_errno;
muext_hash_hdr_ptr_t hash_array = NULL;
# endif
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
assert(4 == SIZEOF(coll_hdr));
gvinit();
v.mvtype = MV_STR;
len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base);
hdr_lvl = EXTR_HEADER_LEVEL(ptr);
if (!(((('4' == hdr_lvl) || ('5' == hdr_lvl)) && (V5_BIN_HEADER_SZ == len)) ||
(('6' == hdr_lvl) && (BIN_HEADER_SZ == len)) ||
(('7' == hdr_lvl) && (BIN_HEADER_SZ == len)) ||
(('4' > hdr_lvl) && (V3_BIN_HEADER_SZ == len))))
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
/* expecting the level in a single character */
assert(' ' == *(ptr + SIZEOF(BIN_HEADER_LABEL) - 3));
if (0 != memcmp(ptr, BIN_HEADER_LABEL, SIZEOF(BIN_HEADER_LABEL) - 2) || ('2' > hdr_lvl) ||
*(BIN_HEADER_VERSION_ENCR) < hdr_lvl)
{ /* ignore the level check */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
/* check if extract was generated in UTF-8 mode */
utf8_extract = (0 == MEMCMP_LIT(&ptr[len - BIN_HEADER_LABELSZ], UTF8_NAME)) ? TRUE : FALSE;
if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode))
{ /* extract CHSET doesn't match $ZCHSET */
if (utf8_extract)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8"));
else
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M"));
mupip_exit(ERR_LDBINFMT);
}
if ('4' >= hdr_lvl)
{ /* Binary extracts in V50000-to-V52000 (label=4) and pre-V50000 (label=3) could have a '\0' byte (NULL byte)
* in the middle of the string. Replace it with ' ' (space) like it would be in V52000 binary extracts and above.
*/
for (c = ptr, ctop = c + len; c < ctop; c++)
{
if ('\0' == *c)
*c = ' ';
}
}
util_out_print("Label = !AD\n", TRUE, len, ptr);
new_gvn = FALSE;
if (hdr_lvl > '3')
{
if (hdr_lvl > '5')
{
memcpy(std_null_coll, ptr + BIN_HEADER_NULLCOLLOFFSET, BIN_HEADER_NUMSZ);
std_null_coll[BIN_HEADER_NUMSZ] = '\0';
}
else
{
memcpy(std_null_coll, ptr + V5_BIN_HEADER_NULLCOLLOFFSET, V5_BIN_HEADER_NUMSZ);
std_null_coll[V5_BIN_HEADER_NUMSZ] = '\0';
}
extr_std_null_coll = STRTOUL(std_null_coll, NULL, 10);
if (0 != extr_std_null_coll && 1!= extr_std_null_coll)
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2,
RTS_ERROR_TEXT("Corrupted null collation field in header"), ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
} else
extr_std_null_coll = 0;
# ifdef GTM_CRYPT
if ('7' <= hdr_lvl)
{
int i, num_indexes;
len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base);
hash_array = (muext_hash_hdr *)malloc(len);
/* store hashes of all the files used during extract into muext_hash_hdr structure */
memcpy((char *)hash_array, ptr, len);
num_indexes = len / GTMCRYPT_HASH_LEN;
encr_key_handles = (gtmcrypt_key_t *)malloc(SIZEOF(gtmcrypt_key_t) * num_indexes);
INIT_PROC_ENCRYPTION(NULL, gtmcrypt_errno);
GC_BIN_LOAD_ERR(gtmcrypt_errno);
for (index = 0; index < num_indexes; index++)
{
if (0 == memcmp(hash_array[index].gtmcrypt_hash, EMPTY_GTMCRYPT_HASH, GTMCRYPT_HASH_LEN))
continue;
GTMCRYPT_GETKEY(NULL, hash_array[index].gtmcrypt_hash, encr_key_handles[index], gtmcrypt_errno);
GC_BIN_LOAD_ERR(gtmcrypt_errno);
}
}
# endif
if ('2' < hdr_lvl)
{
len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base);
if (SIZEOF(coll_hdr) != len)
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"),
ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
extr_collhdr = *((coll_hdr *)(ptr));
new_gvn = TRUE;
} else
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0');
if (begin < 2)
begin = 2;
for (iter = 2; iter < begin; iter++)
{
if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base)))
{
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin);
util_out_print("Error reading record number: !UL\n", TRUE, iter);
mupip_error_occurred = TRUE;
return;
} else if (len == SIZEOF(coll_hdr))
{
extr_collhdr = *((coll_hdr *)(ptr));
assert(hdr_lvl > '2');
iter--;
}
}
assert(iter == begin);
util_out_print("Beginning LOAD at record number: !UL\n", TRUE, begin);
max_data_len = 0;
max_subsc_len = 0;
global_key_count = key_count = 0;
rec_count = begin - 1;
extr_collseq = db_collseq = NULL;
need_xlation = FALSE;
assert(NULL == tmp_gvkey); /* GVKEY_INIT macro relies on this */
GVKEY_INIT(tmp_gvkey, DBKEYSIZE(MAX_KEY_SZ)); /* tmp_gvkey will point to malloced memory after this */
assert(NULL == sn_gvkey); /* GVKEY_INIT macro relies on this */
GVKEY_INIT(sn_gvkey, DBKEYSIZE(MAX_KEY_SZ)); /* sn_gvkey will point to malloced memory after this */
assert(NULL == sn_savekey); /* GVKEY_INIT macro relies on this */
GVKEY_INIT(sn_savekey, DBKEYSIZE(MAX_KEY_SZ)); /* sn_gvkey will point to malloced memory after this */
for (; !mupip_DB_full ;)
{
if (++rec_count > end)
break;
next_cmpc = 0;
mupip_error_occurred = FALSE;
if (mu_ctrly_occurred)
break;
if (mu_ctrlc_occurred)
{
util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE,
LEN_AND_LIT("LOAD TOTAL"), key_count, max_subsc_len, max_data_len);
util_out_print("Last LOAD record number: !UL", TRUE, key_count ? (rec_count - 1) : 0);
mu_gvis();
util_out_print(0, TRUE);
mu_ctrlc_occurred = FALSE;
}
if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base)) || mupip_error_occurred)
break;
else if (len == SIZEOF(coll_hdr))
{
extr_collhdr = *((coll_hdr *)(ptr));
assert(hdr_lvl > '2');
new_gvn = TRUE; /* next record will contain a new gvn */
rec_count--; /* Decrement as this record does not count as a record for loading purposes */
continue;
}
rp = (rec_hdr*)(ptr);
# ifdef GTM_CRYPT
if ('7' <= hdr_lvl)
{ /* Getting index value from the extracted file. It indicates which database file this record belongs to */
GET_LONG(index, ptr);
if (-1 != index) /* Indicates that the record is encrypted. */
{
in_len = len - SIZEOF(int4);
inbuf = (char *)(ptr + SIZEOF(int4));
GTMCRYPT_DECRYPT(NULL, encr_key_handles[index], inbuf, in_len, NULL, gtmcrypt_errno);
GC_BIN_LOAD_ERR(gtmcrypt_errno);
}
rp = (rec_hdr*)(ptr + SIZEOF(int4));
}
# endif
btop = ptr + len;
cp1 = (unsigned char*)(rp + 1);
v.str.addr = (char*)cp1;
while (*cp1++)
;
v.str.len =INTCAST((char*)cp1 - v.str.addr - 1);
if (('2' >= hdr_lvl) || new_gvn)
{
if ((HASHT_GBLNAME_LEN == v.str.len) && (0 == memcmp(v.str.addr, HASHT_GBLNAME, HASHT_GBLNAME_LEN)))
continue;
bin_call_db(BIN_BIND, (INTPTR_T)gd_header, (INTPTR_T)&v.str);
max_key = gv_cur_region->max_key_size;
db_collhdr.act = gv_target->act;
db_collhdr.ver = gv_target->ver;
db_collhdr.nct = gv_target->nct;
}
GET_USHORT(rec_len, &rp->rsiz);
if (EVAL_CMPC(rp) != 0 || v.str.len > rec_len || mupip_error_occurred)
{
bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count);
mu_gvis();
DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK;
continue;
}
if (new_gvn)
{
global_key_count = 1;
if ((db_collhdr.act != extr_collhdr.act || db_collhdr.ver != extr_collhdr.ver
|| db_collhdr.nct != extr_collhdr.nct
|| gv_cur_region->std_null_coll != extr_std_null_coll))
{
if (extr_collhdr.act)
{
if (extr_collseq = ready_collseq((int)extr_collhdr.act))
{
if (!do_verify(extr_collseq, extr_collhdr.act, extr_collhdr.ver))
{
gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_COLLTYPVERSION, 2,
extr_collhdr.act, extr_collhdr.ver, ERR_GVIS, 2,
gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLTYPVERSION);
}
} else
{
gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COLLATIONUNDEF, 1,
extr_collhdr.act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLATIONUNDEF);
}
}
if (db_collhdr.act)
{
if (db_collseq = ready_collseq((int)db_collhdr.act))
{
if (!do_verify(db_collseq, db_collhdr.act, db_collhdr.ver))
{
gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_COLLTYPVERSION, 2,
db_collhdr.act, db_collhdr.ver, ERR_GVIS, 2,
gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLTYPVERSION);
}
} else
{
gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act,
ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLATIONUNDEF);
}
}
need_xlation = TRUE;
} else
need_xlation = FALSE;
}
new_gvn = FALSE;
for (; rp < (rec_hdr*)btop; rp = (rec_hdr*)((unsigned char *)rp + rec_len))
{
GET_USHORT(rec_len, &rp->rsiz);
if (rec_len + (unsigned char *)rp > btop)
{
bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count);
mu_gvis();
DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK;
break;
}
cp1 = (unsigned char*)(rp + 1);
cp2 = gv_currkey->base + EVAL_CMPC(rp);
current = 1;
for (;;)
{
last = current;
current = *cp2++ = *cp1++;
if (0 == last && 0 == current)
break;
if (cp1 > (unsigned char *)rp + rec_len ||
cp2 > (unsigned char *)gv_currkey + gv_currkey->top)
{
gv_currkey->end = cp2 - gv_currkey->base - 1;
gv_currkey->base[gv_currkey->end] = 0;
gv_currkey->base[gv_currkey->end - 1] = 0;
bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count);
mu_gvis();
DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK;
break;
}
}
if (mupip_error_occurred)
break;
gv_currkey->end = cp2 - gv_currkey->base - 1;
if (need_xlation)
{
assert(hdr_lvl >= '3');
assert(extr_collhdr.act || db_collhdr.act || extr_collhdr.nct || db_collhdr.nct ||
extr_std_null_coll != gv_cur_region->std_null_coll);
/* gv_currkey would have been modified/translated in the earlier put */
memcpy(gv_currkey->base, cmpc_str, next_cmpc);
next_rp = (rec_hdr *)((unsigned char*)rp + rec_len);
if ((unsigned char*)next_rp < btop)
{
next_cmpc = EVAL_CMPC(next_rp);
assert(next_cmpc <= gv_currkey->end);
memcpy(cmpc_str, gv_currkey->base, next_cmpc);
} else
next_cmpc = 0;
/* length of the key might change (due to nct variation),
* so get a copy of the original key from the extract */
memcpy(dup_key_str, gv_currkey->base, gv_currkey->end + 1);
gvkey_char_ptr = dup_key_str;
while (*gvkey_char_ptr++)
;
gv_currkey->prev = 0;
gv_currkey->end = gvkey_char_ptr - dup_key_str;
assert(gv_keysize <= tmp_gvkey->top);
while (*gvkey_char_ptr)
{
/* get next subscript (in GT.M internal subsc format) */
subsc_len = 0;
tmp_ptr = src_buff;
while (*gvkey_char_ptr)
*tmp_ptr++ = *gvkey_char_ptr++;
subsc_len = tmp_ptr - src_buff;
src_buff[subsc_len] = '\0';
if (extr_collseq)
{
/* undo the extract time collation */
TREF(transform) = TRUE;
save_gv_target_collseq = gv_target->collseq;
gv_target->collseq = extr_collseq;
} else
TREF(transform) = FALSE;
/* convert the subscript to string format */
end_buff = gvsub2str(src_buff, dest_buff, FALSE);
/* transform the string to the current subsc format */
TREF(transform) = TRUE;
tmp_mval.mvtype = MV_STR;
tmp_mval.str.addr = (char *)dest_buff;
tmp_mval.str.len = INTCAST(end_buff - dest_buff);
tmp_gvkey->prev = 0;
tmp_gvkey->end = 0;
if (extr_collseq)
gv_target->collseq = save_gv_target_collseq;
mval2subsc(&tmp_mval, tmp_gvkey);
/* we now have the correctly transformed subscript */
tmp_key_ptr = gv_currkey->base + gv_currkey->end;
memcpy(tmp_key_ptr, tmp_gvkey->base, tmp_gvkey->end + 1);
gv_currkey->prev = gv_currkey->end;
gv_currkey->end += tmp_gvkey->end;
gvkey_char_ptr++;
}
if ( gv_cur_region->std_null_coll != extr_std_null_coll && gv_currkey->prev)
{
if (extr_std_null_coll == 0)
{
GTM2STDNULLCOLL(gv_currkey->base, gv_currkey->end);
} else
{
STD2GTMNULLCOLL(gv_currkey->base, gv_currkey->end);
}
}
}
if (gv_currkey->end >= max_key)
{
bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count);
mu_gvis();
DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK;
continue;
}
/*
* Spanning node-related variables and their usage:
*
* expected_sn_chunk_number: 0 - looking for spanning nodes (regular nodes are OK, too)
* !0 - number of the next chunk needed (implies we are building
* a spanning node's value)
*
* While building a spanning node's value:
* numsubs: the number of chunks needed to build the spanning node's value
* gblsize: the expected size of the completed value
* sn_chunk_number: The chunk number of the chunk from the current record from the extract
*
* Managing the value
* sn_hold_buff: buffer used to accumulate the spanning node's value
* sn_hold_buff_size: Allocated size of buffer
* sn_hold_buff_pos: amount of the buffer used; where to place the next chunk
* sn_hold_buff_temp: used when we have to increase the size of the buffer
*
* Controlling the placing of the key,value in the database:
* ok_to_put: means we are ready to place the key,value in the database, i.e., we have the full value
* (either of the spanning node or a regular node).
* putting_a_sn: we are placing a spanning node in the database, i.e, use the key from sn_gvkey and
* the value from sn_hold_buff.
*/
CHECK_HIDDEN_SUBSCRIPT(gv_currkey,is_hidden_subscript);
if (!is_hidden_subscript && (max_subsc_len < (gv_currkey->end + 1)))
max_subsc_len = gv_currkey->end + 1;
v.str.addr = (char*)cp1;
v.str.len =INTCAST(rec_len - (cp1 - (unsigned char *)rp));
if (expected_sn_chunk_number && !is_hidden_subscript)
{ /* we were expecting a chunk of an spanning node and we did not get one */
DISPLAY_INCMP_SN_MSG;
util_out_print("!_!_Expected chunk number : !UL but found a non-spanning node", TRUE,
expected_sn_chunk_number + 1);
if (sn_hold_buff_pos)
DISPLAY_PARTIAL_SN_HOLD_BUFF;
KILL_INCMP_SN_IF_NEEDED;
sn_hold_buff_pos = 0;
expected_sn_chunk_number = 0;
ok_to_put = TRUE;
putting_a_sn = FALSE;
numsubs = 0;
}
if (is_hidden_subscript)
{ /* it's a chunk and we were expecting one */
sn_chunk_number = SPAN_GVSUBS2INT((span_subs *) &(gv_currkey->base[gv_currkey->end - 4]));
if (!expected_sn_chunk_number && is_hidden_subscript && sn_chunk_number)
{ /* we not expecting a payload chunk (as opposed to a control record) but we got one */
DISPLAY_INCMP_SN_MSG;
util_out_print("!_!_Not expecting a spanning node chunk but found chunk : !UL", TRUE,
sn_chunk_number + 1);
if (v.str.len)
DISPLAY_VALUE("!_!_Errant Chunk :");
continue;
}
if (0 == sn_chunk_number)
{ /* first spanning node chunk, get ctrl info */
if (0 != expected_sn_chunk_number)
{
DISPLAY_INCMP_SN_MSG;
util_out_print("!_!_Expected chunk number : !UL but found chunk number : !UL", TRUE,
expected_sn_chunk_number + 1, sn_chunk_number + 1);
if (sn_hold_buff_pos)
DISPLAY_PARTIAL_SN_HOLD_BUFF;
KILL_INCMP_SN_IF_NEEDED;
}
/* start building a new spanning node */
sn_gvkey->end = gv_currkey->end - (SPAN_SUBS_LEN + 1);
memcpy(sn_gvkey->base, gv_currkey->base, sn_gvkey->end);
sn_gvkey->base[sn_gvkey->end] = 0;
sn_gvkey->prev = gv_currkey->prev;
sn_gvkey->top = gv_currkey->top;
GET_NSBCTRL(v.str.addr, numsubs, gblsize);
/* look for first payload chunk */
expected_sn_chunk_number = 1;
sn_hold_buff_pos = 0;
ok_to_put = FALSE;
sn_incmp_gbl_already_killed = FALSE;
} else
{ /* we only need to compare the key before the hidden subscripts */
if ((expected_sn_chunk_number == sn_chunk_number)
&& (sn_gvkey->end == gv_currkey->end - (SPAN_SUBS_LEN + 1))
&& !memcmp(sn_gvkey->base,gv_currkey->base, sn_gvkey->end)
&& ((sn_hold_buff_pos + v.str.len) <= gblsize))
{
if (NULL == sn_hold_buff)
{
sn_hold_buff_size = DEFAULT_SN_HOLD_BUFF_SIZE;
sn_hold_buff = (char *)malloc(DEFAULT_SN_HOLD_BUFF_SIZE);
}
if ((sn_hold_buff_pos + v.str.len) > sn_hold_buff_size)
{
sn_hold_buff_size = sn_hold_buff_size * 2;
sn_hold_buff_temp = (char *)malloc(sn_hold_buff_size);
memcpy(sn_hold_buff_temp, sn_hold_buff, sn_hold_buff_pos);
free (sn_hold_buff);
sn_hold_buff = sn_hold_buff_temp;
}
memcpy(sn_hold_buff + sn_hold_buff_pos, v.str.addr, v.str.len);
sn_hold_buff_pos += v.str.len;
if (expected_sn_chunk_number == numsubs)
{
if (sn_hold_buff_pos != gblsize)
{ /* we don't have the expected size even though */
/* we have all the expected chunks. */
DISPLAY_INCMP_SN_MSG;
util_out_print("!_!_Expected size : !UL actual size : !UL", TRUE,
gblsize, sn_hold_buff_pos);
if (sn_hold_buff_pos)
DISPLAY_PARTIAL_SN_HOLD_BUFF;
KILL_INCMP_SN_IF_NEEDED;
expected_sn_chunk_number = 0;
ok_to_put = FALSE;
sn_hold_buff_pos = 0;
}
else
{
expected_sn_chunk_number = 0;
ok_to_put = TRUE;
putting_a_sn = TRUE;
}
}else
expected_sn_chunk_number++;
}else
{
DISPLAY_INCMP_SN_MSG;
if ((sn_hold_buff_pos + v.str.len) <= gblsize)
util_out_print("!_!_Expected chunk number : !UL but found chunk number : !UL", /*BYPASSOK*/
TRUE, expected_sn_chunk_number + 1, sn_chunk_number + 1);
else
util_out_print("!_!_Global value too large: expected size : !UL actual size : !UL chunk number : !UL", TRUE, /*BYPASSOK*/
gblsize, sn_hold_buff_pos + v.str.len, sn_chunk_number + 1);
if (sn_hold_buff_pos)
DISPLAY_PARTIAL_SN_HOLD_BUFF;
if (v.str.len)
DISPLAY_VALUE("!_!_Errant Chunk :");
KILL_INCMP_SN_IF_NEEDED;
sn_hold_buff_pos = 0;
expected_sn_chunk_number = 0;
}
}
} else
ok_to_put = TRUE;
if (ok_to_put)
{
if (putting_a_sn)
{
gv_currkey->base[gv_currkey->end - (SPAN_SUBS_LEN + 1)] = 0;
gv_currkey->end -= (SPAN_SUBS_LEN + 1);
v.str.addr = sn_hold_buff;
v.str.len = sn_hold_buff_pos;
}
if (max_data_len < v.str.len)
max_data_len = v.str.len;
bin_call_db(BIN_PUT, (INTPTR_T)&v, 0);
if (mupip_error_occurred)
{
if (!mupip_DB_full)
{
bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count);
file_offset = file_offset_base + ((unsigned char *)rp - ptr_base);
util_out_print("!_!_at File offset : [0x!XL]", TRUE, file_offset);
DISPLAY_CURRKEY;
DISPLAY_VALUE("!_!_Value :");
}
break;
}
if (putting_a_sn)
putting_a_sn = FALSE;
else
{
key_count++;
global_key_count++;
}
}
}
}
GTMCRYPT_ONLY(
if (NULL != hash_array)
free(hash_array);
)
free(tmp_gvkey);
free(sn_gvkey);
if (NULL != sn_hold_buff)
free(sn_hold_buff);
file_input_close();
util_out_print("LOAD TOTAL!_!_Key Cnt: !UL Max Subsc Len: !UL Max Data Len: !UL", TRUE, key_count, max_subsc_len,
max_data_len);
util_out_print("Last LOAD record number: !UL\n", TRUE, key_count ? (rec_count - 1) : 0);
if (mu_ctrly_occurred)
{
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LOADCTRLY);
mupip_exit(ERR_MUNOFINISH);
}
}
void bin_call_db(int routine, INTPTR_T parm1, INTPTR_T parm2)
{ /* In order to duplicate the VMS functionality, which is to trap all errors in mupip_load_ch and
* continue in bin_load after they occur, it is necessary to call these routines from a
* subroutine due to the limitations of condition handlers and unwinding on UNIX
*/
ESTABLISH(mupip_load_ch);
switch(routine)
{
case BIN_PUT:
op_gvput((mval *)parm1);
break;
case BIN_BIND:
GV_BIND_NAME_AND_ROOT_SEARCH((gd_addr *)parm1, (mstr *)parm2);
break;
case ERR_COR:
rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_CORRUPT, 2, parm1, parm2);
case BIN_KILL:
gvcst_kill(FALSE);
break;
}
REVERT;
}