169 lines
6.0 KiB
C
169 lines
6.0 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2010, 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"
|
||
|
|
||
|
#ifdef GTM_TRIGGER
|
||
|
#include "gdsroot.h" /* for gdsfhead.h */
|
||
|
#include "gdsbt.h" /* for gdsfhead.h */
|
||
|
#include "gdsfhead.h"
|
||
|
#include "gvcst_protos.h"
|
||
|
#include "rtnhdr.h"
|
||
|
#include "gv_trigger.h"
|
||
|
#include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro (within BUILD_HASHT_...) */
|
||
|
#include "gvsub2str.h" /* for COPY_SUBS_TO_GVCURRKEY */
|
||
|
#include "format_targ_key.h" /* for COPY_SUBS_TO_GVCURRKEY */
|
||
|
#include "op.h"
|
||
|
#include "trigger.h"
|
||
|
#include "trigger_gbl_fill_xecute_buffer.h"
|
||
|
#include "mvalconv.h"
|
||
|
#include "memcoherency.h"
|
||
|
#include "t_retry.h"
|
||
|
#include "gtmimagename.h"
|
||
|
|
||
|
LITREF mval literal_ten;
|
||
|
|
||
|
error_def(ERR_TRIGDEFBAD);
|
||
|
error_def(ERR_GTMASSERT);
|
||
|
error_def(ERR_ASSERT);
|
||
|
error_def(ERR_GTMCHECK);
|
||
|
error_def(ERR_MEMORY);
|
||
|
error_def(ERR_OUTOFSPACE);
|
||
|
|
||
|
GBLREF sgmnt_data_ptr_t cs_data;
|
||
|
GBLREF sgmnt_addrs *cs_addrs;
|
||
|
GBLREF gd_region *gv_cur_region;
|
||
|
GBLREF gv_key *gv_currkey;
|
||
|
GBLREF uint4 dollar_tlevel;
|
||
|
GBLREF unsigned int t_tries;
|
||
|
|
||
|
STATICDEF char *xecute_buff;
|
||
|
|
||
|
STATICFNDCL CONDITION_HANDLER(trigger_gbl_fill_xecute_buffer_ch);
|
||
|
|
||
|
/* The trigger_gbl_fill_xecute_buffer() routine below malloc()s storage for our trigger buffer buffer below but any one
|
||
|
* of the various database calls can cause a restart that "loses" the buffer. So we wrap the call will this condition
|
||
|
* handler to release the buffer if one was allocated before moving on to the next handler.
|
||
|
*/
|
||
|
STATICFNDEF CONDITION_HANDLER(trigger_gbl_fill_xecute_buffer_ch)
|
||
|
{
|
||
|
START_CH;
|
||
|
if (!DUMPABLE && (NULL != xecute_buff))
|
||
|
free(xecute_buff);
|
||
|
NEXTCH;
|
||
|
}
|
||
|
|
||
|
char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_index, mval *first_rec, int4 *xecute_len)
|
||
|
{
|
||
|
mval data_val;
|
||
|
boolean_t have_value;
|
||
|
mval index, key_val, *val_ptr;
|
||
|
int4 len, xecute_buff_len;
|
||
|
int4 num;
|
||
|
int4 trgindx;
|
||
|
unsigned char util_buff[MAX_TRIG_UTIL_LEN];
|
||
|
int4 util_len;
|
||
|
char *xecute_buff_ptr;
|
||
|
mval xecute_index;
|
||
|
DEBUG_ONLY(int gvt_cycle;)
|
||
|
DEBUG_ONLY(int csd_cycle;)
|
||
|
DCL_THREADGBL_ACCESS;
|
||
|
|
||
|
SETUP_THREADGBL_ACCESS;
|
||
|
/* assert(0 < dollar_tlevel); Too be added later when it stops breaking MUPIP SELECT & $ZTRIGGER("SELECT"..) */
|
||
|
xecute_buff = NULL;
|
||
|
ESTABLISH_RET(trigger_gbl_fill_xecute_buffer_ch, NULL);
|
||
|
index = *trig_index;
|
||
|
if (NULL != first_rec)
|
||
|
{
|
||
|
xecute_buff_len = first_rec->str.len;
|
||
|
assert(MAX_XECUTE_LEN >= xecute_buff_len);
|
||
|
xecute_buff = malloc(xecute_buff_len);
|
||
|
memcpy(xecute_buff, first_rec->str.addr, xecute_buff_len);
|
||
|
} else
|
||
|
{ /* First check for a single record xecute string */
|
||
|
BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN);
|
||
|
if (gvcst_get(&data_val))
|
||
|
{
|
||
|
xecute_buff_len = data_val.str.len;
|
||
|
assert(MAX_XECUTE_LEN >= xecute_buff_len);
|
||
|
xecute_buff = malloc(xecute_buff_len);
|
||
|
memcpy(xecute_buff, data_val.str.addr, xecute_buff_len);
|
||
|
*xecute_len = xecute_buff_len;
|
||
|
REVERT;
|
||
|
return xecute_buff;
|
||
|
} else
|
||
|
{ /* No single line trigger exists. See if multi-line trigger exists. The form is ^#t(gbl,indx,XECUTE,n)
|
||
|
* so can be easily tested for with $DATA().
|
||
|
*/
|
||
|
op_gvdata(&data_val);
|
||
|
if ((literal_ten.m[0] != data_val.m[0]) || (literal_ten.m[1] != data_val.m[1]))
|
||
|
{ /* The process' view of the triggers is likely stale. Restart to be safe.
|
||
|
* Triggers can be invoked only by GT.M and Update process. Out of these, we expect only
|
||
|
* GT.M to see restarts due to concurrent trigger changes. Update process is the only
|
||
|
* updater on the secondary so we dont expect it to see any concurrent trigger changes
|
||
|
* Assert accordingly. Note similar asserts occur in t_end.c and tp_tend.c.
|
||
|
*/
|
||
|
assert(CDB_STAGNATE > t_tries);
|
||
|
assert(IS_GTM_IMAGE);
|
||
|
/* Assert that the cycle has changed but in order to properly do the assert, we need a memory
|
||
|
* barrier since cs_data->db_trigger_cycle could be stale in our cache.
|
||
|
*/
|
||
|
DEBUG_ONLY(SHM_READ_MEMORY_BARRIER);
|
||
|
/* Vars in locals so can look at them in the core instead of at constantly changing numbers */
|
||
|
DEBUG_ONLY(gvt_cycle = gv_target->db_trigger_cycle);
|
||
|
DEBUG_ONLY(csd_cycle = cs_data->db_trigger_cycle);
|
||
|
assert(csd_cycle > gvt_cycle);
|
||
|
t_retry(cdb_sc_triggermod);
|
||
|
}
|
||
|
}
|
||
|
/* Multi-line triggers exist */
|
||
|
num = 0;
|
||
|
i2mval(&xecute_index, num);
|
||
|
BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN, xecute_index);
|
||
|
if (!gvcst_get(&key_val))
|
||
|
{ /* There has to be an XECUTE string */
|
||
|
assert(FALSE);
|
||
|
trgindx = mval2i(&index);
|
||
|
SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\"");
|
||
|
rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, trigvn_len, trigvn, util_len, util_buff);
|
||
|
}
|
||
|
val_ptr = &key_val;
|
||
|
xecute_buff_len = mval2i(val_ptr);
|
||
|
assert(MAX_XECUTE_LEN >= xecute_buff_len);
|
||
|
xecute_buff_ptr = xecute_buff = malloc(xecute_buff_len);
|
||
|
len = 0;
|
||
|
while (len < xecute_buff_len)
|
||
|
{
|
||
|
i2mval(&xecute_index, ++num);
|
||
|
BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN,
|
||
|
xecute_index);
|
||
|
if (!gvcst_get(&key_val))
|
||
|
break;
|
||
|
if (xecute_buff_len < (len + key_val.str.len))
|
||
|
{ /* The DB string total is longer than the length stored at index 0 -- something is wrong */
|
||
|
free(xecute_buff);
|
||
|
assert(FALSE);
|
||
|
SET_PARAM_STRING(util_buff, util_len, num, ",\"XECUTE\"");
|
||
|
rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, trigvn_len, trigvn, util_len,
|
||
|
util_buff);
|
||
|
}
|
||
|
memcpy(xecute_buff_ptr, key_val.str.addr, key_val.str.len);
|
||
|
xecute_buff_ptr += key_val.str.len;
|
||
|
len += key_val.str.len;
|
||
|
}
|
||
|
}
|
||
|
*xecute_len = xecute_buff_len;
|
||
|
REVERT;
|
||
|
return xecute_buff;
|
||
|
}
|
||
|
#endif
|