boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats) { sgmnt_addrs *csa; char curr_name[MAX_MIDENT_LEN + 1]; uint4 curr_name_len, orig_name_len; mval mv_curr_nam; char *ptr; char *name_tail_ptr; char save_name[MAX_MIDENT_LEN + 1]; gv_key save_currkey[DBKEYALLOC(MAX_KEY_SZ)]; gd_region *save_gv_cur_region, *lgtrig_reg; gv_namehead *save_gv_target; sgm_info *save_sgm_info_ptr; mval trig_gbl; mval *trigger_count; char trigvn[MAX_MIDENT_LEN + 1]; int trigvn_len; int trig_indx; int badpos; boolean_t wildcard; char utilprefix[1024]; int utilprefixlen; boolean_t first_gtmio; uint4 triggers_deleted; mval trigjrec; boolean_t jnl_format_done; gd_region *reg, *reg_top; char disp_trigvn[MAX_MIDENT_LEN + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1 + 1]; /* SPANREG_REGION_LITLEN for " (region ", MAX_RN_LEN for region name, * 1 for ")" and 1 for trailing '\0'. */ int disp_trigvn_len; int trig_protected_mval_push_count; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; badpos = 0; trigjrec.mvtype = MV_STR; trigjrec.str.len = trigger_name_len--; trigjrec.str.addr = trigger_name++; orig_name_len = trigger_name_len; if ((0 == trigger_name_len) || (trigger_name_len != (badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard)))) { /* is the input name valid */ CONV_STR_AND_PRINT("Invalid trigger NAME string: ", orig_name_len, trigger_name); /* badpos is the string position where the bad character was found, pretty print it */ trig_stats[STATS_ERROR_TRIGFILE]++; return TRIG_FAILURE; } name_tail_ptr = trigger_name + trigger_name_len - 1; if ((TRIGNAME_SEQ_DELIM == *name_tail_ptr) || wildcard) trigger_name_len--; /* drop the trailing # sign for wildcard */ jnl_format_done = FALSE; lgtrig_reg = NULL; first_gtmio = TRUE; triggers_deleted = 0; assert(trigger_name_len < MAX_MIDENT_LEN); memcpy(save_name, trigger_name, trigger_name_len); save_name[trigger_name_len] = '\0'; utilprefixlen = ARRAYSIZE(utilprefix); trig_protected_mval_push_count = 0; INCR_AND_PUSH_MV_STENT(trigger_count); /* Protect trigger_count from garbage collection */ for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++) { GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg); csa = cs_addrs; if (NULL == csa) /* not BG or MM access method */ continue; /* gv_target now points to ^#t in region "reg" */ /* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */ if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa)) lgtrig_reg = reg; if (!gv_target->root) continue; memcpy(curr_name, save_name, trigger_name_len); curr_name_len = trigger_name_len; do { /* GVN = $get(^#t("#TNAME",curr_name)) */ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len); if (gvcst_get(&trig_gbl)) { if (reg->read_only) rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg)); SAVE_TRIGGER_REGION_INFO(save_currkey); ptr = trig_gbl.str.addr; trigvn_len = MIN(trig_gbl.str.len, MAX_MIDENT_LEN); STRNLEN(ptr, trigvn_len, trigvn_len); ptr += trigvn_len; if ((trig_gbl.str.len == trigvn_len) || ('\0' != *ptr)) { /* We expect $c(0) in the middle of ptr. If not found, this is a restartable situation */ if (CDB_STAGNATE > t_tries) t_retry(cdb_sc_triggermod); assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), curr_name_len, curr_name); } memcpy(trigvn, trig_gbl.str.addr, trigvn_len); /* the index is just beyond the length of the GVN string */ ptr++; A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx); if (1 > trig_indx) { /* Trigger indexes start from 1 */ if (CDB_STAGNATE > t_tries) t_retry(cdb_sc_triggermod); assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), curr_name_len, curr_name); } SET_DISP_TRIGVN(reg, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len); /* $get(^#t(GVN,"COUNT") */ BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT)); if (!gvcst_get(trigger_count)) { UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen); util_out_print_gtmio("Trigger named !AD exists in the lookup table, " "but global ^!AD has no triggers", FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn); trig_stats[STATS_ERROR_TRIGFILE]++; RETURN_AND_POP_MVALS(TRIG_FAILURE); } if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa)) { jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0); jnl_format_done = TRUE; } /* kill the target trigger for GVN at index trig_indx */ if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, trigger_count, trig_indx))) { UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen); util_out_print_gtmio("Trigger named !AD exists in the lookup table for global ^!AD," \ " but was not deleted!", FLUSH, orig_name_len, trigger_name, disp_trigvn_len, disp_trigvn); trig_stats[STATS_ERROR_TRIGFILE]++; RETURN_AND_POP_MVALS(TRIG_FAILURE); } else { csa->incr_db_trigger_cycle = TRUE; trigger_incr_cycle(trigvn, trigvn_len); /* ^#t records changed, increment cycle */ if (dollar_ztrigger_invoked) { /* Increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this * transaction, on this region, will re-read triggers. See trigger_update.c * for a comment on why it is okay for db_dztrigger_cycle to be incremented * more than once in the same transaction. */ csa->db_dztrigger_cycle++; } trig_stats[STATS_DELETED]++; if (0 == trig_stats[STATS_ERROR_TRIGFILE]) { UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen); util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD", FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn); } } trigger_count->mvtype = 0; /* allow stp_gcol to release the current contents if necessary */ RESTORE_TRIGGER_REGION_INFO(save_currkey); triggers_deleted++; } if (!wildcard) /* not a wild card, don't $order for the next match */ break; op_gvorder(&mv_curr_nam); if (0 == mv_curr_nam.str.len) break; assert(mv_curr_nam.str.len < MAX_MIDENT_LEN); memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len); curr_name_len = mv_curr_nam.str.len; if (0 != memcmp(curr_name, save_name, trigger_name_len)) /* stop when gv_order returns a string that no longer starts save_name */ break; } while (TRUE); } DECR_AND_POP_MV_STENT(); if (!jnl_format_done && (NULL != lgtrig_reg)) { /* There was no journaled region that had a ^#t update, but found at least one journaled region * so write a LGTRIG logical jnl record there. */ GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg); csa = cs_addrs; /* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in * case this is a NO-OP trigger operation that wont update any ^#t records and we still * want to write a TLGTRIG/ULGTRIG journal record. Hence the need to do this. */ JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl); assert(dollar_tlevel); /* below is needed to set update_trans TRUE on this region even if NO db updates happen to ^#t nodes */ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0); jnl_format_done = TRUE; } if (wildcard) { UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen); if (triggers_deleted) { trig_stats[STATS_NOERROR_TRIGFILE]++; util_out_print_gtmio("All existing triggers named !AD (count = !UL) now deleted", FLUSH, orig_name_len, trigger_name, triggers_deleted); } else { trig_stats[STATS_UNCHANGED_TRIGFILE]++; util_out_print_gtmio("No matching triggers of the form !AD found for deletion", FLUSH, orig_name_len, trigger_name); } } else if (triggers_deleted) { /* util_out_print_gtmio of "Deleted trigger named ..." already done so no need to do it again */ trig_stats[STATS_NOERROR_TRIGFILE]++; } else { /* No names match. But treat it as a no-op (i.e. success). */ UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen); util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name); trig_stats[STATS_UNCHANGED_TRIGFILE]++; } return TRIG_SUCCESS; }
boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats) { sgmnt_addrs *csa; char curr_name[MAX_MIDENT_LEN + 1]; uint4 curr_name_len, orig_name_len; mstr gbl_name; mname_entry gvent; gv_namehead *hasht_tree; int len; mval mv_curr_nam; boolean_t name_found; char *ptr; char *name_tail_ptr; char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *save_gv_currkey; gd_region *save_gv_cur_region; gv_namehead *save_gv_target; char save_name[MAX_MIDENT_LEN + 1]; sgm_info *save_sgm_info_ptr; mval trig_gbl; mval trig_value; mval trigger_count; char trigvn[MAX_MIDENT_LEN + 1]; int trigvn_len; int trig_indx; int badpos; boolean_t wildcard; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; badpos = 0; orig_name_len = trigger_name_len; if ((0 == trigger_name_len) || (trigger_name_len != (badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard)))) { /* is the input name valid */ CONV_STR_AND_PRINT("Invalid trigger NAME string: ", orig_name_len, trigger_name); /* badpos is the string position where the bad character was found, pretty print it */ return TRIG_FAILURE; } name_tail_ptr = trigger_name + trigger_name_len - 1; if (TRIGNAME_SEQ_DELIM == *name_tail_ptr || wildcard ) /* drop the trailing # sign or wildcard */ trigger_name_len--; /* $data(^#t) */ SWITCH_TO_DEFAULT_REGION; INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; if (0 == gv_target->root) { util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name); return TRIG_FAILURE; } name_found = FALSE; assert(trigger_name_len < MAX_MIDENT_LEN); memcpy(save_name, trigger_name, trigger_name_len); save_name[trigger_name_len] = '\0'; memcpy(curr_name, save_name, trigger_name_len); curr_name_len = trigger_name_len; STR2MVAL(mv_curr_nam, trigger_name, trigger_name_len); do { /* GVN = $get(^#t("#TNAME",curr_name) */ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len); if (gvcst_get(&trig_gbl)) { SAVE_TRIGGER_REGION_INFO; ptr = trig_gbl.str.addr; trigvn_len = STRLEN(trig_gbl.str.addr); assert(MAX_MIDENT_LEN >= trigvn_len); memcpy(trigvn, ptr, trigvn_len); ptr += trigvn_len + 1; /* the index is just beyon the length of the GVN string */ A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx); gbl_name.addr = trigvn; gbl_name.len = trigvn_len; GV_BIND_NAME_ONLY(gd_header, &gbl_name); csa = gv_target->gd_csa; SETUP_TRIGGER_GLOBAL; INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; /* $get(^#t(GVN,"COUNT") */ BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT)); /* if it does not exist, return false */ if (!gvcst_get(&trigger_count)) { util_out_print_gtmio("Trigger named !AD exists in the lookup table, " "but global ^!AD has no triggers", FLUSH, curr_name_len, curr_name, trigvn_len, trigvn); return TRIG_FAILURE; } /* kill the target trigger for GVN at index trig_indx */ if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, &trigger_count, trig_indx))) { util_out_print_gtmio("Trigger named !AD exists in the lookup table, but was not deleted!", FLUSH, orig_name_len, trigger_name); } else { csa->incr_db_trigger_cycle = TRUE; if (dollar_ztrigger_invoked) { /* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction, * on this region, will re-read triggers. See trigger_update.c for a comment on why * it is okay for db_dztrigger_cycle to be incremented more than once in the same * transaction */ csa->db_dztrigger_cycle++; } trig_stats[STATS_DELETED]++; if (0 == trig_stats[STATS_ERROR]) util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD", FLUSH, curr_name_len, curr_name, trigvn_len, trigvn); } RESTORE_TRIGGER_REGION_INFO; name_found = TRUE; } else { /* no names match, if !wildcard report an error */ if (!wildcard) { util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name); return TRIG_FAILURE; } } if (!wildcard) /* not a wild card, don't $order for the next match */ break; op_gvorder(&mv_curr_nam); if (0 == mv_curr_nam.str.len) break; assert(mv_curr_nam.str.len < MAX_MIDENT_LEN); memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len); curr_name_len = mv_curr_nam.str.len; if (0 != memcmp(curr_name, save_name, trigger_name_len)) /* stop when gv_order returns a string that no longer starts save_name */ break; } while (wildcard); if (name_found) return TRIG_SUCCESS; util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name); return TRIG_FAILURE; }