/* returns FALSE if gv_currkey is undefined in the server end and undef_inhibit is turned OFF */ void gvcmx_increment(mval *increment, mval *result) { unsigned char buff[MAX_ZWR_KEY_SZ], *end; mval tmpmval; error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); error_def(ERR_GVIS); if (!((link_info *)gv_cur_region->dyn.addr->cm_blk->usr)->server_supports_dollar_incr) { assert(dba_cm == gv_cur_region->dyn.addr->acc_meth); /* we should've covered all other access methods elsewhere */ end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE); rts_error(VARLSTCNT(14) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM server does not support $INCREMENT operation"), ERR_GVIS, 2, end - buff, buff, ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); } /* gvcmz_doop() currently accepts only one argument. * It serves as an input argument for SET. * It serves as an output argument for GET etc. * $INCR is unique in that it needs to pass the increment as input and expects the post-increment as output. * * In order to accomplish this without changing the gvcmz_doop() interface, we overload the one argument to * serve two purposes. It will be an input argument until the send of the message to the server and will * then serve as an output argument after the response from the server. ("result" is used for this purpose) * i.e. * to serve as increment for client --> server message * to serve as post-increment value for server --> client message */ assert(MV_IS_NUMERIC(increment)); /* op_gvincr would have forced it to be a NUMERIC */ MV_FORCE_STR(increment); /* convert it to a string before sending it to gvcmz_doop */ *result = *increment; gvcmz_doop(CMMS_Q_INCREMENT, CMMS_R_INCREMENT, result); }
void sgnl_gvundef(void) { unsigned char buff[MAX_ZWR_KEY_SZ], *end; error_def(ERR_GVUNDEF); if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) { end = &buff[MAX_ZWR_KEY_SZ - 1]; } rts_error(VARLSTCNT(4) ERR_GVUNDEF, 2, end - &buff[0], &buff[0]); }
void sgnl_gvnulsubsc(void) { unsigned char buff[MAX_ZWR_KEY_SZ], *end; if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) { end = &buff[MAX_ZWR_KEY_SZ - 1]; } gv_currkey->end = 0; rts_error_csa(NULL, VARLSTCNT(8) ERR_NULSUBSC, 2, gv_cur_region->rname_len, &gv_cur_region->rname[0], ERR_GVIS, 2, end - &buff[0], &buff[0]); }
void get_reference(mval *var) { char *end, *start; char extnamdelim[] = "^|\"\"|"; char *extnamsrc, *extnamtop; int maxlen; /* you need to return a double-quote for every single-quote. assume worst case. */ maxlen = MAX_ZWR_KEY_SZ + (!extnam_str.len ? 0 : ((extnam_str.len * 2) + sizeof(extnamdelim))); if (stringpool.free + maxlen > stringpool.top) stp_gcol(maxlen); var->mvtype = MV_STR; start = var->str.addr = (char *)stringpool.free; var->str.len = 0; if (gv_currkey && gv_currkey->end) { if (extnam_str.len) { *start++ = extnamdelim[0]; *start++ = extnamdelim[1]; *start++ = extnamdelim[2]; extnamsrc = &extnam_str.addr[0]; extnamtop = extnamsrc + extnam_str.len; for ( ; extnamsrc < extnamtop; ) { *start++ = *extnamsrc; if ('"' == *extnamsrc++) /* caution : pointer increment side-effect */ *start++ = '"'; } *start++ = extnamdelim[3]; } end = (char *)format_targ_key((unsigned char *)start, MAX_ZWR_KEY_SZ, gv_currkey, TRUE); if (extnam_str.len) /* Note: the next vertical bar overwrites the caret that * was part of he original name of the global variable */ *start = extnamdelim[4]; var->str.len = end - var->str.addr; stringpool.free += var->str.len; } }
void op_gvincr(mval *increment, mval *result) { unsigned char buff[MAX_ZWR_KEY_SZ], *end; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* If specified var name is global ^%Y*, the name is illegal to use in a SET or KILL command, only GETs are allowed */ if ((RESERVED_NAMESPACE_LEN <= gv_currkey->end) && (0 == MEMCMP_LIT(gv_currkey->base, RESERVED_NAMESPACE))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_PCTYRESERVED); if (gv_cur_region->read_only) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region)); if ((TREF(gv_last_subsc_null) || TREF(gv_some_subsc_null)) && (ALWAYS != gv_cur_region->null_subs)) sgnl_gvnulsubsc(); assert(gv_currkey->end + 1 <= gv_cur_region->max_key_size); MV_FORCE_NUM(increment); switch (gv_cur_region->dyn.addr->acc_meth) { case dba_bg: case dba_mm: gvcst_incr(increment, result); break; case dba_cm: gvcmx_increment(increment, result); break; case dba_usr: /* $INCR not supported for DDP/USR access method */ if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GTCM DDP server does not support $INCREMENT"), ERR_GVIS, 2, end - buff, buff, ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); break; default: assertpro(FALSE); } assert(MV_DEFINED(result)); }
char *jnl2ext(char *jnl_buff, char *ext_buff) { char *curr, *val_ptr, *ptr, rectype, key_buff[sizeof(gv_key) + MAX_KEY_SZ + 7]; jnl_record *rec; gv_key *key; jnl_string *keystr; int val_extr_len, val_len, rec_len; rec = (jnl_record *)jnl_buff; rectype = rec->prefix.jrec_type; rec_len = rec->prefix.forwptr; if (rec_len != REC_LEN_FROM_SUFFIX(jnl_buff, rec_len)) { assert(FALSE); return ext_buff; } if (!IS_REPLICATED(rectype)) { assert(FALSE); return ext_buff; } curr = ext_buff; if (IS_TUPD(rectype)) { if (FALSE == first_tstart) { GET_SHORTP(curr, &muext_code[MUEXT_TSTART][0]); curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2asc((uchar_ptr_t)curr, rec->jrec_kill.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_kill.token_seq.jnl_seqno); *curr++ = '\n'; *curr = '\0'; first_tstart = TRUE; } num_tstarts++; } else if (JRT_TCOM == rectype) { num_tcommits++; if (num_tcommits == num_tstarts) { num_tcommits = num_tstarts = 0; first_tstart = FALSE; GET_SHORTP(curr, &muext_code[MUEXT_TCOMMIT][0]); curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2asc((uchar_ptr_t)curr, rec->jrec_tcom.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_tcom.token_seq.jnl_seqno); DELIMIT_CURR; curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_tcom.participants); *curr++ = '\n'; *curr = '\0'; return curr; } return ext_buff; } if (IS_SET(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_SET][0]); else if (IS_KILL(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_KILL][0]); else if (IS_ZKILL(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_ZKILL][0]); else /* if (JRT_NULL == rectype) */ { assert(JRT_NULL == rectype); GET_SHORTP(curr, &muext_code[MUEXT_NULL][0]); } curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2asc((uchar_ptr_t)curr, rec->jrec_kill.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_kill.token_seq.jnl_seqno); if (rectype == JRT_NULL) { *curr++ = '\n'; *curr='\0'; return curr; } assert(IS_SET_KILL_ZKILL(rectype)); DELIMIT_CURR; keystr = (jnl_string *)&rec->jrec_kill.mumps_node; ptr = (char *)ROUND_UP((uint4)key_buff, 8); key = (gv_key *)ptr; key->top = MAX_KEY_SZ; key->end = keystr->length; if (key->end > key->top) { assert(FALSE); return ext_buff; } memcpy(key->base, &keystr->text[0], keystr->length); key->base[key->end] = 0; curr = (char *)format_targ_key((uchar_ptr_t)curr, MAX_ZWR_KEY_SZ, key, TRUE); if (IS_SET(rectype)) { *curr++ = '='; val_ptr = &keystr->text[keystr->length]; GET_MSTR_LEN(val_len, val_ptr); val_ptr += sizeof(mstr_len_t); format2zwr((sm_uc_ptr_t)val_ptr, val_len, (uchar_ptr_t)curr, &val_extr_len); curr += val_extr_len; } *curr++ = '\n'; *curr='\0'; return curr; }
bool gtcmtr_increment(void) { cm_region_list *reg_ref; mval incr_delta, post_incr; unsigned char buff[MAX_ZWR_KEY_SZ], *end; unsigned char *ptr, regnum; short n; unsigned short top, len, temp_short; static readonly gds_file_id file; error_def(ERR_KEY2BIG); error_def(ERR_GVIS); error_def(ERR_DBPRIVERR); ptr = curr_entry->clb_ptr->mbf; assert(*ptr == CMMS_Q_INCREMENT); ptr++; GET_USHORT(len, ptr); ptr += SIZEOF(unsigned short); regnum = *ptr++; reg_ref = gtcm_find_region(curr_entry,regnum); len--; /* subtract size of regnum */ CM_GET_GVCURRKEY(ptr, len); gtcm_bind_name(reg_ref->reghead, TRUE); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region)); if (JNL_ALLOWED(cs_addrs)) { /* we need to copy client's specific prc_vec into the global variable in order that the gvcst* routines * do the right job. actually we need to do this only if JNL_ENABLED(cs_addrs), but since it is not * easy to re-execute the following two assignments in case gvcst_incr's call to t_end encounters a * cdb_sc_jnlstatemod retry code, we choose the easier approach of executing the following segment * if JNL_ALLOWED(cs_addrs) is TRUE instead of checking for JNL_ENABLED(cs_addrs) to be TRUE. * this approach has the overhead that we will be doing the following assignments even though JNL_ENABLED * might not be TRUE but since the following two are just pointer copies, it is not considered a big overhead. * this approach ensures that the jnl_put_jrt_pini gets the appropriate prc_vec for writing into the * journal record in case JNL_ENABLED turns out to be TRUE in t_end time. * note that the value of JNL_ALLOWED(cs_addrs) cannot be changed on the fly without obtaining standalone access * and hence the correctness of prc_vec (whenever it turns out necessary) is guaranteed. */ originator_prc_vec = curr_entry->pvec; cs_addrs->jnl->pini_addr = reg_ref->pini_addr; } GET_USHORT(len, ptr); ptr += SIZEOF(unsigned short); incr_delta.mvtype = MV_STR; incr_delta.str.len = len; incr_delta.str.addr = (char *)ptr; if ((n = gv_currkey->end + 1) > gv_cur_region->max_key_size) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error(VARLSTCNT(11) ERR_KEY2BIG, 4, n, (int4)gv_cur_region->max_key_size, REG_LEN_STR(gv_cur_region), 0, ERR_GVIS, 2, end - buff, buff); } MV_FORCE_NUMD(&incr_delta); gvcst_incr(&incr_delta, &post_incr); if (JNL_ALLOWED(cs_addrs)) reg_ref->pini_addr = cs_addrs->jnl->pini_addr; /* In case journal switch occurred */ ptr = curr_entry->clb_ptr->mbf; if (MV_DEFINED(&post_incr)) { temp_short = (unsigned short)post_incr.str.len; assert((int4)temp_short == post_incr.str.len); /* ushort <- int4 assignment lossy? */ if (curr_entry->clb_ptr->mbl < 1 + /* msg header */ SIZEOF(temp_short) + /* size of length of $INCR return value */ temp_short) /* length of $INCR return value */ { /* resize buffer */ cmi_realloc_mbf(curr_entry->clb_ptr, 1 + SIZEOF(temp_short) + temp_short); ptr = curr_entry->clb_ptr->mbf; } *ptr++ = CMMS_R_INCREMENT; PUT_USHORT(ptr, temp_short); ptr += SIZEOF(unsigned short); memcpy(ptr, post_incr.str.addr, temp_short); ptr += temp_short; } else
boolean_t mur_select_rec(jnl_ctl_list *jctl) { boolean_t exc_item_seen, inc_item_seen, inc_seen, wildcard_match; char key_buff[MAX_KEY_SZ + 1 + SIZEOF(uint4) * 2], asc_key_buff[MAX_ZWR_KEY_SZ], *ptr; int i, key_len, pat_pos, subs_pos; uint4 pini_addr; gv_key *key; jnl_record *rec; pini_list_struct *plst; jnl_process_vector *pv; enum jnl_record_type rectype; long_list *ll_ptr; select_list *sl_ptr; jnl_string *keystr; uint4 status; int4 pv_len, sl_len; assert(mur_options.selection); rec = jctl->reg_ctl->mur_desc->jnlrec; rectype = (enum jnl_record_type)rec->prefix.jrec_type; pini_addr = rec->prefix.pini_addr; key = NULL; if (JRT_NULL == rectype || JRT_ALIGN == rectype) return TRUE; status = mur_get_pini(jctl, pini_addr, &plst); if (SS_NORMAL != status) return TRUE; pv = &plst->jpv; if (IS_SET_KILL_ZKILL_ZTRIG(rectype)) { /* Translate internal format of jnl_record key to ascii */ keystr = (jnl_string *)&rec->jrec_set_kill.mumps_node; key = (gv_key *)key_buff; key->top = MAX_KEY_SZ; key->end = keystr->length; assert(key->end <= key->top); memcpy(key->base, &keystr->text[0], keystr->length); key->base[key->end] = '\0'; key_len = INTCAST((format_targ_key((uchar_ptr_t)asc_key_buff, MAX_ZWR_KEY_SZ, key, FALSE) - (unsigned char *)asc_key_buff)); } /* Check this record against the various selection lists */ if (NULL != mur_options.user) { inc_seen = inc_item_seen = exc_item_seen = FALSE; for (sl_ptr = mur_options.user; NULL != sl_ptr; sl_ptr = sl_ptr->next) { wildcard_match = FALSE; if (!sl_ptr->exclude) inc_seen = TRUE; if (sl_ptr->has_wildcard) wildcard_match = mur_do_wildcard(pv->jpv_user, sl_ptr->buff, JPV_LEN_USER, sl_ptr->len); if (!wildcard_match) { pv_len = real_len(JPV_LEN_USER, (uchar_ptr_t)pv->jpv_user); sl_len = MIN(sl_ptr->len, JPV_LEN_USER); } if (wildcard_match || (pv_len == sl_len) && (0 == memcmp(pv->jpv_user, sl_ptr->buff, sl_len))) { if (sl_ptr->exclude) exc_item_seen = TRUE; else inc_item_seen = TRUE; } } if (exc_item_seen || (inc_seen && !inc_item_seen)) return FALSE; } if ((NULL != mur_options.global) && (NULL != key)) { inc_seen = inc_item_seen = exc_item_seen = FALSE; for (sl_ptr = mur_options.global; NULL != sl_ptr; sl_ptr = sl_ptr->next) { wildcard_match = FALSE; if (!sl_ptr->exclude) inc_seen = TRUE; if (sl_ptr->has_wildcard) wildcard_match = mur_do_wildcard(asc_key_buff, sl_ptr->buff, key_len, sl_ptr->len); i = sl_ptr->len; if (sl_ptr->buff[i - 1] == ')') --i; if (wildcard_match || (key_len == i) && (0 == memcmp(asc_key_buff, sl_ptr->buff, i)) || (key_len > i) && (0 == memcmp(asc_key_buff, sl_ptr->buff, i)) && (('(' == asc_key_buff[i]) || (')' == asc_key_buff[i]) || (',' == asc_key_buff[i]))) { if (sl_ptr->exclude) exc_item_seen = TRUE; else inc_item_seen = TRUE; } } if (exc_item_seen || (inc_seen && !inc_item_seen)) return FALSE; } if (NULL != mur_options.process) { inc_seen = inc_item_seen = exc_item_seen = FALSE; for (sl_ptr = mur_options.process; NULL != sl_ptr; sl_ptr = sl_ptr->next) { wildcard_match = FALSE; if (!sl_ptr->exclude) inc_seen = TRUE; if (sl_ptr->has_wildcard) wildcard_match = mur_do_wildcard(pv->jpv_prcnam, sl_ptr->buff, JPV_LEN_PRCNAM, sl_ptr->len); if (!wildcard_match) { pv_len = real_len(JPV_LEN_PRCNAM, (uchar_ptr_t)pv->jpv_prcnam); sl_len = MIN(sl_ptr->len, JPV_LEN_PRCNAM); } if (wildcard_match || (pv_len == sl_len) && (0 == memcmp(pv->jpv_prcnam, sl_ptr->buff, sl_len))) { if (sl_ptr->exclude) exc_item_seen = TRUE; else inc_item_seen = TRUE; } } if (exc_item_seen || (inc_seen && !inc_item_seen)) return FALSE; } if (NULL != mur_options.id) { inc_seen = inc_item_seen = exc_item_seen = FALSE; for (ll_ptr = mur_options.id; NULL != ll_ptr; ll_ptr = ll_ptr->next) { if (!ll_ptr->exclude) inc_seen = TRUE; if (ll_ptr->num == pv->jpv_pid) { if (ll_ptr->exclude) exc_item_seen = TRUE; else inc_item_seen = TRUE; } } if (exc_item_seen || (inc_seen && !inc_item_seen)) return FALSE; } if (IS_SET_KILL_ZKILL_ZTRIG(rectype)) { if (IS_SET(rectype)) return mur_options.transaction != TRANS_KILLS; else return mur_options.transaction != TRANS_SETS; } return TRUE; }
bool gtcmtr_bufflush(void) { cm_region_list *reg_ref; mval v; short n; unsigned short num_trans, data_len; unsigned char buff[MAX_ZWR_KEY_SZ], *end; unsigned char *ptr, regnum, len, cc, prv; static readonly gds_file_id file; error_def(ERR_KEY2BIG); error_def(ERR_REC2BIG); error_def(ERR_GVIS); ptr = curr_entry->clb_ptr->mbf; assert(*ptr == CMMS_B_BUFFLUSH); ptr++; v.mvtype = MV_STR; GET_USHORT(num_trans, ptr); ptr += sizeof (short); for (; num_trans-- > 0;) { regnum = *ptr++; reg_ref = gtcm_find_region(curr_entry, regnum); len = *ptr++; cc = *ptr++; prv = *ptr++; assert (len + cc - 1 < gv_currkey->top); memcpy(&gv_currkey->base[cc], ptr, len); ptr += len; gv_currkey->end = len + cc - 1; gv_currkey->prev = prv; assert(prv < gv_currkey->end); if ((n = gv_currkey->end + 1) > gv_cur_region->max_key_size) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error(VARLSTCNT(11) ERR_KEY2BIG, 4, n, (int4)gv_cur_region->max_key_size, REG_LEN_STR(gv_cur_region), 0, ERR_GVIS, 2, end - buff, buff); } gtcm_bind_name(reg_ref->reghead, TRUE); if (JNL_ENABLED(cs_addrs->hdr)) { cs_addrs->jnl->pini_addr = reg_ref->pini_addr; originator_prc_vec = curr_entry->pvec; } GET_USHORT(data_len, ptr); ptr += sizeof(short); v.str.len = data_len; v.str.addr = (char *)ptr; if (n + v.str.len + sizeof(rec_hdr) > gv_cur_region->max_rec_size) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error(VARLSTCNT(11) ERR_REC2BIG, 4, n + v.str.len + sizeof(rec_hdr), (int4)gv_cur_region->max_rec_size, REG_LEN_STR(gv_cur_region), 0, ERR_GVIS, 2, end - buff, buff); } gvcst_put(&v); if (JNL_ENABLED(cs_addrs->hdr)) reg_ref->pini_addr = cs_addrs->jnl->pini_addr; /* In case journal switch occurred */ ptr += data_len; } ptr = curr_entry->clb_ptr->mbf; *ptr++ = CMMS_C_BUFFLUSH; curr_entry->clb_ptr->cbl = S_HDRSIZE; return TRUE; }
void op_gvquery (mval *v) { int4 size; unsigned char buff[MAX_ZWR_KEY_SZ], *end, *glob_begin; bool found; enum db_acc_method acc_meth; unsigned char *extnamsrc, *extnamdst, *extnamtop; int maxlen; char extnamdelim[] = "^|\"\"|"; mval val; /* We want to turn QUERY into QUERYGET for all types of access methods so that we can cache the value of the key returned * by $QUERY. The value is very likely to be used shortly after $QUERY - Vinaya, Aug 13, 2001 */ acc_meth = gv_cur_region->dyn.addr->acc_meth; if (gv_curr_subsc_null) { if (0 == gv_cur_region->std_null_coll) gv_currkey->base[gv_currkey->prev] = 01; else { gv_currkey->base[gv_currkey->end++]= 1; gv_currkey->base[gv_currkey->end++] = 0; gv_currkey->base[gv_currkey->end] = 0; } } else { /* Note, gv_currkey->prev isn't changed here. We rely on this in gtcmtr_query to distinguish different forms of the key */ gv_currkey->base[gv_currkey->end++]= 1; gv_currkey->base[gv_currkey->end++] = 0; gv_currkey->base[gv_currkey->end] = 0; } switch (acc_meth) { case dba_bg: case dba_mm: found = ((0 != gv_target->root) ? gvcst_query() : FALSE); /* global does not exist if root is 0 */ break; case dba_cm: found = gvcmx_query(&val); /* val ignored currently - Vinaya Aug 13, 2001*/ break; case dba_usr: found = gvusr_query(v); /* $Q result in v for dba_usr, for others, in gv_altkey */ break; default: assert(FALSE); /* why didn't we cover all access methods? */ found = FALSE; break; } v->mvtype = MV_STR; if (found) { if (acc_meth != dba_usr) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_altkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; size = (int)(end - &buff[0] - 1); /* exclude ^ */ glob_begin = &buff[1]; /* skip ^ */ } else { size = v->str.len - 1; /* exclude ^ */ glob_begin = (unsigned char *)v->str.addr + 1; /* skip ^ */ } /* Need to return a double-quote for every single-quote; assume worst case. */ /* Account for ^ in both cases - extnam and no extnam */ maxlen = size + ((0 == extnam_str.len) ? 1 : ((extnam_str.len * 2) + (int)(STR_LIT_LEN(extnamdelim)))); if ((stringpool.top - stringpool.free) < maxlen) { v->str.len = 0; /* so stp_gcol ignores otherwise incompletely setup mval */ stp_gcol(maxlen); } extnamdst = stringpool.free; *extnamdst++ = extnamdelim[0]; if (extnam_str.len > 0) { *extnamdst++ = extnamdelim[1]; *extnamdst++ = extnamdelim[2]; for (extnamsrc = (unsigned char *)extnam_str.addr, extnamtop = extnamsrc + extnam_str.len; extnamsrc < extnamtop; ) { *extnamdst++ = *extnamsrc; if ('"' == *extnamsrc++) /* caution : pointer increment side-effect */ *extnamdst++ = '"'; } *extnamdst++ = extnamdelim[3]; *extnamdst++ = extnamdelim[4]; extnam_str.len = 0; } memcpy(extnamdst, glob_begin, size); v->str.len = INTCAST(extnamdst - stringpool.free + size); v->str.addr = (char *)stringpool.free; stringpool.free += v->str.len; 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 /* !found */ v->str.len = 0; return; }
/* This routine formats and outputs journal extract records corresponding to M SET, KILL, ZKILL, TSTART, ZTSTART, and ZTRIGGER commands, $ZTRIGGER function (LGTRIG) and $ZTWORMHOLE */ void mur_extract_set(jnl_ctl_list *jctl, fi_type *fi, jnl_record *rec, pini_list_struct *plst) { enum jnl_record_type rectype; int max_blen, actual, extract_len, val_extr_len, val_len; char *val_ptr, *ptr, *buff; jnl_string *keystr; boolean_t do_format2zwr, is_ztstart; if (!mur_options.detail) extract_len = 0; else EXT_DET_COMMON_PREFIX(jctl); rectype = (enum jnl_record_type)rec->prefix.jrec_type; if (IS_FUPD_TUPD(rectype)) { if (!mur_options.detail) { if (IS_TUPD(rectype)) { EXT2BYTES(&muext_code[MUEXT_TSTART][0]); /* TSTART */ is_ztstart = FALSE; } else /* if (IS_FUPD(rectype)) */ { EXT2BYTES(&muext_code[MUEXT_ZTSTART][0]); /* ZTSTART */ is_ztstart = TRUE; } } else { if (IS_TUPD(rectype)) { strcpy(murgbl.extr_buff + extract_len, "TSTART \\"); is_ztstart = FALSE; } else /* if (IS_FUPD(rectype)) */ { strcpy(murgbl.extr_buff + extract_len, "ZTSTART\\"); is_ztstart = TRUE; } extract_len = STRLEN(murgbl.extr_buff); } EXTTIME(rec->prefix.time); EXTQW(rec->prefix.tn); if (mur_options.detail) EXTINT(rec->prefix.checksum); EXTPID(plst); EXTQW(rec->jrec_set_kill.token_seq.jnl_seqno); if (!is_ztstart) EXT_STRM_SEQNO(rec->jrec_set_kill.strm_seqno); jnlext_write(fi, murgbl.extr_buff, extract_len); } /* Output the SET or KILL or ZKILL or ZTWORMHOLE or LGTRIG or ZTRIG record */ if (!mur_options.detail) { extract_len = 0; if (IS_SET(rectype)) { EXT2BYTES(&muext_code[MUEXT_SET][0]); } else if (IS_KILL(rectype)) { EXT2BYTES(&muext_code[MUEXT_KILL][0]); } else if (IS_ZKILL(rectype)) { EXT2BYTES(&muext_code[MUEXT_ZKILL][0]); } else if (IS_ZTWORM(rectype)) { EXT2BYTES(&muext_code[MUEXT_ZTWORM][0]); } else if (IS_LGTRIG(rectype)) { EXT2BYTES(&muext_code[MUEXT_LGTRIG][0]); } else if (IS_ZTRIG(rectype)) { EXT2BYTES(&muext_code[MUEXT_ZTRIG][0]); } else assert(FALSE); /* The assert will disappear in pro but not the ";" to properly terminate the else */ } else { if (IS_FUPD_TUPD(rectype)) { memcpy(murgbl.extr_buff, " ", 23); extract_len = 23; } else extract_len = STRLEN(murgbl.extr_buff); strcpy(murgbl.extr_buff + extract_len, " \\"); memcpy(murgbl.extr_buff + extract_len, jrt_label[rectype], LAB_LEN); extract_len += LAB_LEN; memcpy(murgbl.extr_buff + extract_len, LAB_TERM, LAB_TERM_SZ); extract_len += LAB_TERM_SZ; } EXTTIME(rec->prefix.time); EXTQW(rec->prefix.tn); if (mur_options.detail) EXTINT(rec->prefix.checksum); EXTPID(plst); if (IS_ZTP(rectype)) { EXTQW(rec->jrec_set_kill.token_seq.token); } else EXTQW(rec->jrec_set_kill.token_seq.jnl_seqno); assert(IS_SET_KILL_ZKILL_ZTWORM_LGTRIG_ZTRIG(rectype)); assert(&rec->jrec_set_kill.strm_seqno == &rec->jrec_ztworm.strm_seqno); assert(&rec->jrec_set_kill.strm_seqno == &rec->jrec_lgtrig.strm_seqno); EXT_STRM_SEQNO(rec->jrec_set_kill.strm_seqno); assert(&rec->jrec_set_kill.update_num == &rec->jrec_ztworm.update_num); assert(&rec->jrec_set_kill.update_num == &rec->jrec_lgtrig.update_num); EXTINT(rec->jrec_set_kill.update_num); do_format2zwr = FALSE; if (IS_SET_KILL_ZKILL_ZTRIG(rectype)) { keystr = (jnl_string *)&rec->jrec_set_kill.mumps_node; EXTINT(keystr->nodeflags); buff = &murgbl.extr_buff[extract_len]; max_blen = MIN(MAX_ZWR_KEY_SZ, murgbl.max_extr_record_length - extract_len); assert(MAX_ZWR_KEY_SZ == max_blen); /* We allocated enough for key and data expansion for ZWR format */ ptr = (char *)format_targ_key((uchar_ptr_t)buff, max_blen, gv_currkey, TRUE); assert(NULL != ptr); if (NULL != ptr) extract_len += (int)(ptr - &murgbl.extr_buff[extract_len]); if (IS_SET(rectype)) { murgbl.extr_buff[extract_len++] = '='; val_ptr = &keystr->text[keystr->length]; GET_MSTR_LEN(val_len, val_ptr); val_ptr += SIZEOF(mstr_len_t); do_format2zwr = TRUE; } } else if (IS_ZTWORM(rectype) || IS_LGTRIG(rectype)) { assert(&rec->jrec_ztworm.ztworm_str == &rec->jrec_lgtrig.lgtrig_str); keystr = (jnl_string *)&rec->jrec_ztworm.ztworm_str; val_len = keystr->length; val_ptr = &keystr->text[0]; do_format2zwr = TRUE; } if (do_format2zwr) { if (ZWR_EXP_RATIO(val_len) <= murgbl.max_extr_record_length - extract_len) { ptr = &murgbl.extr_buff[extract_len]; format2zwr((sm_uc_ptr_t)val_ptr, val_len, (unsigned char *)ptr, &val_extr_len); extract_len += val_extr_len; } else { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Length of the record is too high for zwr format")); if (mur_options.verbose || mur_options.detail) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUINFOUINT4, 4, LEN_AND_LIT("After max expansion record length"), ZWR_EXP_RATIO(val_len), ZWR_EXP_RATIO(val_len)); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUINFOUINT4, 4, LEN_AND_LIT("Buffer size"), murgbl.max_extr_record_length - extract_len, murgbl.max_extr_record_length - extract_len); } assert(FALSE); } } murgbl.extr_buff[extract_len++] = '\\'; jnlext_write(fi, murgbl.extr_buff, extract_len); }
void gvcmz_doop(unsigned char query_code, unsigned char reply_code, mval *v) { unsigned char *ptr; short len, temp_short; int4 status, max_reply_len; struct CLB *lnk; unsigned char buff[MAX_ZWR_KEY_SZ], *end; error_def(ERR_BADSRVRNETMSG); error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); error_def(ERR_GVIS); lnk = gv_cur_region->dyn.addr->cm_blk; if (!((link_info *)lnk->usr)->server_supports_long_names && (PRE_V5_MAX_MIDENT_LEN < strlen((char *)gv_currkey->base))) { end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE); rts_error(VARLSTCNT(14) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM server does not support global names longer than 8 characters"), ERR_GVIS, 2, end - buff, buff, ERR_TEXT, 2, DB_LEN_STR(gv_cur_region)); } lnk->ast = 0; /* all database queries are sync */ lnk->cbl = 1 + /* HDR */ gv_currkey->end + /* key */ sizeof(unsigned short) + /* gv_key.top */ sizeof(unsigned short) + /* gv_key.end */ sizeof(unsigned short) + /* gv_key.prev */ sizeof(unsigned char) + /* gv_key.base */ sizeof(unsigned char) + /* regnum */ sizeof(unsigned short); /* size for variable len SUBSC */ /* the current GT.CM maximum message buffer length is bounded by the size of a short which is 64K. but the * calculation below of lnk->cbl and max_reply_len takes into account the fact that the value that is sent in as * input or read in from the server side can be at most MAX_DBSTRLEN in size. therefore, there is a dependency * that MAX_DBSTRLEN always be less than the GT.CM maximum message buffer length. to ensure this is always the * case, the following assert is added so that whenever MAX_DBSTRLEN is increased, we will fail this assert * and reexamine the code below. */ assert(sizeof(lnk->cbl) == 2); /* assert it is a short. when it becomes a uint4 the assert can be removed * if the macro CM_MAX_BUF_LEN (used below) is changed appropriately */ assert(MAX_DBSTRLEN == (32 * 1024 - 1)); if (CMMS_Q_PUT == query_code || CMMS_Q_INCREMENT == query_code) { if (CMMS_Q_INCREMENT == query_code) { /* 1-byte boolean value of "undef_inhibit" passed to the server for $INCREMENT although, effective V5.0-000, undef_inhibit is no longer relevant as $INCREMENT() implicitly does a $GET() on the global. We keep this byte to ensure compatibility with V5.0-FT01 */ lnk->cbl++; } assert((uint4)lnk->cbl + sizeof(unsigned short) + (uint4)MAX_DBSTRLEN <= (uint4)CM_MAX_BUF_LEN); lnk->cbl += (sizeof(unsigned short) + v->str.len); /* VALUE + length */ } if ((CMMS_Q_GET == query_code) || (CMMS_Q_INCREMENT == query_code) || (CMMS_Q_QUERY == query_code) && ((link_info *)lnk->usr)->query_is_queryget) max_reply_len = lnk->mbl + SIZEOF(unsigned short) + MAX_DBSTRLEN; /* can't predict the length of data value */ else max_reply_len = lnk->mbl; assert(max_reply_len <= (int4)CM_MAX_BUF_LEN); if (stringpool.top < stringpool.free + max_reply_len) stp_gcol(max_reply_len); lnk->mbf = stringpool.free; ptr = lnk->mbf; *ptr++ = query_code; /* temp_short = gv_currkey->end + sizeof(gv_key) + 1; */ temp_short = gv_currkey->end + sizeof(unsigned short) + sizeof(unsigned short) + sizeof(unsigned short) + sizeof(char) + 1; CM_PUT_SHORT(ptr, temp_short, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(short); *ptr++ = gv_cur_region->cmx_regnum; CM_PUT_SHORT(ptr, gv_currkey->top, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(short); CM_PUT_SHORT(ptr, gv_currkey->end, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(short); CM_PUT_SHORT(ptr, gv_currkey->prev, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(short); memcpy(ptr, gv_currkey->base, gv_currkey->end + 1); if (CMMS_Q_PUT == query_code || CMMS_Q_INCREMENT == query_code) { ptr += gv_currkey->end + 1; temp_short = (short)v->str.len; assert((int4)temp_short == v->str.len); /* short <- int4 assignment lossy? */ CM_PUT_SHORT(ptr, temp_short, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(short); memcpy(ptr,v->str.addr, v->str.len); if (CMMS_Q_INCREMENT == query_code) { /* UNDEF flag is no longer relevant, but set the flag to ensure compatibility with V5.0-FT01 */ assert(sizeof(undef_inhibit) == 1); ptr[v->str.len] = (unsigned char)undef_inhibit; } } status = cmi_write(lnk); if (CMI_ERROR(status)) { ((link_info *)(lnk->usr))->neterr = TRUE; gvcmz_error(query_code, status); return; } status = cmi_read(lnk); if (CMI_ERROR(status)) { ((link_info *)(lnk->usr))->neterr = TRUE; gvcmz_error(query_code, status); return; } ptr = lnk->mbf; if (CMMS_Q_PUT == query_code || CMMS_Q_ZWITHDRAW == query_code || CMMS_Q_KILL == query_code) { if (reply_code != *ptr) { if (*ptr != CMMS_E_ERROR) rts_error(VARLSTCNT(1) ERR_BADSRVRNETMSG); gvcmz_errmsg(lnk,FALSE); } return; } if (reply_code != *ptr) { if ((CMMS_R_UNDEF != *ptr) || ((CMMS_Q_GET != query_code) && (CMMS_Q_INCREMENT != query_code))) { if (CMMS_E_ERROR != *ptr) rts_error(VARLSTCNT(1) ERR_BADSRVRNETMSG); gvcmz_errmsg(lnk, FALSE); } if (CMMS_Q_INCREMENT == query_code) v->mvtype = 0; /* set the result to be undefined */ return; } ptr++; if (CMMS_R_DATA == reply_code) { CM_GET_SHORT(temp_short, ptr, ((link_info *)(lnk->usr))->convert_byteorder); if (1 != temp_short) rts_error(VARLSTCNT(1) ERR_BADSRVRNETMSG); ptr += sizeof(short); status = *ptr; /* Temp assignment to status gets rid of compiler warning in MV_FORCE_MVAL macro */ MV_FORCE_MVAL(v, status); return; } if (reply_code == CMMS_R_PREV || reply_code == CMMS_R_QUERY || reply_code == CMMS_R_ORDER) { CM_GET_SHORT(len, ptr, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(short); if (1 == len) { MV_FORCE_MVAL(v, 0); } else { if (*ptr++ != gv_cur_region->cmx_regnum) rts_error(VARLSTCNT(1) ERR_BADSRVRNETMSG); /* memcpy(gv_altkey, ptr, len - 1); */ CM_GET_USHORT(gv_altkey->top, ptr, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(unsigned short); CM_GET_USHORT(gv_altkey->end, ptr, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(unsigned short); CM_GET_USHORT(gv_altkey->prev, ptr, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(unsigned short); memcpy(gv_altkey->base, ptr, len - 1 - sizeof(unsigned short) - sizeof(unsigned short) - sizeof(unsigned short)); ptr += (len - 1 - sizeof(unsigned short) - sizeof(unsigned short) - sizeof(unsigned short)); MV_FORCE_MVAL(v, 1); } if (CMMS_R_QUERY != reply_code || 1 == len || !((link_info *)lnk->usr)->query_is_queryget) { if (CMMS_R_QUERY == reply_code && ((link_info *)lnk->usr)->query_is_queryget) v->mvtype = 0; /* force undefined to distinguish $Q returning "" from value of QUERYGET being 0 */ return; } } assert(CMMS_R_GET == reply_code || CMMS_R_INCREMENT == reply_code || CMMS_R_QUERY == reply_code && ((link_info *)lnk->usr)->query_is_queryget && 1 < len); CM_GET_SHORT(len, ptr, ((link_info *)(lnk->usr))->convert_byteorder); ptr += sizeof(unsigned short); assert(ptr >= stringpool.base && ptr + len < stringpool.top); /* incoming message is in stringpool */ v->mvtype = MV_STR; v->str.len = len; v->str.addr = (char *)stringpool.free; /* we don't need the reply msg anymore, can overwrite reply */ memcpy(v->str.addr, ptr, len); /* so that we don't leave a gaping hole in the stringpool */ stringpool.free += len; return; }
bool gtcmtr_put(void) { cm_region_list *reg_ref; mval v; unsigned char buff[MAX_ZWR_KEY_SZ], *end; unsigned char *ptr, regnum; short n; unsigned short top, len; static readonly gds_file_id file; error_def(ERR_KEY2BIG); error_def(ERR_REC2BIG); error_def(ERR_GVIS); error_def(ERR_DBPRIVERR); ptr = curr_entry->clb_ptr->mbf; assert(*ptr == CMMS_Q_PUT); ptr++; GET_USHORT(len, ptr); ptr += SIZEOF(unsigned short); regnum = *ptr++; reg_ref = gtcm_find_region(curr_entry,regnum); len--; /* subtract size of regnum */ CM_GET_GVCURRKEY(ptr, len); gtcm_bind_name(reg_ref->reghead, TRUE); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region)); if (JNL_ALLOWED(cs_addrs)) { /* we need to copy client's specific prc_vec into the global variable in order that the gvcst* routines * do the right job. actually we need to do this only if JNL_ENABLED(cs_addrs), but since it is not * easy to re-execute the following two assignments in case gvcst_put()'s call to t_end() encounters a * cdb_sc_jnlstatemod retry code, we choose the easier approach of executing the following segment * if JNL_ALLOWED(cs_addrs) is TRUE instead of checking for JNL_ENABLED(cs_addrs) to be TRUE. * this approach has the overhead that we will be doing the following assignments even though JNL_ENABLED * might not be TRUE but since the following two are just pointer copies, it is not considered a big overhead. * this approach ensures that the jnl_put_jrt_pini() gets the appropriate prc_vec for writing into the * journal record in case JNL_ENABLED turns out to be TRUE in t_end() time. * note that the value of JNL_ALLOWED(cs_addrs) cannot be changed on the fly without obtaining standalone access * and hence the correctness of prc_vec (whenever it turns out necessary) is guaranteed. */ originator_prc_vec = curr_entry->pvec; cs_addrs->jnl->pini_addr = reg_ref->pini_addr; } GET_USHORT(len, ptr); ptr += SIZEOF(unsigned short); v.mvtype = MV_STR; v.str.len = len; v.str.addr = (char *)ptr; if ((n = gv_currkey->end + 1) > gv_cur_region->max_key_size) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error(VARLSTCNT(11) ERR_KEY2BIG, 4, n, (int4)gv_cur_region->max_key_size, REG_LEN_STR(gv_cur_region), 0, ERR_GVIS, 2, end - buff, buff); } if (n + v.str.len + SIZEOF(rec_hdr) > gv_cur_region->max_rec_size) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, n + v.str.len + SIZEOF(rec_hdr), (int4)gv_cur_region->max_rec_size, REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, end - buff, buff); } gvcst_put(&v); if (JNL_ALLOWED(cs_addrs)) reg_ref->pini_addr = cs_addrs->jnl->pini_addr; /* In case journal switch occurred */ ptr = curr_entry->clb_ptr->mbf; *ptr++ = CMMS_R_PUT; curr_entry->clb_ptr->cbl = S_HDRSIZE; return TRUE; }