/**************************************************************** * * * Copyright 2010, 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" #ifdef GTM_TRIGGER #include "gtm_stdio.h" #include "gtm_string.h" #include "nametabtyp.h" #include "namelook.h" #include "op.h" #include "util.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "error.h" #include "filestruct.h" #include "gdscc.h" #include "gdskill.h" #include "jnl.h" #include "io.h" #include "hashtab_str.h" #include "gv_trigger.h" #include "trigger.h" #include "trigger_update_protos.h" #include "trigger_select_protos.h" #include "trigger_trgfile_protos.h" GBLREF sgmnt_data_ptr_t cs_data; GBLREF uint4 dollar_tlevel; GBLREF gd_addr *gd_header; GBLREF gd_binding *gd_map; GBLREF gd_region *gv_cur_region; GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; GBLREF boolean_t dollar_ztrigger_invoked; GBLREF int4 gtm_trigger_depth; GBLREF mstr *dollar_ztname; LITREF mval literal_zero; LITREF mval literal_one; STATICDEF char save_currkey[SIZEOF(gv_key) + SIZEOF(short) + DBKEYSIZE(MAX_KEY_SZ)]; /* SIZEOF(short) for alignment */ STATICDEF gd_addr *save_gd_header; STATICDEF gd_binding *save_gd_map; STATICDEF gv_key *save_gv_currkey; STATICDEF gv_namehead *save_gv_target; STATICDEF gd_region *save_gv_cur_region; STATICDEF boolean_t save_gv_last_subsc_null, save_gv_some_subsc_null; #ifdef DEBUG STATICDEF boolean_t in_op_fnztrigger; #endif error_def(ERR_FILENAMETOOLONG); error_def(ERR_ZTRIGINVACT); error_def(ERR_DZTRIGINTRIG); enum ztrprms { ZTRP_FILE, /* $ZTRIGGER() FILE parameter - process given file of triggers */ ZTRP_ITEM, /* $ZTRIGGER() ITEM parameter - process single line of trigger file */ ZTRP_SELECT /* $ZTRIGGER() SELECT parameter - perform mupip trigger select with given parms */ }; LITDEF nametabent ztrprm_names[] = { {1, "F"}, {4, "FILE"}, {1, "I"}, {4, "ITEM"}, {1, "S"}, {6, "SELECT"} }; LITDEF unsigned char ztrprm_index[27] = { 0, 0, 0, 0, 0, 0, 2, 2, 2, /* a b c d e f g h i */ 4, 4, 4, 4, 4, 4, 4, 4, 4, /* j k l m n o p q r */ 4, 6, 6, 6, 6, 6, 6, 6, 6 /* s t u v w x y z ~ */ }; LITDEF enum ztrprms ztrprm_data[] = { ZTRP_FILE, ZTRP_FILE, ZTRP_ITEM, ZTRP_ITEM, ZTRP_SELECT, ZTRP_SELECT }; /* reset global variables from the values noted down at op_fnztrigger entry */ #define RESTORE_ZTRIGGER_ENTRY_STATE \ { \ unsigned short top; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ /* Reset global variables noted down at function entry */ \ gd_map = save_gd_map; \ gd_header = save_gd_header; \ if (NULL != save_gv_cur_region) \ { \ gv_cur_region = save_gv_cur_region; \ TP_CHANGE_REG(gv_cur_region); \ } \ gv_target = save_gv_target; \ if (NULL != save_gv_currkey) \ { /* gv_currkey->top could have changed if we opened a database with bigger keysize \ * inside the trigger* functions above. Therefore take care not to overwrite that \ * part of the gv_currkey structure. Restore everything else. \ */ \ top = gv_currkey->top; \ memcpy(gv_currkey, save_gv_currkey, SIZEOF(gv_key) + save_gv_currkey->end); \ gv_currkey->top = top; \ } else if (NULL != gv_currkey) \ { \ gv_currkey->end = 0; \ gv_currkey->base[0] = KEY_DELIMITER; \ TREF(gv_last_subsc_null) = save_gv_last_subsc_null; \ TREF(gv_some_subsc_null) = save_gv_some_subsc_null; \ } \ DEBUG_ONLY(in_op_fnztrigger = FALSE); \ } /* In case of an rts_error deep inside the op_fnztrigger invocation, we need to restore certain global variables that could * have been modified. */ CONDITION_HANDLER(op_fnztrigger_ch) { START_CH; RESTORE_ZTRIGGER_ENTRY_STATE; NEXTCH; } void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst) { int inparm_len, index; uint4 dummy_stats[NUM_STATS], filename_len; boolean_t failed; char filename[MAX_FN_LEN + 1]; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(FALSE == in_op_fnztrigger); /* $ZTRIGGER() should not nest */ DEBUG_ONLY(in_op_fnztrigger = TRUE); /* $ZTRIGGER() is not allowed while already inside the trigger frame */ if (0 < gtm_trigger_depth) { DEBUG_ONLY(in_op_fnztrigger = FALSE); rts_error(VARLSTCNT(4) ERR_DZTRIGINTRIG, 2, dollar_ztname->len, dollar_ztname->addr); } MV_FORCE_STR(func); MV_FORCE_STR(arg1); /* MV_FORCE_STR(arg2); optional arg2 not currently used - added so parm easily implemented when added */ inparm_len = func->str.len; if ((0 >= inparm_len) || (NAME_ENTRY_SZ < inparm_len) || !ISALPHA_ASCII(func->str.addr[0])) { DEBUG_ONLY(in_op_fnztrigger = FALSE;) /* We have a wrong-sized keyword */ rts_error(VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 1); } if (0 > (index = namelook(ztrprm_index, ztrprm_names, func->str.addr, inparm_len))) /* Note assignment */ { DEBUG_ONLY(in_op_fnztrigger = FALSE); /* Specified parm was not found */ rts_error(VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 1); } if ((0 < arg1->str.len) && (0 == arg1->str.addr[0])) { DEBUG_ONLY(in_op_fnztrigger = FALSE); /* 2nd parameter is invalid */ rts_error(VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2); } save_gd_header = gd_header; save_gv_target = gv_target; save_gd_map = gd_map; save_gv_cur_region = gv_cur_region; if (NULL != gv_currkey) { /* Align save_gv_currkey on a "short" boundary, but first we check that field "gv_currkey->end" is truly short */ assert(SIZEOF(short) == SIZEOF(save_gv_currkey->end)); save_gv_currkey = (gv_key *)ROUND_UP2((INTPTR_T)&save_currkey[0], SIZEOF(gv_currkey->end)); memcpy(save_gv_currkey, gv_currkey, SIZEOF(gv_key) + gv_currkey->end); save_gv_last_subsc_null = TREF(gv_last_subsc_null); save_gv_some_subsc_null = TREF(gv_some_subsc_null); } else save_gv_currkey = NULL; util_out_print(NULL, RESET); /* Make sure the util_out_print_gtmio() messages start at the beginning of the buffer * in case there are any stale messages already in the buffer - for example rts_error * output left over from a trapped error and hence not printed */ /* Any time gv_currkey is manipulated, the global variables - gv_last_subsc_null and gv_some_subsc_null should also be * set appropriately. Although the BUILD_HASHT_*_CURRKEY_T macros maintain this property, the * INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED macro does not maintain the global variables. Since the macro is used in various * other places (including update process and GT.M runtime), the implications of setting the global variables is not * clear. So, reset gv_currkey and the global variables at the $ztrigger() entry as they will be restored before exiting * from this function. */ if (gv_currkey) { gv_currkey->end = 0; gv_currkey->base[0] = KEY_DELIMITER; } TREF(gv_last_subsc_null) = TREF(gv_some_subsc_null) = FALSE; ESTABLISH(op_fnztrigger_ch); dollar_ztrigger_invoked = TRUE; /* reset after use when the transaction commits, restarts or rollbacks */ switch(ztrprm_data[index]) { case ZTRP_FILE: if (0 == arg1->str.len) /* 2nd parameter is missing */ rts_error(VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2); if (MAX_FN_LEN < arg1->str.len) rts_error(VARLSTCNT(1) ERR_FILENAMETOOLONG); /* The file name is in string pool so make a local copy in case GC happens */ strncpy(filename, arg1->str.addr, arg1->str.len); filename_len = arg1->str.len; filename[filename_len] = '\0'; failed = trigger_trgfile_tpwrap(filename, filename_len, TRUE); break; case ZTRP_ITEM: if (0 == arg1->str.len) /* 2nd parameter is missing */ rts_error(VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2); failed = trigger_update(arg1->str.addr, arg1->str.len); break; case ZTRP_SELECT: failed = (TRIG_FAILURE == trigger_select(arg1->str.addr, arg1->str.len, NULL, 0)); break; default: GTMASSERT; /* Should never happen with checks above */ } REVERT; RESTORE_ZTRIGGER_ENTRY_STATE; memcpy(dst, (failed ? &literal_zero : &literal_one), SIZEOF(mval)); return; } #else /* !GTM_TRIGGER */ void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst) { error_def(ERR_UNIMPLOP); rts_error(VARLSTCNT(1) ERR_UNIMPLOP); } #endif