/**************************************************************** * * * 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 "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "rc.h" #include "cdb_sc.h" #include "rc_oflow.h" #include "copy.h" #include "error.h" #include "gtcm.h" #include "t_end.h" #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_search,gvcst_rtsib,gvcst_lftsib prototype */ GBLREF int rc_size_return; GBLREF gd_addr *gd_header; GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; GBLREF sgmnt_data *cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLDEF rc_oflow *rc_overflow; GBLREF gd_region *gv_cur_region; GBLREF trans_num rc_read_stamp; GBLREF int gv_keysize; error_def(ERR_GVGETFAIL); int rc_prc_getr(rc_q_hdr *qhdr) { int key_size, data_len, i; bool dollar_order, two_histories; char *cp2, *cp1; mval v; short rsiz, bsiz, fmode, size_return; rec_hdr *rp; blk_hdr *bp; srch_hist second_history; enum cdb_sc status; rc_req_getr *req; rc_rsp_page *rsp; srch_blk_status *bh; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ESTABLISH_RET(rc_dbms_ch,0); req = (rc_req_getr *)qhdr; rsp = (rc_rsp_page *)qhdr; rsp->hdr.a.len.value = (short)((char*)(&rsp->page[0]) - (char*)rsp); fmode = qhdr->r.fmd.value; if ((qhdr->a.erc.value = rc_fnd_file(&qhdr->r.xdsid)) != RC_SUCCESS) { REVERT; DEBUG_ONLY(gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"rc_fnd_file failed.");) return -1; } if (req->key.len.value > cs_data->max_key_size) { qhdr->a.erc.value = RC_KEYTOOLONG; rsp->size_return.value = 0; rsp->size_remain.value = 0; rsp->rstatus.value = 0; REVERT; return 0; } v.mvtype = MV_STR; cp2 = req->key.key + req->key.len.value; for (cp1 = req->key.key; *cp1 && cp1 < cp2; cp1++) ; v.str.len = INTCAST(cp1 - req->key.key); v.str.addr = req->key.key; if (v.str.len > MAX_MIDENT_LEN) /* GT.M does not support global variables > MAX_MIDENT_LEN chars */ { if (!(v.str.len == (MAX_MIDENT_LEN + 1) && v.str.addr[MAX_MIDENT_LEN] == 0x01)) { qhdr->a.erc.value = RC_KEYTOOLONG; rsp->size_return.value = 0; rsp->size_remain.value = 0; rsp->rstatus.value = 0; REVERT; DEBUG_ONLY(gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");) return -1; } } GV_BIND_NAME_AND_ROOT_SEARCH(gd_header, &v.str); memcpy(gv_currkey->base, req->key.key, req->key.len.value); gv_currkey->end = req->key.len.value; dollar_order = FALSE; if (gv_currkey->base[gv_currkey->end - 1] == 0xFF) { TREF(gv_last_subsc_null) = TRUE; /* Trailing null subscript has NO trailing zero */ gv_currkey->base[gv_currkey->end] = 0; gv_currkey->end += 1; }else { TREF(gv_last_subsc_null) = FALSE; if (gv_currkey->base[gv_currkey->end - 1] == 0x01) { dollar_order = TRUE; gv_currkey->base[gv_currkey->end] = 0; gv_currkey->end += 1; } } if (!gv_target->root && (cp1 != cp2)) { qhdr->a.erc.value = RC_MUMERRUNDEFVAR; rsp->size_return.value = 0; rsp->size_remain.value = 0; rsp->rstatus.value = 0; REVERT; return 0; } gv_currkey->base[gv_currkey->end] = 0; for (i = gv_currkey->end - 2; i > 0; i--) if (!gv_currkey->base[i - 1]) break; gv_currkey->prev = i; if (fmode & RC_MODE_NEXT) { if (TREF(gv_last_subsc_null)) gv_currkey->base[gv_currkey->prev] = 01; else { if (dollar_order) { gv_currkey->end++; gv_currkey->base[gv_currkey->end] = 0; }else { gv_currkey->base[gv_currkey->end] = 1; gv_currkey->base[gv_currkey->end + 1] = 0; gv_currkey->base[gv_currkey->end + 2] = 0; gv_currkey->end += 2; } } } else if (fmode & RC_MODE_PREV) { if (TREF(gv_last_subsc_null)) { *(&gv_currkey->base[0] + gv_currkey->prev + 1) = 0xFF; *(&gv_currkey->base[0] + gv_currkey->end + 1) = 0; gv_currkey->end += 1; } } rsp->size_return.value = 0; if (dollar_order && (cp1 == cp2)) { rc_gbl_ord(rsp); REVERT; return 0; } if (!gv_target->root) { qhdr->a.erc.value = RC_BADXBUF; rsp->size_return.value = 0; rsp->size_remain.value = 0; rsp->rstatus.value = 0; REVERT; return 0; } t_begin(ERR_GVGETFAIL, 0); for (;;) { rsp->hdr.a.len.value = (short)((char*)(&rsp->page[0]) - (char*)rsp); size_return = rc_size_return; two_histories = FALSE; if ((status = gvcst_search(gv_currkey, NULL)) == cdb_sc_normal) { bh = gv_target->hist.h; if (fmode & RC_MODE_NEXT) /* if getnext */ { rp = (rec_hdr *)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr *)bh->buffaddr; if (rp >= (rec_hdr *)CST_TOB(bp)) { two_histories = TRUE; status = gvcst_rtsib(&second_history, 0); if (status == cdb_sc_normal) bh = second_history.h; else if (status == cdb_sc_endtree) two_histories = FALSE; /* second history not valid */ else goto restart; } } else if (fmode & RC_MODE_PREV) /* if get previous */ { if (bh->prev_rec.offset == 0) { two_histories = TRUE; status = gvcst_lftsib(&second_history); if (status == cdb_sc_normal) bh = second_history.h; else if (status == cdb_sc_endtree) two_histories = FALSE; /* second history not valid */ else goto restart; } } if ((bsiz = ((blk_hdr *)(bh->buffaddr))->bsiz + RC_BLKHD_PAD) > SIZEOF(blk_hdr) + RC_BLKHD_PAD) { /* Non-empty block, global exists */ if (bsiz > size_return) rc_overflow->size = bsiz - size_return; else { rc_overflow->size = 0; size_return = bsiz; } memcpy(rsp->page, bh->buffaddr, SIZEOF(blk_hdr)); PUT_SHORT(&((blk_hdr*)rsp->page)->bsiz,bsiz); memcpy(rsp->page + SIZEOF(blk_hdr) + RC_BLKHD_PAD, bh->buffaddr + SIZEOF(blk_hdr), size_return - (SIZEOF(blk_hdr) + RC_BLKHD_PAD)); rsp->size_return.value = size_return; rsp->hdr.a.len.value += rsp->size_return.value; assert(rsp->hdr.a.len.value <= rc_size_return+SIZEOF(rc_rsp_page)); rsp->zcode.value = (cs_data->blk_size / 512); /* (2 ** zcode) == blk_size */ if (rc_overflow->size) { memcpy(rc_overflow->buff, bh->buffaddr + size_return - RC_BLKHD_PAD, rc_overflow->size); rc_overflow->offset = size_return; rc_overflow->dsid = qhdr->r.xdsid.dsid.value; rc_overflow->page = bh->blk_num; rc_overflow->zcode = rsp->zcode.value; } rsp->size_remain.value = rc_overflow->size; } if (0 == (rc_read_stamp = t_end(&gv_target->hist, two_histories ? &second_history : NULL, TN_NOT_SPECIFIED))) continue; if (bsiz == SIZEOF(blk_hdr) + RC_BLKHD_PAD) /* Empty block, global does not exist */ { qhdr->a.erc.value = RC_MUMERRUNDEFVAR; rsp->size_return.value = 0; rsp->size_remain.value = 0; rsp->rstatus.value = 0; REVERT; return 0; } if (status == cdb_sc_endtree) { if (fmode & RC_MODE_NEXT) { rsp->after.value = (unsigned short)-1; rsp->before.value = 0; }else { rsp->after.value = 0; rsp->before.value = (unsigned short)-1; } rsp->xcc.value = 0; }else { if (two_histories) { rsp->after.value = 0; rsp->before.value = 0; rsp->xcc.value = 0; }else { if (fmode & RC_MODE_PREV) /* getprev */ { rsp->before.value = bh->prev_rec.offset; if (rsp->before.value) rsp->before.value += RC_BLKHD_PAD; rsp->xcc.value = bh->prev_rec.match; rsp->after.value = bh->curr_rec.offset + RC_BLKHD_PAD; }else /* if getnext or just get */ { /* If key not found, use prev and curr, else use curr and next */ if (gv_currkey->end + 1 != bh->curr_rec.match) /* not found */ { rsp->before.value = bh->prev_rec.offset; if (rsp->before.value) rsp->before.value += RC_BLKHD_PAD; rsp->xcc.value = bh->prev_rec.match; rsp->after.value = bh->curr_rec.offset + RC_BLKHD_PAD; }else /* found */ { rsp->before.value = bh->curr_rec.offset; if (rsp->before.value) rsp->before.value += RC_BLKHD_PAD; rsp->xcc.value = bh->curr_rec.match; rp = (rec_hdr *)(bh->buffaddr + bh->curr_rec.offset); GET_SHORT(rsiz, &rp->rsiz); rsp->after.value = bh->curr_rec.offset + rsiz + RC_BLKHD_PAD; } } } } PUT_LONG(rsp->pageaddr, bh->blk_num); rsp->frag_offset.value = 0; rsp->rstatus.value = 0; REVERT; return 0; } restart: t_retry(status); } }