CUBRID Engine  latest
trigger_manager.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * trigger_manager.c - Trigger Manager
21  */
22 
23 #ident "$Id$"
24 
25 #include <assert.h>
26 
27 #include "config.h"
28 
29 #include "misc_string.h"
30 #include "memory_alloc.h"
31 #include "error_manager.h"
32 #include "dbtype.h"
33 #include "trigger_manager.h"
34 #include "memory_hash.h"
35 #include "work_space.h"
36 #include "schema_manager.h"
37 #include "object_accessor.h"
38 #include "object_primitive.h"
39 #include "object_print.h"
40 #include "set_object.h"
41 #include "authenticate.h"
42 #include "db.h"
43 #include "parser.h"
44 #include "system_parameter.h"
45 #include "locator_cl.h"
46 #include "transaction_cl.h"
47 
48 #include "dbtype.h"
49 #if defined (SUPPRESS_STRLEN_WARNING)
50 #define strlen(s1) ((int) strlen(s1))
51 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
52 
53 #define TR_EXECUTION_ENABLED (tr_Execution_enabled == true)
54 #define UNIQUE_SAVEPOINT_RENAME_TRIGGER "rENAMEtRIGGER"
55 #define UNIQUE_SAVEPOINT_DROP_TRIGGER "dROPtRIGGER"
56 #define UNIQUE_SAVEPOINT_CREATE_TRIGGER "cREATEtRIGGER"
57 
58 /*
59  * IS_USER_EVENT
60  * IS_CLASSEVENT
61  *
62  * Note:
63  * Shorthand macros for determing if an event constant represents
64  * one of the "user" events or one of the "class" events.
65  *
66  */
67 
68 #define IS_USER_EVENT(event) \
69  ((event) == TR_EVENT_COMMIT || \
70  (event) == TR_EVENT_ROLLBACK || \
71  (event) == TR_EVENT_ABORT || \
72  (event) == TR_EVENT_TIMEOUT)
73 
74 /* TR_EVENT_NULL and TR_EVENT_ALL are treated as class events */
75 #define IS_CLASS_EVENT(event) (!IS_USER_EVENT(event))
76 
77 /*
78  * Use this to compare trigger names, should be usign the same thing
79  * we use for class names.
80  */
81 
82 #define COMPARE_TRIGGER_NAMES intl_identifier_casecmp
83 
84 
85 /* Should have something in ER for this */
86 #define MAX_ERROR_STRING 2048
87 
88 /*
89  * IMPORTANT, while evaluating a trigger condition/action, we
90  * set the effective user to the owner of the trigger. This
91  * is primarily of importance if the trigger is accessed through
92  * a view.
93  */
94 
95 
96 /*
97  * TR_RETURN_ codes
98  *
99  * Note:
100  * These are used by functions that need to return 3 valued logic.
101  */
102 
103 static const int TR_RETURN_ERROR = -1;
104 static const int TR_RETURN_FALSE = 0;
105 static const int TR_RETURN_TRUE = 1;
106 
107 /*
108  * tr_init
109  *
110  * Note: Trigger initialization function.
111  * This function should be called at the beginning of a
112  * transaction.
113  */
114 
115 static const int TR_EST_MAP_SIZE = 1024;
116 
117 static const char *OBJ_REFERENCE_NAME = "obj";
118 static const char *NEW_REFERENCE_NAME = "new";
119 static const char *OLD_REFERENCE_NAME = "old";
120 
121 /*
122  * Formerly had a semicolon at the end, not sure that is acceptable since
123  * pt_compile_trigger_stmt is going to surround this in a SCOPE___ statement.
124  * Currently, the evaluate grammar must have parens surrounding the expression.
125  */
126 
127 static const char *EVAL_PREFIX = "EVALUATE ( ";
128 static const char *EVAL_SUFFIX = " ) ";
129 
130 const char *TR_CLASS_NAME = "db_trigger";
131 const char *TR_ATT_NAME = "name";
132 const char *TR_ATT_OWNER = "owner";
133 const char *TR_ATT_EVENT = "event";
134 const char *TR_ATT_STATUS = "status";
135 const char *TR_ATT_PRIORITY = "priority";
136 const char *TR_ATT_CLASS = "target_class";
137 const char *TR_ATT_ATTRIBUTE = "target_attribute";
138 const char *TR_ATT_CLASS_ATTRIBUTE = "target_class_attribute";
139 const char *TR_ATT_CONDITION_TYPE = "condition_type";
140 const char *TR_ATT_CONDITION_TIME = "condition_time";
141 const char *TR_ATT_CONDITION = "condition";
142 const char *TR_ATT_ACTION_TYPE = "action_type";
143 const char *TR_ATT_ACTION_TIME = "action_time";
144 const char *TR_ATT_ACTION = "action_definition";
145 const char *TR_ATT_ACTION_OLD = "action";
146 const char *TR_ATT_PROPERTIES = "properties";
147 const char *TR_ATT_COMMENT = "comment";
148 
152 
155 
156 bool tr_Trace = true;
157 
160 
161 static int tr_User_triggers_valid = 0;
164 
167 
168 /*
169  * Global trigger firing state flag, used to determine if triggers are fired.
170  * This can be modified using tr_set_execution_enabled().
171  */
172 static bool tr_Execution_enabled = true;
173 
174 /*
175  * tr_object_map
176  *
177  * Note:
178  * This is a hash table that maps trigger object MOPs into trigger
179  * structures.
180  * It will be initialized and freed by tr_init & tr_final.
181  *
182  */
183 
185 
186 static const char *time_as_string (DB_TRIGGER_TIME tr_time);
187 static char *tr_process_name (const char *name_string);
188 static TR_ACTIVITY *make_activity (void);
189 static void free_activity (TR_ACTIVITY * act);
190 static TR_TRIGGER *tr_make_trigger (void);
191 static void tr_clear_trigger (TR_TRIGGER * trigger);
192 static void free_trigger (TR_TRIGGER * trigger);
193 
194 static int insert_trigger_list (TR_TRIGLIST ** list, TR_TRIGGER * trigger);
195 static int merge_trigger_list (TR_TRIGLIST ** list, TR_TRIGLIST * more, int destructive);
196 static void remove_trigger_list_element (TR_TRIGLIST ** list, TR_TRIGLIST * element);
197 static void remove_trigger_list (TR_TRIGLIST ** list, TR_TRIGGER * trigger);
198 static void reinsert_trigger_list (TR_TRIGLIST ** list, TR_TRIGGER * trigger);
200 static int add_deferred_activities (TR_TRIGLIST * triggers, MOP current);
201 static void flush_deferred_activities (void);
202 static void remove_deferred_activity (TR_DEFERRED_CONTEXT * context, TR_TRIGLIST * element);
204 
205 static TR_STATE *make_state (void);
206 static void free_state (TR_STATE * state);
207 static DB_OBJECT *trigger_to_object (TR_TRIGGER * trigger);
208 static int object_to_trigger (DB_OBJECT * object, TR_TRIGGER * trigger);
209 static void get_reference_names (TR_TRIGGER * trigger, TR_ACTIVITY * activity, const char **curname,
210  const char **tempname);
211 static int compile_trigger_activity (TR_TRIGGER * trigger, TR_ACTIVITY * activity, int with_evaluate);
212 static int validate_trigger (TR_TRIGGER * trigger);
213 
214 static int register_user_trigger (DB_OBJECT * object);
215 static int unregister_user_trigger (TR_TRIGGER * trigger, int rollback);
216 static int get_user_trigger_objects (DB_TRIGGER_EVENT event, bool active_filter, DB_OBJLIST ** trigger_list);
217 
218 static void reorder_schema_caches (TR_TRIGGER * trigger);
219 static int trigger_table_add (const char *name, DB_OBJECT * trigger);
220 static int trigger_table_find (const char *name, DB_OBJECT ** trigger_p);
221 static int trigger_table_rename (DB_OBJECT * trigger_object, const char *newname);
222 static int trigger_table_drop (const char *name);
223 static bool check_authorization (TR_TRIGGER * trigger, bool alter_flag);
224 static int find_all_triggers (bool active_filter, bool alter_filter, DB_OBJLIST ** list);
225 static int get_schema_trigger_objects (DB_OBJECT * class_mop, const char *attribute, DB_TRIGGER_EVENT event,
226  bool active_flag, DB_OBJLIST ** objlist);
227 static int find_event_triggers (DB_TRIGGER_EVENT event, DB_OBJECT * class_mop, const char *attribute,
228  bool active_filter, DB_OBJLIST ** list);
229 static bool check_target (DB_TRIGGER_EVENT event, DB_OBJECT * class_mop, const char *attribute);
230 static int check_semantics (TR_TRIGGER * trigger);
231 static PT_NODE *tr_check_correlation (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *walk_on);
232 
233 static int tr_drop_trigger_internal (TR_TRIGGER * trigger, int rollback, bool need_savepoint);
234 
235 static bool value_as_boolean (DB_VALUE * value);
236 static int signal_evaluation_error (TR_TRIGGER * trigger, int error);
237 static int eval_condition (TR_TRIGGER * trigger, DB_OBJECT * current, DB_OBJECT * temp, bool * status);
238 static int eval_action (TR_TRIGGER * trigger, DB_OBJECT * current, DB_OBJECT * temp, bool * reject);
239 static int execute_activity (TR_TRIGGER * trigger, DB_TRIGGER_TIME tr_time, DB_OBJECT * current, DB_OBJECT * temp,
240  bool * rejected);
241 static int tr_execute_activities (TR_STATE * state, DB_TRIGGER_TIME tr_time, DB_OBJECT * current, DB_OBJECT * temp);
242 static int run_user_triggers (DB_TRIGGER_EVENT event, DB_TRIGGER_TIME time);
243 static int compare_recursion_levels (int rl_1, int rl_2);
244 static TR_STATE *start_state (TR_STATE ** current, const char *name);
245 static void tr_finish (TR_STATE * state);
246 
247 static int its_deleted (DB_OBJECT * object);
248 
249 static int map_flush_helper (const void *key, void *data, void *args);
250 static int define_trigger_classes (void);
251 
252 static TR_RECURSION_DECISION tr_check_recursivity (OID oid, OID stack[], int stack_size, bool is_statement);
253 
254 /* ERROR HANDLING */
255 
256 /*
257  * time_as_string() - The function returns a illuminating string for a time
258  * constant.
259  * return: const char
260  * tr_time(in): execution time
261  *
262  */
263 static const char *
265 {
266  const char *return_str;
267 
268  switch (tr_time)
269  {
270  case TR_TIME_NULL:
271  return_str = "NULL";
272  break;
273 
274  case TR_TIME_BEFORE:
275  return_str = "BEFORE";
276  break;
277 
278  case TR_TIME_AFTER:
279  return_str = "AFTER";
280  break;
281 
282  case TR_TIME_DEFERRED:
283  return_str = "DEFERRED";
284  break;
285 
286  default:
287  return_str = "UNKNOWN";
288  break;
289  }
290 
291  return return_str;
292 }
293 
294 /* UTILITIES */
295 
296 /*
297  * tr_process_name() - This copies and processes a trigger name string.
298  * return: trigger name string
299  * str(in): proposed name string
300  *
301  * Note:
302  * The processing for trigger names is similar to that for class names.
303  * The name must not contain any invalid characters as defined by sm_check_name and will be downcased before
304  * it is assigned.
305  */
306 static char *
307 tr_process_name (const char *name_string)
308 {
309  char buffer[SM_MAX_IDENTIFIER_LENGTH + 2];
310  char *name = NULL;
311 
312  if (sm_check_name (name_string))
313  {
314  sm_downcase_name (name_string, buffer, SM_MAX_IDENTIFIER_LENGTH);
315  name = strdup (buffer);
316  }
317  return name;
318 }
319 
320 
321 /* ACTIVITY STRUCTURES */
322 
323 /*
324  * make_activity() - Construct an activity structure.
325  * return: allocate and initialize an activity structure
326  */
327 static TR_ACTIVITY *
329 {
330  TR_ACTIVITY *act;
331 
332  act = (TR_ACTIVITY *) malloc (sizeof (TR_ACTIVITY));
333  if (act == NULL)
334  {
336  return NULL;
337  }
338 
339  act->type = TR_ACT_NULL;
340  act->time = TR_TIME_NULL;
341  act->source = NULL;
342  act->parser = NULL;
343  act->statement = NULL;
344  act->exec_cnt = 0;
345 
346  return act;
347 }
348 
349 /*
350  * free_activity() - This frees storage for an activity.
351  * return: none
352  * activity(in): activity to free
353  */
354 static void
356 {
357  if (activity == NULL)
358  {
359  return;
360  }
361 
362  if (activity->source)
363  {
364  free_and_init (activity->source);
365  }
366 
367  if (activity->parser != NULL)
368  {
369  /*
370  * We need to free the statement explicitly here since it may
371  * contain pointers to db_values in the workspace.
372  */
373  parser_free_tree ((PARSER_CONTEXT *) activity->parser, (PT_NODE *) activity->statement);
374  parser_free_parser ((PARSER_CONTEXT *) activity->parser);
375  }
376  free_and_init (activity);
377 }
378 
379 
380 /* TRIGGER STRUCTURES */
381 
382 /*
383  * tr_make_trigger() - Memory allocation function for TR_TRIGGER
384  * return: a TR_TRIGGER pointer
385  *
386  */
387 static TR_TRIGGER *
389 {
390  TR_TRIGGER *trigger;
391 
392  trigger = (TR_TRIGGER *) malloc (sizeof (TR_TRIGGER));
393  if (trigger == NULL)
394  {
396  return NULL;
397  }
398 
399  trigger->owner = NULL;
400  trigger->object = NULL;
401  trigger->name = NULL;
402  trigger->status = TR_STATUS_INVALID;
403  trigger->priority = TR_LOWEST_PRIORITY;
404  trigger->event = TR_EVENT_NULL;
405  trigger->class_mop = NULL;
406  trigger->attribute = NULL;
407  trigger->class_attribute = 0;
408  trigger->condition = NULL;
409  trigger->action = NULL;
410  trigger->current_refname = NULL;
411  trigger->temp_refname = NULL;
412  trigger->chn = NULL_CHN;
413  trigger->comment = NULL;
414 
415  return trigger;
416 }
417 
418 /*
419  * tr_clear_trigger() - This clears the contents of a trigger.
420  * return: none
421  * trigger(in): trigger to clear
422  *
423  * Note:
424  * Don't clear the cache pointer since it remains valid.
425  * Since we cant alter the trigger class/owner etc. without deleting
426  * the trigger, we probably don't need to reset those fields either.
427  */
428 static void
430 {
431  if (trigger == NULL)
432  {
433  return;
434  }
435 
436  /* make sure to clear any DB_OBJECT* pointers for garbage collection */
437  trigger->owner = NULL;
438  trigger->object = NULL;
439  trigger->class_mop = NULL;
440 
441  if (trigger->name)
442  {
443  free_and_init (trigger->name);
444  }
445  if (trigger->attribute)
446  {
447  free_and_init (trigger->attribute);
448  }
449  if (trigger->condition)
450  {
451  free_activity (trigger->condition);
452  trigger->condition = NULL;
453  }
454  if (trigger->action)
455  {
456  free_activity (trigger->action);
457  trigger->action = NULL;
458  }
459  if (trigger->comment != NULL)
460  {
461  free_and_init (trigger->comment);
462  }
463 }
464 
465 /*
466  * free_trigger() - Frees all storage for an allocated trigger.
467  * return: none
468  * trigger(in): trigger to free
469  *
470  */
471 static void
473 {
474  if (trigger)
475  {
476  tr_clear_trigger (trigger);
477  free_and_init (trigger);
478  }
479 }
480 
481 
482 /* TRIGLIST STRUCTURES */
483 
484 /*
485  * tr_free_trigger_list() - Memory free function for TR_TRIGLIST.
486  * return: none
487  * list(in): pointer to a trigger list
488  *
489  * Note:
490  * Since these things can go in the schema cache attached to the class,
491  * use WS_ALLOC to avoid warnings when shutting down the database.
492  */
493 void
495 {
496  TR_TRIGLIST *node, *next;
497 
498  for (node = list, next = NULL; node != NULL; node = next)
499  {
500  next = node->next;
501  db_ws_free (node);
502  }
503 }
504 
505 /*
506  * insert_trigger_list() - This inserts a node in a triglist for a new trigger structure.
507  * return: error code
508  * list(in/out): pointer to a list head
509  * trigger(in): trigger to insert
510  *
511  * Note:
512  * The nodes in the triglist are ordered based on trigger priority.
513  * Since these things can go in the schema cache attached to the class,
514  * use WS_ALLOC to avoid warnings when shutting down the database.
515  */
516 static int
518 {
519  TR_TRIGLIST *t, *prev, *new_tr;
520 
521  /* scoot up to the appropriate position in the list */
522  for (t = *list, prev = NULL; t != NULL && t->trigger->priority > trigger->priority; prev = t, t = t->next)
523  ;
524 
525  /* make a new node and link it in */
526  new_tr = (TR_TRIGLIST *) db_ws_alloc (sizeof (TR_TRIGLIST));
527  if (new_tr == NULL)
528  {
529  assert (er_errid () != NO_ERROR);
530  return er_errid ();
531  }
532 
533  new_tr->trigger = trigger;
534  new_tr->next = t;
535  new_tr->prev = prev;
536  new_tr->target = NULL;
537 
538  if (t != NULL)
539  {
540  t->prev = new_tr;
541  }
542 
543  if (prev == NULL)
544  {
545  *list = new_tr;
546  }
547  else
548  {
549  prev->next = new_tr;
550  }
551 
552  return NO_ERROR;
553 }
554 
555 /*
556  * Hack on this, it could be better.
557  *
558  * Need to fix this so that it pays attention to the filter_inactive flag.
559  */
560 
561 
562 /*
563  * merge_trigger_list() - This adds the contents of one sorted trigger list to another.
564  * return: none
565  * list(in/out): pointer to a list head
566  * more(in): list to merge
567  * destructive(in): non-zero if the new list can be physically combined
568  *
569  * Note:
570  * It is used to combine the various sorted trigger lists to construct
571  * the consolodated trigger list for a particular event.
572  * Since these things can go in the schema cache attached to the class,
573  * use WS_ALLOC to avoid warnings when shutting down the database.
574  */
575 static int
576 merge_trigger_list (TR_TRIGLIST ** list, TR_TRIGLIST * more, int destructive)
577 {
578  TR_TRIGLIST *t1, *t2, *prev, *new_tr, *t2_next;
579  int error;
580 
581  /* quick exit if nothing to do */
582  if (more == NULL)
583  {
584  return NO_ERROR;
585  }
586 
587  t1 = *list;
588  t2 = more;
589  prev = NULL;
590 
591  while (t2 != NULL)
592  {
593  t2_next = t2->next;
594 
595  /* scoot up to the appropriate position in the list */
596  for (; t1 != NULL && t1->trigger->priority > t2->trigger->priority; prev = t1, t1 = t1->next)
597  ;
598 
599  if (destructive)
600  {
601  new_tr = t2;
602  }
603  else
604  {
605  new_tr = (TR_TRIGLIST *) db_ws_alloc (sizeof (TR_TRIGLIST));
606  if (new_tr == NULL)
607  {
608  ASSERT_ERROR_AND_SET (error);
609  return error;
610  }
611  new_tr->trigger = t2->trigger;
612  new_tr->target = NULL;
613  }
614 
615  new_tr->next = t1;
616  new_tr->prev = prev;
617 
618  if (prev == NULL)
619  {
620  *list = new_tr;
621  }
622  else
623  {
624  prev->next = new_tr;
625  }
626 
627  if (t1 != NULL)
628  {
629  t1->prev = new_tr;
630  }
631 
632  prev = new_tr;
633  t2 = t2_next;
634  }
635 
636  return NO_ERROR;
637 }
638 
639 /*
640  * remove_trigger_list_element() - This removes a particular element from a trigger list.
641  * return: none
642  * list(in/out): trigger list
643  * element(in): trigger list element
644  *
645  * Note:
646  * It is assumed that the given element actually exists in the list.
647  *
648  */
649 static void
651 {
652  if (element->prev == NULL)
653  {
654  *list = element->next;
655  }
656  else
657  {
658  element->prev->next = element->next;
659  }
660 
661  if (element->next != NULL)
662  {
663  element->next->prev = element->prev;
664  }
665 
666  element->next = NULL;
667  tr_free_trigger_list (element);
668 }
669 
670 /*
671  * remove_trigger_list() - This removes a trigger from a trigger list.
672  * return: none
673  * list(in/out): trigger list
674  * trigger(in): trigger to remove
675  *
676  */
677 static void
679 {
680  TR_TRIGLIST *element;
681 
682  for (element = *list; element != NULL && element->trigger != trigger; element = element->next)
683  ;
684 
685  if (element != NULL)
686  {
687  remove_trigger_list_element (list, element);
688  }
689 }
690 
691 /*
692  * reinsert_trigger_list() - This is used primarily to implement the altering of trigger priorities.
693  * return: none
694  * list(in/out): trigger list pointer
695  * trigger(in): trigger to insert/re-insert
696  *
697  * Note:
698  * It will search a trigger list for the given trigger,
699  * if the trigger is found in the list, it will be removed from its current location and re-inserted in the list
700  * based on its current priority. If the trigger isn't in the list, it does nothing.
701  *
702  */
703 static void
705 {
706  TR_TRIGLIST *element;
707 
708  for (element = *list; element != NULL && element->trigger != trigger; element = element->next)
709  ;
710 
711  /*
712  * note, since we just freed a triglist element, it should be possible
713  * to allocated a new one without error, need to have these in
714  * a resource for faster allocation.
715  */
716  if (element != NULL)
717  {
718  remove_trigger_list_element (list, element);
719  insert_trigger_list (list, trigger);
720  }
721 }
722 
723 /* DEFERRED ACTIVITY MAINTENANCE */
724 
725 /*
726  * add_deferred_activity_context() - This adds another element to the deferred activity list.
727  * return: new context structure
728  *
729  * Note:
730  * This adds another element to the deferred activity list.
731  * This is called once to establish the initial context and will also be called each time
732  * a subsequent savepoint context is required.
733  */
734 static TR_DEFERRED_CONTEXT *
736 {
737  TR_DEFERRED_CONTEXT *def;
738 
739  def = (TR_DEFERRED_CONTEXT *) malloc (sizeof (TR_DEFERRED_CONTEXT));
740  if (def == NULL)
741  {
743  return NULL;
744  }
745 
746  def->next = NULL;
747  def->prev = NULL;
748  def->head = NULL;
749  def->tail = NULL;
750  def->savepoint_id = (void *) -1;
751 
752  if (tr_Deferred_activities == NULL)
753  {
754  tr_Deferred_activities = def;
755  tr_Deferred_activities_tail = def;
756  }
757  else
758  {
759  tr_Deferred_activities_tail->next = def;
761  }
762 
763  return def;
764 }
765 
766 /*
767  * add_deferred_activities() - This adds a list of triggers to the current deferred activity context.
768  * return: error code
769  * triggers(in): trigger list
770  * current(in): associated target object
771  *
772  * Note:
773  * If a context has not been allocated, a new one is created.
774  * The triggers are appended to the context's trigger list.
775  * Each trigger is stamped with the current recursion level and the associated target object.
776  */
777 static int
779 {
780  TR_DEFERRED_CONTEXT *def;
781  TR_TRIGLIST *t, *last;
782 
784  if (def == NULL)
785  {
787  if (def == NULL)
788  {
789  assert (er_errid () != NO_ERROR);
790  return er_errid ();
791  }
792  }
793 
794  /* tag the list entries with the target object */
795  for (t = triggers, last = NULL; t != NULL; t = t->next)
796  {
797  last = t;
798  t->target = current;
799  }
800 
801  /* concatenate the activities to the master list */
802  if (def->head == NULL)
803  {
804  def->head = triggers;
805  }
806  else
807  {
808  def->tail->next = triggers;
809  triggers->prev = def->tail;
810  }
811 
812  def->tail = last;
813 
814  return NO_ERROR;
815 }
816 
817 /*
818  * flush_deferred_activities() - Flushes any remaining entries on the deferred activity list.
819  * return: none
820  *
821  */
822 static void
824 {
825  TR_DEFERRED_CONTEXT *c, *next;
826 
827  for (c = tr_Deferred_activities, next = NULL; c != NULL; c = next)
828  {
829  next = c->next;
831  free_and_init (c);
832  }
833 
834  tr_Deferred_activities = tr_Deferred_activities_tail = NULL;
835 }
836 
837 /*
838  * remove_deferred_activity() - This removes an element from the trigger list
839  * of a deferred activity context.
840  * return: none
841  * context(in): activity context
842  * element(in): activity to remove
843  *
844  */
845 static void
847 {
848  if (context->tail == element)
849  {
850  context->tail = element->prev;
851  }
852 
853  remove_trigger_list_element (&context->head, element);
854 }
855 
856 /*
857  * remove_deferred_context() - Removes an activity context from the global list
858  * This can happen if the context's trigger list becomes empty.
859  * return: none
860  * context(in): context
861  *
862  */
863 static void
865 {
866  if (context->prev != NULL)
867  {
868  context->prev->next = context->next;
869  }
870  else
871  {
872  if (context->next == NULL)
873  {
874  tr_Deferred_activities = tr_Deferred_activities_tail = NULL;
875  }
876  else
877  {
878  tr_Deferred_activities = context->next;
879  }
880  }
881 
882  free_and_init (context);
883 }
884 
885 #if defined(ENABLE_UNUSED_FUNCTION)
886 /*
887  * tr_set_savepoint() - This establishes a new context for scheduling deferred trigger activities.
888  * return: error code
889  * savepoint_id(in): savepoint id
890  *
891  * Note:
892  * It will be called by the transaction manager whenever a savepoint is established.
893  */
894 int
895 tr_set_savepoint (void *savepoint_id)
896 {
897  TR_DEFERRED_CONTEXT *def;
898 
900  if (def != NULL && def->head != NULL)
901  {
902  /* mark this with the supplied savepoint id */
903  def->savepoint_id = savepoint_id;
904 
905  /* build a new one on top of this */
907  {
908  assert (er_errid () != NO_ERROR);
909  return er_errid ();
910  }
911  }
912  return NO_ERROR;
913 }
914 
915 /*
916  * tr_abort_to_savepoint() - This aborts the activity contexts back to
917  * a context with an id that matches the supplied id.
918  * return: error code
919  * savepoint_id(in): savepoint id to abort back to
920  *
921  */
922 int
923 tr_abort_to_savepoint (void *savepoint_id)
924 {
925  TR_DEFERRED_CONTEXT *save, *prev;
926 
927  for (save = tr_Deferred_activities_tail, prev = NULL; save != NULL && save->savepoint_id != savepoint_id; save = prev)
928  {
929  prev = save->prev;
930  /* throw away the scheduled triggers */
931  tr_free_trigger_list (save->head);
932  free_and_init (save);
933  }
934 
935  if (save != NULL)
936  {
937  save->next = NULL;
938  }
939 
940  return NO_ERROR;
941 }
942 #endif /* ENABLE_UNUSED_FUNCTION */
943 
944 /* TRIGGER STATE STRUCTURES */
945 
946 /*
947  * make_state() - Memory allocation function for TR_STATE.
948  * return: TR_STATE *
949  *
950  */
951 static TR_STATE *
953 {
954  TR_STATE *state;
955 
956  state = (TR_STATE *) malloc (sizeof (TR_STATE));
957  if (state == NULL)
958  {
960  return NULL;
961  }
962 
963  state->triggers = NULL;
964 
965  return state;
966 }
967 
968 /*
969  * free_state() - Frees a trigger state structure.
970  *
971  * return: none
972  * state(in): state structure to free
973  *
974  */
975 static void
977 {
978  if (state)
979  {
981  free_and_init (state);
982  }
983 }
984 
985 
986 /* TRIGGER INSTANCES */
987 
988 /*
989  * The trigger instance is used to store the trigger definition in the database.
990  * When the trigger is brought into memory, it is converted into a run-time trigger structure for fast access.
991  * See the trigger object map below.
992  *
993  */
994 
995 /*
996  * trigger_to_object() - This converts a trigger trigger into a database object
997  * return: trigger database object
998  * trigger(in/out): trigger structure
999  *
1000  */
1001 static DB_OBJECT *
1003 {
1004  DB_OBJECT *object_p, *class_p;
1005  DB_OTMPL *obt_p;
1006  DB_VALUE value;
1007  int save, err;
1008  MOBJ obj;
1009 
1010  AU_DISABLE (save);
1011 
1012  object_p = NULL;
1013  obt_p = NULL;
1014 
1015  class_p = db_find_class (TR_CLASS_NAME);
1016  if (class_p == NULL)
1017  {
1018  goto error;
1019  }
1020 
1021  obt_p = dbt_create_object_internal (class_p);
1022  if (obt_p == NULL)
1023  {
1024  goto error;
1025  }
1026 
1027  db_make_object (&value, trigger->owner);
1028  if (dbt_put_internal (obt_p, TR_ATT_OWNER, &value) != NO_ERROR)
1029  {
1030  goto error;
1031  }
1032 
1033  db_make_string (&value, trigger->name);
1034  if (dbt_put_internal (obt_p, TR_ATT_NAME, &value) != NO_ERROR)
1035  {
1036  goto error;
1037  }
1038 
1039  db_make_int (&value, trigger->status);
1040  if (dbt_put_internal (obt_p, TR_ATT_STATUS, &value) != NO_ERROR)
1041  {
1042  goto error;
1043  }
1044 
1045  db_make_float (&value, (float) trigger->priority);
1046  if (dbt_put_internal (obt_p, TR_ATT_PRIORITY, &value) != NO_ERROR)
1047  {
1048  goto error;
1049  }
1050 
1051  db_make_int (&value, trigger->event);
1052  if (dbt_put_internal (obt_p, TR_ATT_EVENT, &value) != NO_ERROR)
1053  {
1054  goto error;
1055  }
1056 
1057  db_make_object (&value, trigger->class_mop);
1058  if (dbt_put_internal (obt_p, TR_ATT_CLASS, &value) != NO_ERROR)
1059  {
1060  goto error;
1061  }
1062 
1063  db_make_string (&value, trigger->attribute);
1064  if (dbt_put_internal (obt_p, TR_ATT_ATTRIBUTE, &value) != NO_ERROR)
1065  {
1066  goto error;
1067  }
1068 
1069  db_make_int (&value, trigger->class_attribute);
1070  if (dbt_put_internal (obt_p, TR_ATT_CLASS_ATTRIBUTE, &value) != NO_ERROR)
1071  {
1072  goto error;
1073  }
1074 
1075  if (trigger->condition != NULL)
1076  {
1077  db_make_int (&value, trigger->condition->type);
1078  if (dbt_put_internal (obt_p, TR_ATT_CONDITION_TYPE, &value) != NO_ERROR)
1079  {
1080  goto error;
1081  }
1082 
1083  db_make_int (&value, trigger->condition->time);
1084  if (dbt_put_internal (obt_p, TR_ATT_CONDITION_TIME, &value) != NO_ERROR)
1085  {
1086  goto error;
1087  }
1088 
1089  db_make_string (&value, trigger->condition->source);
1090  if (dbt_put_internal (obt_p, TR_ATT_CONDITION, &value) != NO_ERROR)
1091  {
1092  goto error;
1093  }
1094  }
1095 
1096  if (trigger->action != NULL)
1097  {
1098  db_make_int (&value, trigger->action->type);
1099  if (dbt_put_internal (obt_p, TR_ATT_ACTION_TYPE, &value) != NO_ERROR)
1100  {
1101  goto error;
1102  }
1103 
1104  db_make_int (&value, trigger->action->time);
1105  if (dbt_put_internal (obt_p, TR_ATT_ACTION_TIME, &value) != NO_ERROR)
1106  {
1107  goto error;
1108  }
1109 
1110  db_make_string_copy (&value, trigger->action->source);
1111  err = dbt_put_internal (obt_p, TR_ATT_ACTION, &value);
1112  if (err != NO_ERROR)
1113  {
1114  /* hack, try old name before aborting */
1115  err = dbt_put_internal (obt_p, TR_ATT_ACTION_OLD, &value);
1116  if (err != NO_ERROR)
1117  {
1118  pr_clear_value (&value);
1119  goto error;
1120  }
1121  }
1122  pr_clear_value (&value);
1123  }
1124 
1125  db_make_string_copy (&value, trigger->comment);
1126  err = dbt_put_internal (obt_p, TR_ATT_COMMENT, &value);
1127  pr_clear_value (&value);
1128  if (err != NO_ERROR)
1129  {
1130  goto error;
1131  }
1132 
1133  object_p = dbt_finish_object (obt_p);
1134  if (object_p != NULL)
1135  {
1136  trigger->object = object_p;
1137  obt_p = NULL;
1138 
1139  /* get the object CHN so we know this template is still valid; get dirty version, as we need lock for triggers fetch */
1140  if (au_fetch_instance_force (object_p, &obj, AU_FETCH_READ, LC_FETCH_DIRTY_VERSION) == 0)
1141  {
1142  trigger->chn = WS_CHN (obj);
1143  }
1144  else
1145  {
1146  /* shoudln't happen, make sure the trigger is disconnected */
1147  trigger->object = NULL;
1148  object_p = NULL;
1149  }
1150  }
1151 
1152 error:
1153  if (obt_p != NULL)
1154  {
1155  dbt_abort_object (obt_p);
1156  }
1157 
1158  AU_ENABLE (save);
1159  return object_p;
1160 }
1161 
1162 /*
1163  * object_to_trigger() - This converts a trigger object from the database into a C structure.
1164  * return: error code
1165  * object(in): trigger object
1166  * trigger(in/out): trigger structure to fill in
1167  *
1168  */
1169 static int
1171 {
1172  DB_VALUE value;
1173  int save;
1174  MOBJ obj;
1175  SM_CLASS *class_;
1176  const char *tmp;
1177 
1178  AU_DISABLE (save);
1179 
1180  /* initialize the trigger to a known default state */
1181  trigger->owner = NULL;
1182  trigger->object = object;
1183  trigger->name = NULL;
1184  trigger->status = TR_STATUS_INVALID;
1185  trigger->priority = TR_LOWEST_PRIORITY;
1186  trigger->event = TR_EVENT_NULL;
1187  trigger->class_mop = NULL;
1188  trigger->attribute = NULL;
1189  trigger->condition = NULL;
1190  trigger->action = NULL;
1191  trigger->comment = NULL;
1192 
1193  /*
1194  * Save the cache coherency number so we know when to re-calculate the
1195  * cache. Get the last dirty version.
1196  */
1198  {
1199  goto error;
1200  }
1201 
1202  trigger->chn = WS_CHN (obj);
1203 
1204  /* OWNER */
1205  if (db_get (object, TR_ATT_OWNER, &value))
1206  {
1207  goto error;
1208  }
1209 
1210  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT)
1211  {
1212  if (DB_IS_NULL (&value))
1213  {
1214  trigger->owner = NULL;
1215  }
1216  else
1217  {
1218  trigger->owner = db_get_object (&value);
1219  }
1220  }
1221 
1222  /* NAME */
1223  if (db_get (object, TR_ATT_NAME, &value))
1224  {
1225  goto error;
1226  }
1227 
1228  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value))
1229  {
1230  tmp = db_get_string (&value);
1231  if (tmp)
1232  {
1233  trigger->name = strdup (tmp);
1234  }
1235  }
1236  db_value_clear (&value);
1237 
1238  /* STATUS */
1239  if (db_get (object, TR_ATT_STATUS, &value))
1240  {
1241  goto error;
1242  }
1243 
1244  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1245  {
1246  trigger->status = (DB_TRIGGER_STATUS) db_get_int (&value);
1247  }
1248 
1249  /* PRIORITY */
1250  if (db_get (object, TR_ATT_PRIORITY, &value))
1251  {
1252  goto error;
1253  }
1254 
1255  if (DB_VALUE_TYPE (&value) == DB_TYPE_DOUBLE)
1256  {
1257  trigger->priority = db_get_double (&value);
1258  }
1259 
1260  /* EVENT */
1261  if (db_get (object, TR_ATT_EVENT, &value))
1262  {
1263  goto error;
1264  }
1265 
1266  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1267  {
1268  trigger->event = (DB_TRIGGER_EVENT) db_get_int (&value);
1269  }
1270 
1271  /* CLASS */
1272  if (db_get (object, TR_ATT_CLASS, &value))
1273  {
1274  goto error;
1275  }
1276 
1277  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT)
1278  {
1279  if (DB_IS_NULL (&value))
1280  {
1281  trigger->class_mop = NULL;
1282  }
1283  else
1284  {
1285  trigger->class_mop = db_get_object (&value);
1286  }
1287  /*
1288  * Check to make sure the class is still available. It is possible
1289  * that the class can be deleted and it wasn't possible to inform
1290  * the associated trigger objects of that fact.
1291  */
1292  if (trigger->class_mop != NULL)
1293  {
1295  {
1296  trigger->status = TR_STATUS_INVALID;
1297  }
1298  }
1299  }
1300 
1301  /* ATTRIBUTE */
1302  if (db_get (object, TR_ATT_ATTRIBUTE, &value))
1303  {
1304  goto error;
1305  }
1306 
1307  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value))
1308  {
1309  tmp = db_get_string (&value);
1310  if (tmp)
1311  {
1312  trigger->attribute = strdup (tmp);
1313  }
1314  }
1315 
1316  db_value_clear (&value);
1317 
1318  /* CLASS ATTRIBUTE */
1319  if (db_get (object, TR_ATT_CLASS_ATTRIBUTE, &value))
1320  {
1321  goto error;
1322  }
1323 
1324  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1325  {
1326  trigger->class_attribute = db_get_int (&value);
1327  }
1328 
1329  /* CONDITION TYPE */
1330  if (db_get (object, TR_ATT_CONDITION_TYPE, &value))
1331  {
1332  goto error;
1333  }
1334 
1335  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1336  {
1337  trigger->condition = make_activity ();
1338  if (trigger->condition == NULL)
1339  {
1340  goto error;
1341  }
1342 
1343  trigger->condition->type = (DB_TRIGGER_ACTION) db_get_int (&value);
1344 
1345  /* CONDITION TIME */
1346  if (db_get (object, TR_ATT_CONDITION_TIME, &value))
1347  {
1348  goto error;
1349  }
1350 
1351  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1352  {
1353  trigger->condition->time = (DB_TRIGGER_TIME) db_get_int (&value);
1354  }
1355 
1356  /* CONDITION SOURCE */
1357  if (db_get (object, TR_ATT_CONDITION, &value))
1358  {
1359  goto error;
1360  }
1361 
1362  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value))
1363  {
1364  tmp = db_get_string (&value);
1365  if (tmp)
1366  {
1367  trigger->condition->source = strdup (tmp);
1368  }
1369  }
1370  db_value_clear (&value);
1371  }
1372 
1373  /* ACTION TYPE */
1374  if (db_get (object, TR_ATT_ACTION_TYPE, &value))
1375  {
1376  goto error;
1377  }
1378 
1379  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1380  {
1381  trigger->action = make_activity ();
1382  if (trigger->action == NULL)
1383  {
1384  goto error;
1385  }
1386 
1387  trigger->action->type = (DB_TRIGGER_ACTION) db_get_int (&value);
1388 
1389  /* ACTION TIME */
1390  if (db_get (object, TR_ATT_ACTION_TIME, &value))
1391  {
1392  goto error;
1393  }
1394 
1395  if (DB_VALUE_TYPE (&value) == DB_TYPE_INTEGER)
1396  {
1397  trigger->action->time = (DB_TRIGGER_TIME) db_get_int (&value);
1398  }
1399 
1400  /* ACTION SOURCE */
1401  if (db_get (object, TR_ATT_ACTION, &value))
1402  {
1403  /* hack, try old name if error */
1404  if (db_get (object, TR_ATT_ACTION_OLD, &value))
1405  {
1406  goto error;
1407  }
1408  }
1409 
1410  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value))
1411  {
1412  tmp = db_get_string (&value);
1413  if (tmp)
1414  {
1415  trigger->action->source = strdup (tmp);
1416  }
1417  }
1418  db_value_clear (&value);
1419  }
1420 
1421  /* COMMENT */
1422  if (db_get (object, TR_ATT_COMMENT, &value))
1423  {
1424  goto error;
1425  }
1426 
1427  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value))
1428  {
1429  tmp = db_get_string (&value);
1430  if (tmp != NULL)
1431  {
1432  trigger->comment = strdup (tmp);
1433  }
1434  }
1435  db_value_clear (&value);
1436 
1437  AU_ENABLE (save);
1438  return NO_ERROR;
1439 
1440 error:
1441  AU_ENABLE (save);
1442 
1443  assert (er_errid () != NO_ERROR);
1444  return er_errid ();
1445 }
1446 
1447 
1448 /* EXPRESSION COMPILATION */
1449 
1450 /*
1451  * get_reference_names() - This determines which of the various reference names are valid for a particular trigger expression
1452  * return: none
1453  * trigger(in): trigger of interest
1454  * activity(in): action
1455  * curname(out): current name (returned)
1456  * tempname(out): temp name (returned)
1457  *
1458  */
1459 static void
1460 get_reference_names (TR_TRIGGER * trigger, TR_ACTIVITY * activity, const char **curname, const char **tempname)
1461 {
1462  *curname = NULL;
1463  *tempname = NULL;
1464 
1466  {
1467  switch (trigger->event)
1468  {
1469  case TR_EVENT_INSERT:
1470  switch (activity->time)
1471  {
1472  case TR_TIME_BEFORE:
1473  *tempname = NEW_REFERENCE_NAME;
1474  break;
1475  case TR_TIME_AFTER:
1476  case TR_TIME_DEFERRED:
1477  *curname = OBJ_REFERENCE_NAME;
1478  break;
1479  default:
1480  break;
1481  }
1482  break;
1483 
1484  case TR_EVENT_UPDATE:
1485  switch (activity->time)
1486  {
1487  case TR_TIME_BEFORE:
1488  *curname = OBJ_REFERENCE_NAME;
1489  *tempname = NEW_REFERENCE_NAME;
1490  break;
1491  case TR_TIME_AFTER:
1492  *curname = OBJ_REFERENCE_NAME;
1493  *tempname = OLD_REFERENCE_NAME;
1494  break;
1495  case TR_TIME_DEFERRED:
1496  *curname = OBJ_REFERENCE_NAME;
1497  break;
1498  default:
1499  break;
1500  }
1501  break;
1502 
1503  case TR_EVENT_DELETE:
1504  switch (activity->time)
1505  {
1506  case TR_TIME_BEFORE:
1507  *curname = OBJ_REFERENCE_NAME;
1508  break;
1509  case TR_TIME_AFTER:
1510  case TR_TIME_DEFERRED:
1511  break;
1512  default:
1513  break;
1514  }
1515  break;
1516 
1517  default:
1518  break;
1519  }
1520  }
1521  else
1522  {
1523  switch (trigger->event)
1524  {
1525  case TR_EVENT_INSERT:
1526  switch (activity->time)
1527  {
1528  case TR_TIME_BEFORE:
1529  *tempname = NEW_REFERENCE_NAME;
1530  break;
1531  case TR_TIME_AFTER:
1532  case TR_TIME_DEFERRED:
1533  *curname = NEW_REFERENCE_NAME;
1534  break;
1535  default:
1536  break;
1537  }
1538  break;
1539 
1540  case TR_EVENT_UPDATE:
1541  switch (activity->time)
1542  {
1543  case TR_TIME_BEFORE:
1544  *curname = OLD_REFERENCE_NAME;
1545  *tempname = NEW_REFERENCE_NAME;
1546  break;
1547  case TR_TIME_AFTER:
1548  *curname = NEW_REFERENCE_NAME;
1549  *tempname = OLD_REFERENCE_NAME;
1550  break;
1551  case TR_TIME_DEFERRED:
1552  *curname = NEW_REFERENCE_NAME;
1553  break;
1554  default:
1555  break;
1556  }
1557  break;
1558 
1559  case TR_EVENT_DELETE:
1560  switch (activity->time)
1561  {
1562  case TR_TIME_BEFORE:
1563  *curname = OLD_REFERENCE_NAME;
1564  break;
1565  case TR_TIME_AFTER:
1566  case TR_TIME_DEFERRED:
1567  break;
1568  default:
1569  break;
1570  }
1571  break;
1572 
1573  default:
1574  break;
1575  }
1576  }
1577 }
1578 
1579 /*
1580  * compile_trigger_activity() - This is used to compile the condition or action expressions of a trigger.
1581  * return: error code
1582  * trigger(in): trigger being updated
1583  * activity(in): activity to compile
1584  * with_evaluate(in):
1585  *
1586  * Note:
1587  * Normally this is done once and then left cached in the trigger structure
1588  * It will be recompiled if the trigger object is changed in any way.
1589  * This is detected by examining the cache coherency number for the trigger object.
1590  * When this changes the cache (including the parse trees) will be flushed and the parse trees will be generated again.
1591  * Parse trees must also be generated after a trigger has been loaded from disk for the first time.
1592  */
1593 static int
1594 compile_trigger_activity (TR_TRIGGER * trigger, TR_ACTIVITY * activity, int with_evaluate)
1595 {
1596  int error = NO_ERROR;
1597  const char *curname, *tempname;
1598  DB_OBJECT *class_mop;
1599  char *text;
1600  int length;
1601  PT_NODE *err;
1602  int stmt, line, column;
1603  const char *msg;
1604  PT_NODE **node_ptr;
1605 
1606  if (activity != NULL && activity->type == TR_ACT_EXPRESSION && activity->source != NULL)
1607  {
1608  if (activity->parser != NULL)
1609  {
1610  parser_free_parser ((PARSER_CONTEXT *) activity->parser);
1611  activity->parser = NULL;
1612  activity->statement = NULL;
1613  }
1614 
1615  /* build a string suitable for compilation */
1616  if (!with_evaluate)
1617  {
1618  text = activity->source;
1619  }
1620  else
1621  {
1622  length = strlen (EVAL_PREFIX) + strlen (activity->source) + strlen (EVAL_SUFFIX) + 1;
1623  text = (char *) malloc (length);
1624  if (text == NULL)
1625  {
1627  return er_errid ();
1628  }
1629  strcpy (text, EVAL_PREFIX);
1630  strcat (text, activity->source);
1631  strcat (text, EVAL_SUFFIX);
1632  }
1633 
1634  /* get a parser for this statement */
1635  activity->parser = parser_create_parser ();
1636  if (activity->parser == NULL)
1637  {
1638  assert (er_errid () != NO_ERROR);
1639  return er_errid ();
1640  }
1641 
1642  get_reference_names (trigger, activity, &curname, &tempname);
1643 
1644  /*
1645  * The pt_ interface doesn't like the first name to be NULL and the second name to be non-NULL.
1646  * For cases like BEFORE INSERT where we have a temp object but no "real" object, shift the tempname down to the curname.
1647  * Must remember to do the same thing when the objects are passed to pt_exec_trigger_stmt()
1648  */
1649 
1650  if (curname == NULL)
1651  {
1652  curname = tempname;
1653  tempname = NULL;
1654  }
1655 
1656  /*
1657  * if both correlation names are NULL, don't pass in the class pointer
1658  * because it adds an empty FROM clause to the expression which results in compile errors
1659  */
1660  class_mop = ((curname == NULL && tempname == NULL) ? NULL : trigger->class_mop);
1661 
1662  activity->statement =
1663  pt_compile_trigger_stmt ((PARSER_CONTEXT *) activity->parser, text, class_mop, curname, tempname);
1664  if (activity->statement == NULL || pt_has_error ((PARSER_CONTEXT *) activity->parser))
1665  {
1666  error = er_errid ();
1667  /* Do not overwrite UNILATERALLY ABORTED error */
1668  if (!ER_IS_ABORTED_DUE_TO_DEADLOCK (error))
1669  {
1670  err = pt_get_errors ((PARSER_CONTEXT *) activity->parser);
1671  if (err == NULL)
1672  {
1673  /* missing compiler error list */
1674  error = ER_TR_INTERNAL_ERROR;
1675  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
1676  }
1677  else
1678  {
1679  error = ER_EMERGENCY_ERROR;
1680  while (err != NULL)
1681  {
1682  err = pt_get_next_error (err, &stmt, &line, &column, &msg);
1683  er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, msg);
1684  }
1685 
1686  /* package up the last error into a general trigger error */
1687  error = (with_evaluate) ? ER_TR_CONDITION_COMPILE : ER_TR_ACTION_COMPILE;
1688  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, trigger->name, msg);
1689  }
1690  }
1691 
1692  /*
1693  * since we had a problem with the compilation, don't leave
1694  * the parser hanging around in the trigger cache
1695  */
1696  if (activity->statement)
1697  {
1698  parser_free_tree ((PARSER_CONTEXT *) activity->parser, (PT_NODE *) activity->statement);
1699  }
1700  activity->statement = NULL;
1701  parser_free_parser ((PARSER_CONTEXT *) activity->parser);
1702  activity->parser = NULL;
1703  }
1704 
1705  if (activity->statement)
1706  {
1707  /*
1708  * We can't allow the user to have a before insert trigger that uses the OID of the new value.
1709  * i.e. they can reference "new.a" but not "new". Let's walk the statement and look for this case.
1710  */
1711  if (trigger->event == TR_EVENT_INSERT && activity->time == TR_TIME_BEFORE)
1712  {
1713  node_ptr = &((PT_NODE *) activity->statement)->info.scope.stmt;
1714  *node_ptr =
1715  parser_walk_tree ((PARSER_CONTEXT *) activity->parser, *node_ptr, NULL, NULL, tr_check_correlation,
1716  NULL);
1717  if (pt_has_error ((PARSER_CONTEXT *) activity->parser))
1718  {
1720  error = er_errid ();
1721  parser_free_tree ((PARSER_CONTEXT *) activity->parser, (PT_NODE *) activity->statement);
1722  activity->statement = NULL;
1723  parser_free_parser ((PARSER_CONTEXT *) activity->parser);
1724  activity->parser = NULL;
1725  }
1726  }
1727  }
1728 
1729  /* free the computed string */
1730  if (with_evaluate)
1731  {
1732  free_and_init (text);
1733  }
1734  }
1735 
1736  return error;
1737 }
1738 
1739 /* TRIGGER STRUCTURE & OBJECT MAP */
1740 
1741 
1742 /*
1743  * validate_trigger() - This is used to check the validity of a cached trigger structure.
1744  * return: error code
1745  * trigger(in/out): trigger structure
1746  *
1747  * Note:
1748  * This is used to check the validity of a cached trigger structure.
1749  * It should be called once before any API level trigger operation takes place.
1750  * Among other things, this must make sure the condition and action statements are compiled and ready to go.
1751  * It also checks "quickly" to see if the associated trigger instance was modified since the last time the trigger
1752  * was cached. This could be faster.
1753  */
1754 static int
1756 {
1757  MOBJ obj;
1758  TR_TRIGGER new_trigger;
1759  int error;
1760 
1761  /*
1762  * should have a quicker lock check mechanism, could call
1763  * locator directly here if it speeds things up
1764  * Get the current version, not the latest one.
1765  */
1766 
1768  {
1769  ASSERT_ERROR_AND_SET (error);
1770  return error;
1771  }
1772 
1773  if (trigger->chn != WS_CHN (obj))
1774  {
1775  /* cache coherency numbers have changed, recache */
1776 
1777  if (object_to_trigger (trigger->object, &new_trigger))
1778  {
1779  ASSERT_ERROR_AND_SET (error);
1780  return error;
1781  }
1782 
1783  tr_clear_trigger (trigger);
1784  *trigger = new_trigger;
1785 
1786  if (compile_trigger_activity (trigger, trigger->condition, 1))
1787  {
1788  trigger->status = TR_STATUS_INVALID;
1790  {
1791  ASSERT_ERROR_AND_SET (error);
1792  return error;
1793  }
1794  }
1795 
1796  if (compile_trigger_activity (trigger, trigger->action, 0))
1797  {
1798  trigger->status = TR_STATUS_INVALID;
1800  {
1801  ASSERT_ERROR_AND_SET (error);
1802  return error;
1803  }
1804  }
1805 
1806  }
1807 
1808  return NO_ERROR;
1809 }
1810 
1811 /*
1812  * tr_map_trigger() - This creates a trigger cache structure for a trigger instance and optionally validates the cache.
1813  * return: trigger structure
1814  * object(in): trigger object handle
1815  * fetch(in): non-zero if the cache is to be updated
1816  *
1817  * Note:
1818  * This creates a trigger cache structure for a trigger instance and optionally validates the cache.
1819  * This is used whenever a trigger object handle needs to be mapped into a trigger structure.
1820  * The structure will be created if one has not yet been allocated.
1821  * This is called by the schema manager when a class is loaded in order to build the class trigger cache list.
1822  * In this case, the fetch flag is off so we don't cause recursive fetches during the transformation of the class object.
1823  * It is also called by the trigger API functions which take MOPs as arguments but which need to convert these
1824  * to the run-time trigger structures.
1825  * In these cases, the fetch flag is set because the trigger will need to be immediately validated.
1826  *
1827  */
1828 TR_TRIGGER *
1829 tr_map_trigger (DB_OBJECT * object, int fetch)
1830 {
1831  TR_TRIGGER *trigger = NULL;
1832 
1833  trigger = (TR_TRIGGER *) mht_get (tr_object_map, (void *) object);
1834  if (trigger != NULL)
1835  {
1836  if (fetch && validate_trigger (trigger) != NO_ERROR)
1837  {
1838  trigger = NULL;
1839  }
1840  }
1841  else
1842  {
1843  trigger = tr_make_trigger ();
1844  if (trigger != NULL)
1845  {
1846  if (object_to_trigger (object, trigger) != NO_ERROR)
1847  {
1848  free_trigger (trigger);
1849  trigger = NULL;
1850  }
1851  else
1852  {
1853  if (mht_put (tr_object_map, object, trigger) == NULL)
1854  {
1855  free_trigger (trigger);
1856  trigger = NULL;
1857  }
1858  }
1859  }
1860  }
1861 
1862  return trigger;
1863 }
1864 
1865 /*
1866  * tr_unmap_trigger() - This is used to release a reference to a trigger structure.
1867  * return: error code
1868  * trigger(in): trigger structure
1869  *
1870  * Note:
1871  * This is used to release a reference to a trigger structure.
1872  * The trigger can be removed from the mapping table and freed.
1873  * This MUST ONLY be called if the caller knows that there will be no other references to this trigger structure.
1874  * This is the case for most class triggers.
1875  * If this cannot be guaranteed, the trigger can simply be left in the mapping table and it will be freed during shutdown.
1876  *
1877  */
1878 int
1880 {
1881  int error = NO_ERROR;
1882 
1883  /* better make damn sure that the caller is the only one that could be referencing this trigger structure */
1884  if (mht_rem (tr_object_map, trigger->object, NULL, NULL) != NO_ERROR)
1885  {
1886  ASSERT_ERROR_AND_SET (error);
1887  }
1888 
1889  return error;
1890 }
1891 
1892 /* USER TRIGGER CACHE */
1893 
1894 /*
1895  * The user object has an attribute that may contain a sequence of trigger object pointers.
1896  * These were once in the au_ module but since they don't really need any special support there,
1897  * they were* moved here to keep au_ from having to know too much about triggers.
1898  * The triggers in this list are only the "user" level triggers such as COMMIT, ABORT, TIMEOUT, and ROLLBACK.
1899  * These triggers are extracted from the user object and placed in a global trigger cache list.
1900  * This saves the expense of performing the usual db_get() operations to extract the trigger info every time
1901  * a user event happens. Proper maintenance of the cache depends on the function tr_check_rollback_triggers being called
1902  * inside the tran_abort() function. When the transaction is rolled back, we universally invalidate the user cache
1903  * so that it can be recalculated for the next transaction.
1904  * We only really need to do this if the user object was modified during the transaction.
1905  *
1906  */
1907 
1908 /*
1909  * register_user_trigger() - This stores a new trigger object inside the current user object
1910  * return: error code
1911  * object(in): trigger object
1912  *
1913  * Note:
1914  * If successful, it will recalculate the user trigger cache list as well.
1915  */
1916 static int
1918 {
1919  int error = NO_ERROR;
1920  DB_SET *table;
1921  DB_VALUE value;
1922  int save;
1923 
1924  AU_DISABLE (save);
1925 
1926  if (Au_user != NULL && (error = obj_inst_lock (Au_user, 1)) == NO_ERROR
1927  && (error = obj_get (Au_user, "triggers", &value)) == NO_ERROR)
1928  {
1929  if (DB_IS_NULL (&value))
1930  {
1931  table = NULL;
1932  }
1933  else
1934  {
1935  table = db_get_set (&value);
1936  }
1937 
1938  if (table == NULL)
1939  {
1940  table = set_create_sequence (0);
1941  db_make_sequence (&value, table);
1942  obj_set (Au_user, "triggers", &value);
1943  /*
1944  * remember, because of coercion, we have to either set the domain properly to begin with or
1945  * we have to get the coerced set back out after it has been assigned
1946  */
1947  set_free (table);
1948  obj_get (Au_user, "triggers", &value);
1949  if (DB_IS_NULL (&value))
1950  {
1951  table = NULL;
1952  }
1953  else
1954  {
1955  table = db_get_set (&value);
1956  }
1957  }
1958 
1959  db_make_object (&value, object);
1960  error = set_insert_element (table, 0, &value);
1961  /* if an error is set, probably must abort the transaction */
1962  }
1963 
1964  AU_ENABLE (save);
1965 
1966  if (error == NO_ERROR)
1967  {
1970  }
1971 
1972  return error;
1973 }
1974 
1975 /*
1976  * unregister_user_trigger() - This removes a trigger from the user object and associated caches
1977  * return: error code
1978  * trigger(in): trigger structure
1979  * rollback(in): non-zero if we're performing a rollback
1980  *
1981  * Note:
1982  * This removes a trigger from the user object and associated caches.
1983  * If the rollback flag is set, it indicates that we're trying to
1984  * remove a trigger that was defined during the current transaction.
1985  * In that case, try to be more tolerant of errors that may occurr.
1986  */
1987 static int
1988 unregister_user_trigger (TR_TRIGGER * trigger, int rollback)
1989 {
1990  int error = NO_ERROR;
1991  DB_SET *table;
1992  DB_VALUE value;
1993  int save;
1994 
1995  if (rollback)
1996  {
1997  /*
1998  * Carefully remove it from the user cache first, if we have
1999  * errors touching the user object then at least it will be
2000  * out of the cache
2001  */
2002  (void) remove_trigger_list (&tr_User_triggers, trigger);
2003  }
2004 
2005  AU_DISABLE (save);
2006 
2007  if (Au_user != NULL && (error = obj_inst_lock (Au_user, 1)) == NO_ERROR
2008  && (error = obj_get (Au_user, "triggers", &value)) == NO_ERROR)
2009  {
2010  if (DB_IS_NULL (&value))
2011  {
2012  table = NULL;
2013  }
2014  else
2015  {
2016  table = db_get_set (&value);
2017  }
2018 
2019  if (table != NULL)
2020  {
2021  db_make_object (&value, trigger->object);
2022  error = set_drop_element (table, &value, false);
2023  set_free (table);
2024  }
2025  /* else, should have "trigger not found" error ? */
2026  }
2027 
2028  AU_ENABLE (save);
2029 
2030  /* don't bother updating the cache now if its a rollback */
2031  if (error == NO_ERROR && !rollback)
2032  {
2035  }
2036 
2037  return error;
2038 }
2039 
2040 /*
2041  * get_user_trigger_objects() - This is used to build and return a list of all the user triggers currently defined
2042  * return: error code
2043  * event(in): event type
2044  * active_filter(in): non-zero to filter out inactive triggers
2045  * trigger_list(in/out): returned list of trigger obects
2046  *
2047  */
2048 static int
2049 get_user_trigger_objects (DB_TRIGGER_EVENT event, bool active_filter, DB_OBJLIST ** trigger_list)
2050 {
2051  int error = NO_ERROR;
2052  DB_SET *table;
2053  DB_VALUE value;
2054  DB_TRIGGER_EVENT e;
2055  TR_TRIGGER *trigger;
2056  int max, i;
2057 
2058  *trigger_list = NULL;
2059 
2060  if (Au_user == NULL)
2061  {
2062  return NO_ERROR;
2063  }
2064 
2065  error = obj_get (Au_user, "triggers", &value);
2066  if (error != NO_ERROR)
2067  {
2068  return error;
2069  }
2070 
2071  if (DB_IS_NULL (&value))
2072  {
2073  table = NULL;
2074  }
2075  else
2076  {
2077  table = db_get_set (&value);
2078  }
2079 
2080  if (table != NULL)
2081  {
2082  error = set_filter (table);
2083  max = set_size (table);
2084 
2085  for (i = 0; i < max && error == NO_ERROR; i++)
2086  {
2087  error = set_get_element (table, i, &value);
2088  if (error == NO_ERROR)
2089  {
2090  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && !DB_IS_NULL (&value) && db_get_object (&value) != NULL)
2091  {
2092  /* deleted objects should have been filtered by now */
2093  trigger = tr_map_trigger (db_get_object (&value), 1);
2094  if (trigger == NULL)
2095  {
2096  ASSERT_ERROR_AND_SET (error);
2097  }
2098  else
2099  {
2100  if (!active_filter || trigger->status == TR_STATUS_ACTIVE)
2101  {
2102  if (event == TR_EVENT_NULL)
2103  {
2104  /* unconditionally collect all the trigger objects */
2105  error = ml_ext_add (trigger_list, db_get_object (&value), NULL);
2106  }
2107  else
2108  {
2109  /* must check for a specific event */
2110  error = tr_trigger_event (db_get_object (&value), &e);
2111  if (error == NO_ERROR)
2112  {
2113  if (e == event)
2114  {
2115  error = ml_ext_add (trigger_list, db_get_object (&value), NULL);
2116  }
2117  }
2118  }
2119  }
2120  }
2121  }
2122  }
2123  }
2124 
2125  set_free (table);
2126  }
2127 
2128  if (error != NO_ERROR && *trigger_list != NULL)
2129  {
2130  ml_ext_free (*trigger_list);
2131  *trigger_list = NULL;
2132  }
2133 
2134  return error;
2135 }
2136 
2137 /*
2138  * tr_update_user_cache() - This is used to establish the user trigger cache
2139  * return: error
2140  *
2141  * Note:
2142  * It goes through the trigger objects defined for the user, maps them to trigger objects and
2143  * stores them on specific lists for quick access.
2144  */
2145 int
2147 {
2148  int error = NO_ERROR;
2149  DB_SET *table;
2150  DB_VALUE value;
2151  TR_TRIGGER *trigger;
2152  int max, i;
2153 
2155  if (tr_User_triggers != NULL)
2156  {
2157  tr_free_trigger_list (tr_User_triggers);
2158  tr_User_triggers = NULL;
2159  }
2160 
2161  if (Au_user != NULL && (error = obj_get (Au_user, "triggers", &value)) == NO_ERROR)
2162  {
2163  if (DB_IS_NULL (&value))
2164  {
2165  table = NULL;
2166  }
2167  else
2168  {
2169  table = db_get_set (&value);
2170  }
2171 
2172  if (table != NULL)
2173  {
2174  error = set_filter (table);
2175  max = set_size (table);
2176 
2177  for (i = 0; i < max && error == NO_ERROR; i++)
2178  {
2179  error = set_get_element (table, i, &value);
2180  if (error == NO_ERROR)
2181  {
2182  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && !DB_IS_NULL (&value)
2183  && db_get_object (&value) != NULL)
2184  {
2185  /* deleted objects will have been filtered by now */
2186  trigger = tr_map_trigger (db_get_object (&value), 1);
2187  if (trigger == NULL)
2188  {
2189  assert (er_errid () != NO_ERROR);
2190  error = er_errid ();
2191  }
2192  else
2193  {
2194  error = insert_trigger_list (&tr_User_triggers, trigger);
2195  }
2196  }
2197  }
2198  }
2199 
2200  set_free (table);
2201  }
2202  }
2203 
2204  if (error == NO_ERROR)
2205  {
2207  }
2208  else if (tr_User_triggers != NULL)
2209  {
2210  tr_free_trigger_list (tr_User_triggers);
2211  tr_User_triggers = NULL;
2212  }
2213 
2214  return error;
2215 }
2216 
2217 #if defined(ENABLE_UNUSED_FUNCTION)
2218 /*
2219  * tr_invalidate_user_cache() - This is called to invalidate the user trigger
2220  * cache and cause it to be recalculated the next
2221  * time a user event is encountered.
2222  * return: none
2223  *
2224  * Note:
2225  * It is intended to be called only by au_set_user() when the user
2226  * object has been changed. Since this can happen frequently under
2227  * some conditions, don't do much complicated here. Delay the actual
2228  * cache calulation until it is needed.
2229  */
2230 void
2232 {
2234 }
2235 #endif /* ENABLE_UNUSED_FUNCTION */
2236 
2237 /* SCHEMA CACHE */
2238 
2239 /*
2240  * Pointers to trigger cache structures are placed directly in the schema structures
2241  * so that the triggers for a particular class/attribute can be quickly located.
2242  *
2243  */
2244 
2245 /*
2246  * tr_make_schema_cache() - This creates a schema class structure
2247  * return: schema cache structure
2248  * type(in): type of cache to create
2249  * objects(in): initial list of schema objects
2250  *
2251  * Note:
2252  * This creates a schema class structure. The length of the cache array will vary depending on the type of the cache.
2253  * Since these are going to be attached to class objects and may not get freed unless the class is specifically flushed,
2254  * we allocate them in the workspace rather than using malloc so we don't get a bunch of dangling allocation references
2255  * when we shut down.
2256  */
2259 {
2260  TR_SCHEMA_CACHE *cache = NULL;
2261  int elements, size, i;
2262 
2263  if (type == TR_CACHE_CLASS)
2264  {
2265  elements = TR_MAX_CLASS_TRIGGERS;
2266  }
2267  else
2268  {
2269  elements = TR_MAX_ATTRIBUTE_TRIGGERS;
2270  }
2271 
2272  /* there is already space for one ponter in the structure so decrement the element count multiplier */
2273  size = sizeof (TR_SCHEMA_CACHE) + (sizeof (TR_TRIGLIST *) * (elements - 1));
2274  cache = (TR_SCHEMA_CACHE *) db_ws_alloc (size);
2275  if (cache == NULL)
2276  {
2277  return NULL;
2278  }
2279 
2280  cache->objects = objects;
2281  cache->compiled = 0;
2282  cache->array_length = elements;
2283  for (i = 0; i < elements; i++)
2284  {
2285  cache->triggers[i] = NULL;
2286  }
2287 
2288  /* add it to the global list */
2289  cache->next = tr_Schema_caches;
2290  tr_Schema_caches = cache;
2291 
2292  return cache;
2293 }
2294 
2295 /*
2296  * tr_copy_schema_cache() - This is called by the schema manager during class flattening
2297  * return: new cache
2298  * cache(in): cache to copy
2299  * filter_class(in): non-null if filtering triggers
2300  *
2301  * Note:
2302  * It creates a copy of an existing schema cache. Don't bother compiling it at this time, just copy the trigger
2303  * object list and let it get compiled the next time the class is referenced.
2304  * If the filter_class is non-NULL, the copied cache will contain only triggers that are defined with targets
2305  * directly on the filter_class. This is used to filter out triggers in the cache that were inherited from super classes.
2306  */
2309 {
2310  TR_SCHEMA_CACHE *new_ent;
2311  TR_TRIGGER *trigger;
2312  TR_CACHE_TYPE type;
2313  DB_OBJLIST *obj_list;
2314 
2315  if (cache == NULL)
2316  {
2317  return NULL;
2318  }
2319 
2320  new_ent = NULL;
2321 
2323 
2324  new_ent = tr_make_schema_cache (type, NULL);
2325  if (new_ent == NULL)
2326  {
2327  return NULL;
2328  }
2329 
2330  if (cache->objects != NULL)
2331  {
2332  if (filter_class == NULL)
2333  {
2334  new_ent->objects = ml_copy (cache->objects);
2335  if (new_ent->objects == NULL)
2336  {
2337  goto abort_it;
2338  }
2339  }
2340  else
2341  {
2342  for (obj_list = cache->objects; obj_list != NULL; obj_list = obj_list->next)
2343  {
2344  trigger = tr_map_trigger (obj_list->op, 1);
2345  if (trigger == NULL)
2346  {
2347  goto abort_it;
2348  }
2349 
2350  if (trigger->class_mop == filter_class)
2351  {
2352  if (ml_add (&new_ent->objects, obj_list->op, NULL))
2353  {
2354  goto abort_it;
2355  }
2356  }
2357  }
2358  }
2359  }
2360 
2361  return new_ent;
2362 
2363 abort_it:
2364  if (new_ent != NULL)
2365  {
2366  tr_free_schema_cache (new_ent);
2367  }
2368 
2369  return NULL;
2370 }
2371 
2372 /*
2373  * tr_merge_schema_cache() - This is a support routine called by the schema manager during class flattening.
2374  * return: error code
2375  * dest(in): destination cache
2376  * src(in): source cache
2377  *
2378  * Note:
2379  * It will merge the contents of one trigger cache with another.
2380  */
2381 int
2383 {
2384  int error = NO_ERROR;
2385  DB_OBJLIST *obj_list;
2386 
2387  if (destination != NULL && source != NULL)
2388  {
2389  for (obj_list = source->objects; obj_list != NULL && !error; obj_list = obj_list->next)
2390  {
2391  error = ml_add (&destination->objects, obj_list->op, NULL);
2392  }
2393  }
2394 
2395  return error;
2396 }
2397 
2398 /*
2399  * tr_empty_schema_cache() - Looks to see if a cache is empty.
2400  * return: non-zero if the schema cache is empty
2401  * cache(in):
2402  *
2403  */
2404 int
2406 {
2407  return ((cache == NULL) || (cache->objects == NULL));
2408 }
2409 
2410 /*
2411  * tr_free_schema_cache() - This is called to free a schema cache.
2412  * return: none
2413  * cache(in): cache structure
2414  *
2415  * Note:
2416  * Normally this is done only when a class is deleted or swapped out of the workspace.
2417  */
2418 void
2420 {
2421  TR_SCHEMA_CACHE *c, *prev;
2422  int i;
2423 
2424  if (cache == NULL)
2425  {
2426  return;
2427  }
2428 
2429  for (i = 0; i < cache->array_length; i++)
2430  {
2431  if (cache->triggers[i])
2432  {
2433  tr_free_trigger_list (cache->triggers[i]);
2434  }
2435  }
2436 
2437  if (cache->objects != NULL)
2438  {
2439  ml_free (cache->objects);
2440  }
2441 
2442  /* unlink it from the global list */
2443  for (c = tr_Schema_caches, prev = NULL; c != NULL && c != cache; c = c->next)
2444  {
2445  prev = c;
2446  }
2447 
2448  if (c == cache)
2449  {
2450  if (prev != NULL)
2451  {
2452  prev->next = c->next;
2453  }
2454  else
2455  {
2456  tr_Schema_caches = c->next;
2457  }
2458  }
2459 
2460  db_ws_free (cache);
2461 }
2462 
2463 /*
2464  * tr_add_cache_trigger() - This is a callback function called by the schema manager during the processing of
2465  * an sm_add_trigger request
2466  * return: error code
2467  * cache(in/out): cache pointer
2468  * trigger_object(in): trigger (object) to add
2469  *
2470  * Note:
2471  * As the schema manager walks through the class hierarchy identifying subclasses that need to inherit the trigger,
2472  * it will create caches using tr_make_schema_cache and then call tr_add_cache_trigger to add the trigger object.
2473  * If the cache has already been compiled, we map the trigger and add it to the appropriate list.
2474  * If it hasn't yet been compiled we simply add it to the object list.
2475  */
2476 int
2478 {
2479  int error = NO_ERROR;
2480  TR_TRIGGER *trigger;
2481 
2482  if (cache == NULL)
2483  {
2484  return NO_ERROR;
2485  }
2486 
2487  error = ml_add (&cache->objects, trigger_object, NULL);
2488  if (error == NO_ERROR)
2489  {
2490  if (cache->compiled)
2491  {
2492  trigger = tr_map_trigger (trigger_object, 1);
2493  if (trigger == NULL)
2494  {
2495  ASSERT_ERROR_AND_SET (error);
2496  }
2497  else
2498  {
2499  error = insert_trigger_list (&(cache->triggers[trigger->event]), trigger);
2500  }
2501  }
2502  }
2503 
2504  return error;
2505 }
2506 
2507 /*
2508  * tr_drop_cache_trigger() - This is a callback function called by the schema manager during the processing of
2509  * an sm_drop_trigger request.
2510  * return: error code
2511  * cache(in): schema cache
2512  * trigger_object(in): trigger object to remove
2513  *
2514  * Note:
2515  * As the schema manager walks the class hierarchy, it will call this function to remove a particular trigger object
2516  * from the cache of each of the affected subclasses. Compare with the function tr_add_cache_trigger.
2517  */
2518 int
2520 {
2521  int error = NO_ERROR;
2522  TR_TRIGGER *trigger;
2523 
2524  if (cache == NULL)
2525  {
2526  return NO_ERROR;
2527  }
2528 
2529  ml_remove (&cache->objects, trigger_object);
2530  if (cache->compiled)
2531  {
2532  trigger = tr_map_trigger (trigger_object, 1);
2533  if (trigger == NULL)
2534  {
2535  assert (er_errid () != NO_ERROR);
2536  error = er_errid ();
2537  }
2538  else
2539  {
2540  (void) remove_trigger_list (&(cache->triggers[trigger->event]), trigger);
2541  }
2542  }
2543 
2544  return error;
2545 }
2546 
2547 /*
2548  * tr_get_cache_objects() - This builds an object list for all of the triggers found in a schema cache.
2549  * return: error code
2550  * cache(in): schema cache
2551  * list(out): returned object list
2552  *
2553  * Note:
2554  * This is used for storing classes on disk. Since we don't need the full trigger cache structure on disk,
2555  * we just store a list of all the associated trigger objects. When the class is brought back in,
2556  * we convert the object list back into a trigger cache.
2557  * The list returned by this function will become part of the cache if it doesn't already exist and should
2558  * NOT be freed by the caller. There shouldn't be any conditions where the list doesn't match
2559  * the cache but build it by hand just in case.
2560  */
2561 int
2563 {
2564  int error = NO_ERROR;
2565  int i;
2566  TR_TRIGLIST *t;
2567 
2568  *list = NULL;
2569 
2570  if (cache == NULL)
2571  {
2572  return NO_ERROR;
2573  }
2574 
2575  if (cache->objects == NULL)
2576  {
2577  for (i = 0; i < cache->array_length && !error; i++)
2578  {
2579  for (t = cache->triggers[i]; t != NULL; t = t->next)
2580  {
2581  error = ml_add (&cache->objects, t->trigger->object, NULL);
2582  }
2583  }
2584  }
2585 
2586  *list = cache->objects;
2587 
2588  return error;
2589 }
2590 
2591 /*
2592  * tr_validate_schema_cache() - This must be called by anyone that is about to "look inside" a class cache structure.
2593  * return: error
2594  * cache(in): class cache attached to schema
2595  * class_mop(in): class mop
2596  *
2597  * Note:
2598  * This must be called by anyone that is about to "look inside" a class cache structure.
2599  * It makes sure that the cache objects have been converted to trigger structures and sorted on the proper list.
2600  */
2601 int
2603 {
2604  int error = NO_ERROR;
2605  DB_OBJLIST *object_list, *prev, *next;
2606  TR_TRIGGER *trigger;
2607  bool mop_found;
2608 
2609  if (cache == NULL)
2610  {
2611  return NO_ERROR;
2612  }
2613  if (cache->compiled)
2614  {
2615  return NO_ERROR;
2616  }
2617 
2618  for (object_list = cache->objects, prev = NULL, next = NULL; object_list != NULL && cache != NULL; object_list = next)
2619  {
2620  next = object_list->next;
2621  trigger = tr_map_trigger (object_list->op, 1);
2622 
2623  /* check for deleted objects that need to be quietly removed */
2624  if (trigger != NULL && trigger->event < cache->array_length)
2625  {
2626  if (class_mop != NULL && ws_mop_compare (class_mop, trigger->class_mop) != 0)
2627  {
2628  if (sm_find_subclass_in_hierarchy (trigger->class_mop, class_mop, &mop_found) != NO_ERROR)
2629  {
2630  return error;
2631  }
2632 
2633  if (mop_found == false)
2634  {
2635  /*
2636  * got a bogus trigger object in the cache,
2637  * remove it
2638  */
2639 
2640  if (prev == NULL)
2641  {
2642  cache->objects = next;
2643  }
2644  else
2645  {
2646  prev->next = next;
2647  }
2648 
2649  object_list->next = NULL;
2650  ml_free (object_list);
2651 
2652  continue;
2653  }
2654  }
2655 
2656 
2657  if (insert_trigger_list (&(cache->triggers[trigger->event]), trigger))
2658  {
2659  ASSERT_ERROR_AND_SET (error);
2660  return error; /* memory error */
2661  }
2662  prev = object_list;
2663  }
2664  else
2665  {
2666  if (trigger == NULL && er_errid () != ER_HEAP_UNKNOWN_OBJECT)
2667  {
2668  /* we got some kind of severe error, abort */
2669  ASSERT_ERROR_AND_SET (error);
2670 
2671  if (ER_IS_ABORTED_DUE_TO_DEADLOCK (error))
2672  {
2673  /* UNILATERALLY ABORTED error must be returned */
2674  return error;
2675  }
2676  }
2677  else
2678  {
2679  /*
2680  * else, got a bogus trigger object in the cache,
2681  * remove it
2682  */
2683  if (prev == NULL)
2684  {
2685  cache->objects = next;
2686  }
2687  else
2688  {
2689  prev->next = next;
2690  }
2691 
2692  object_list->next = NULL;
2693  ml_free (object_list);
2694  }
2695  }
2696  }
2697 
2698  if (error == NO_ERROR)
2699  {
2700  cache->compiled = 1;
2701  }
2702 
2703  return error;
2704 }
2705 
2706 #if defined(ENABLE_UNUSED_FUNCTION)
2707 /*
2708  * tr_reset_schema_cache() - This is called by functions that alter triggers
2709  * in such a way that the schema caches need
2710  * to be rebuilt
2711  * return: error
2712  * cache(in): cache to clear
2713  *
2714  * Note:
2715  * Currently this is called only by tr_set_priority.
2716  */
2717 
2718 int
2719 tr_reset_schema_cache (TR_SCHEMA_CACHE * cache)
2720 {
2721  int error = NO_ERROR;
2722  int i;
2723 
2724  if (cache != NULL)
2725  {
2726  /* remove the existing trigger lists if any */
2727  for (i = 0; i < cache->array_length; i++)
2728  {
2729  if (cache->triggers[i])
2730  {
2731  tr_free_trigger_list (cache->triggers[i]);
2732  cache->triggers[i] = NULL;
2733  }
2734  }
2735 
2736  cache->compiled = 0;
2737  error = tr_validate_schema_cache (cache);
2738  }
2739 
2740  return error;
2741 }
2742 #endif /* ENABLE_UNUSED_FUNCTION */
2743 
2744 /*
2745  * reorder_schema_caches() - This finds all the schema caches that point to a particular trigger and reorders their lists
2746  * based on the new trigger priority
2747  * return: none
2748  * trigger(in/out): trigger that has been modified
2749  *
2750  * Note:
2751  * This could be more effecient if we had a more directed way to determine which caches a trigger might be on.
2752  * For now just look at all of them. Changing trigger priorities shouldn't be a very common operation so it isn't
2753  * worth walking class hierarchies at this point.
2754  */
2755 static void
2757 {
2758  TR_SCHEMA_CACHE *c;
2759  int i;
2760 
2761  for (c = tr_Schema_caches; c != NULL; c = c->next)
2762  {
2763  if (c->compiled)
2764  {
2765  for (i = 0; i < c->array_length; i++)
2766  {
2767  reinsert_trigger_list (&(c->triggers[i]), trigger);
2768  }
2769  }
2770  }
2771 }
2772 
2773 /*
2774  * tr_active_schema_cache() - This is used to determine if a cache contains active event_type triggers.
2775  * return: 0 = none, >0 = active, <0 = error
2776  * class_mop(in): class mop
2777  * cache(in): schema cache to examine
2778  * event_type(in) : event type.
2779  *
2780  * Note:
2781  * The schema manager calls this to cache the trigger activity status so that it can be faster in cases
2782  * where there are no active triggers defined for a class.
2783  * Returns -1 on error, this can only happen if there are storage allocation problems trying to build the schema cache.
2784  *
2785  */
2786 int
2788  bool * has_event_type_triggers)
2789 {
2790  TR_TRIGLIST *t;
2791  int i, active;
2792  bool result = false;
2793 
2794  active = 0;
2795 
2796  if (cache != NULL)
2797  {
2798  if (tr_validate_schema_cache (cache, class_mop))
2799  {
2800  return -1;
2801  }
2802  for (i = 0; i < cache->array_length && !result; i++)
2803  {
2804  for (t = cache->triggers[i]; t != NULL && !result; t = t->next)
2805  {
2806  if (t->trigger->status == TR_STATUS_ACTIVE)
2807  {
2808  active = 1;
2809  if ((event_type == TR_EVENT_ALL) || (t->trigger->event == event_type))
2810  {
2811  result = true;
2812  }
2813  }
2814  }
2815  }
2816  }
2817 
2818  if (has_event_type_triggers)
2819  {
2820  *has_event_type_triggers = result;
2821  }
2822 
2823  return active;
2824 }
2825 
2826 /*
2827  * tr_delete_schema_cache() - This is called by the schema manager to notify the trigger manager that a class or
2828  * attribute is being deleted and the schema cache is no longer needed
2829  * return: error code
2830  * cache(in): schema cache
2831  * class_object(in): class_object
2832  *
2833  * Note:
2834  * This is different than tr_free_schema_cache because we can also mark the associated triggers as being invalid
2835  * since their targets are gone. Note that marking the triggers invalid is only performed if the trigger target class
2836  * is the same as the supplied class. This is because this function may be called by subclasses that are losing
2837  * the attribute but the attribute still exists in a super class and the trigger is still applicable to
2838  * the super class attribute.
2839  */
2840 int
2842 {
2843  DB_VALUE value;
2844  DB_OBJLIST *m;
2845  TR_TRIGGER *trigger;
2846  int save;
2847 
2848  AU_DISABLE (save);
2849 
2850  /* make a value container for marking the trigger object as invalid */
2851  db_make_int (&value, (int) TR_STATUS_INVALID);
2852  if (cache != NULL)
2853  {
2854  for (m = cache->objects; m != NULL; m = m->next)
2855  {
2856  trigger = tr_map_trigger (m->op, 0);
2857 
2858  /*
2859  * if the trigger has already been marked invalid, don't
2860  * bother updating the object
2861  */
2862  if (trigger != NULL)
2863  {
2864  /*
2865  * only invalidate the trigger if it is defined directly
2866  * on this class
2867  */
2868  if (trigger->class_mop == class_object)
2869  {
2870  /*
2871  * don't bother updating the trigger object if its already
2872  * invalid
2873  */
2874  if (trigger->status != TR_STATUS_INVALID)
2875  {
2876  trigger->status = TR_STATUS_INVALID;
2877 
2878  /*
2879  * Store the status permanently in the trigger object.
2880  * This may result in an access violation, if so ignore
2881  * it but be prepared to recognize it when the trigger
2882  * is loaded again.
2883  */
2884  (void) db_put_internal (m->op, TR_ATT_STATUS, &value);
2885  }
2886  }
2887  }
2888  }
2889 
2890  tr_free_schema_cache (cache);
2891  }
2892 
2893  AU_ENABLE (save);
2894  return NO_ERROR;
2895 }
2896 
2897 /*
2898  * tr_delete_triggers_for_class - Finds all triggers on a class and deletes them one by one.
2899  * WARNING: it really deletes them, not the wimpy
2900  * delete_schema_cache() which only invalidates them.
2901  *
2902  *
2903  *
2904  * return: error code
2905  * cache(in/out): schema cache
2906  * class_object(in): class_object
2907  *
2908  * Note:
2909  * This removes only the triggers that have the given class as the trigger object, and not attributes,
2910  * or super- or subclasses. The idea is that if the user deletes a class, it is reasonable
2911  * to assume that he does not want its triggers to remain around.
2912  */
2913 int
2915 {
2916  TR_TRIGGER *trigger;
2917  int save;
2918  DB_OBJLIST *m;
2919  int didwork = 1;
2920  int error;
2921 
2922  if ((NULL == cache) || (*cache == NULL))
2923  {
2924  return NO_ERROR;
2925  }
2926 
2927  AU_DISABLE (save);
2928 
2929  while (didwork)
2930  {
2931  didwork = 0;
2932 
2933  /* need better error handling here */
2934  error = tr_validate_schema_cache (*cache, class_object);
2935  if (error != NO_ERROR)
2936  {
2937  break;
2938  }
2939 
2940  for (m = (*cache)->objects; m != NULL; m = m->next)
2941  {
2942  trigger = tr_map_trigger (m->op, 0);
2943  if (trigger == NULL)
2944  {
2945  continue;
2946  }
2947 
2948  if (trigger->class_mop != class_object)
2949  {
2950  continue;
2951  }
2952 
2953  error = tr_drop_trigger_internal (trigger, 0, false);
2954  if (error != NO_ERROR)
2955  {
2956  break;
2957  }
2958 
2959  didwork = 1;
2960 
2961  /* we can only delete one trigger per operation, because we need to re-validate the schema cache after each
2962  * delete, so that we can iterate through the rest of its elements. */
2963  break;
2964  }
2965  }
2966 
2967  tr_free_schema_cache (*cache);
2968  *cache = NULL;
2969 
2970  AU_ENABLE (save);
2971  return error;
2972 }
2973 
2974 
2975 
2976 /* TRIGGER TABLE */
2977 
2978 /*
2979  * This is the global trigger table. All triggers are entered into the table and must be uniquely identifiable by name.
2980  * This should be one of the new "transaction aware" hash tables on the server but until that facility is available
2981  * we have to keep a global list. The disadvantate with this approach is that there will be more contention.
2982  */
2983 
2984 /*
2985  * trigger_table_add() - Adds a trigger to the global name table
2986  * return: error code
2987  * name(in): trigger name
2988  * trigger(in): trigger object
2989  *
2990  * Note:
2991  * We can assume here that a trigger with this name does not exist
2992  */
2993 static int
2994 trigger_table_add (const char *name, DB_OBJECT * trigger)
2995 {
2996  int error = NO_ERROR;
2997  DB_SET *table = NULL;
2998  DB_VALUE value;
2999  int max, save;
3000 
3001  AU_DISABLE (save);
3002 
3003  if (Au_root == NULL)
3004  {
3005  return NO_ERROR;
3006  }
3007 
3008  error = obj_inst_lock (Au_root, 1);
3009  if (error != NO_ERROR)
3010  {
3011  return error;
3012  }
3013 
3014  error = obj_get (Au_root, "triggers", &value);
3015  if (error != NO_ERROR)
3016  {
3017  return error;
3018  }
3019 
3020  if (DB_IS_NULL (&value))
3021  {
3022  table = NULL;
3023  }
3024  else
3025  {
3026  table = db_get_set (&value);
3027  }
3028 
3029  if (table == NULL)
3030  {
3031  table = set_create_sequence (0);
3032  if (table == NULL)
3033  {
3034  error = er_errid ();
3035  if (error == NO_ERROR)
3036  {
3037  error = ER_GENERIC_ERROR;
3038  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
3039  }
3040 
3041  goto end;
3042  }
3043 
3044  error = db_make_sequence (&value, table);
3045  if (error != NO_ERROR)
3046  {
3047  goto end;
3048  }
3049 
3050  error = obj_set (Au_root, "triggers", &value);
3051  if (error != NO_ERROR)
3052  {
3053  goto end;
3054  }
3055 
3056  /* remember, because of coercion, we have to either set the domain properly to begin with or
3057  * we have to get the coerced set back out after it has been assigned
3058  */
3059  set_free (table);
3060  table = NULL;
3061 
3062  error = obj_get (Au_root, "triggers", &value);
3063  if (error != NO_ERROR)
3064  {
3065  goto end;
3066  }
3067 
3068  if (DB_IS_NULL (&value))
3069  {
3070  table = NULL;
3071 
3072  goto end;
3073  }
3074  else
3075  {
3076  table = db_get_set (&value);
3077  }
3078  }
3079  max = set_size (table);
3080 
3081  db_make_string_copy (&value, name);
3082  error = set_put_element (table, max, &value);
3083  pr_clear_value (&value);
3084  if (error == NO_ERROR)
3085  {
3086  db_make_object (&value, trigger);
3087  error = set_put_element (table, max + 1, &value);
3088  /*
3089  * if we have an error at this point, we probably should abort the
3090  * transaction, we now have a partial update of the trigger
3091  * association list
3092  */
3093  }
3094 
3095  set_free (table);
3096  table = NULL;
3097 
3098 end:
3099  if (table != NULL)
3100  {
3101  set_free (table);
3102  table = NULL;
3103  }
3104 
3105  AU_ENABLE (save);
3106 
3107  return error;
3108 }
3109 
3110 /*
3111  * trigger_table_find() - This finds a trigger object by name
3112  * return: error code
3113  * name(in): trigger name
3114  * trigger_ptr(out): trigger object (returned)
3115  *
3116  * Note:
3117  * All triggers must have a globally unique name.
3118  * Should be modified to use an actual persistent table rather than the temporary in-memory table.
3119  */
3120 static int
3121 trigger_table_find (const char *name, DB_OBJECT ** trigger_p)
3122 {
3123  int error = NO_ERROR;
3124  DB_SET *table;
3125  DB_VALUE value;
3126  int max, i, found;
3127 
3128  *trigger_p = NULL;
3129  if (Au_root == NULL)
3130  {
3131  return NO_ERROR;
3132  }
3133 
3134  error = obj_get (Au_root, "triggers", &value);
3135  if (error != NO_ERROR)
3136  {
3137  return error;
3138  }
3139 
3140  if (DB_IS_NULL (&value))
3141  {
3142  table = NULL;
3143  }
3144  else
3145  {
3146  table = db_get_set (&value);
3147  }
3148 
3149  if (table == NULL)
3150  {
3151  return NO_ERROR;
3152  }
3153 
3154  error = set_filter (table);
3155  max = set_size (table);
3156 
3157  /* see if the name is already used */
3158  for (i = 0, found = -1; i < max && error == NO_ERROR && found == -1; i += 2)
3159  {
3160  error = set_get_element (table, i, &value);
3161  if (error == NO_ERROR)
3162  {
3163  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value) && db_get_string (&value) != NULL
3164  && COMPARE_TRIGGER_NAMES (db_get_string (&value), name) == 0)
3165  {
3166  found = i;
3167  }
3168  pr_clear_value (&value);
3169  }
3170  }
3171 
3172  if (found != -1)
3173  {
3174  error = set_get_element (table, found + 1, &value);
3175  if (error == NO_ERROR)
3176  {
3177  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT)
3178  {
3179  if (DB_IS_NULL (&value))
3180  {
3181  *trigger_p = NULL;
3182  }
3183  else
3184  {
3185  *trigger_p = db_get_object (&value);
3186  }
3187  }
3188  pr_clear_value (&value);
3189  }
3190  }
3191  set_free (table);
3192 
3193  return error;
3194 }
3195 
3196 /*
3197  * trigger_table_rename() - This is called when a trigger is renamed
3198  * return: error code
3199  * trigger_object(in): trigger object
3200  * newname(in): new name
3201  *
3202  * Note:
3203  * Since the name table is managed as an association list of name/object pairs, we must change the name in the table
3204  * for the associated trigger. Note that if the transaction is aborted, global trigger object is decached
3205  * so we don't have to unwind our change to the alist before rollback.
3206  */
3207 static int
3208 trigger_table_rename (DB_OBJECT * trigger_object, const char *newname)
3209 {
3210  int error = NO_ERROR;
3211  DB_SET *table;
3212  DB_VALUE value;
3213  int max, save, i, found;
3214  DB_OBJECT *exists;
3215 
3216  /* make sure we don't already have one */
3217  if (trigger_table_find (newname, &exists))
3218  {
3219  assert (er_errid () != NO_ERROR);
3220  return er_errid ();
3221  }
3222 
3223  if (exists != NULL)
3224  {
3226  return er_errid ();
3227  }
3228 
3229  /* change the name */
3230  AU_DISABLE (save);
3231 
3232  if (Au_root == NULL)
3233  {
3234  goto end;
3235  }
3236 
3237  error = obj_inst_lock (Au_root, 1);
3238  if (error != NO_ERROR)
3239  {
3240  goto end;
3241  }
3242 
3243  error = obj_get (Au_root, "triggers", &value);
3244  if (error != NO_ERROR)
3245  {
3246  goto end;
3247  }
3248 
3249  if (DB_IS_NULL (&value))
3250  {
3251  table = NULL;
3252  }
3253  else
3254  {
3255  table = db_get_set (&value);
3256  }
3257 
3258  if (table == NULL)
3259  {
3260  error = ER_TR_TRIGGER_NOT_FOUND;
3261  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, newname);
3262  goto end;
3263  }
3264 
3265  error = set_filter (table);
3266  max = set_size (table);
3267 
3268  for (i = 1, found = -1; i < max && error == NO_ERROR && found == -1; i += 2)
3269  {
3270  error = set_get_element (table, i, &value);
3271  if (error == NO_ERROR)
3272  {
3273  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && db_get_object (&value) == trigger_object)
3274  {
3275  found = i;
3276  }
3277  pr_clear_value (&value);
3278  }
3279  }
3280 
3281  if (found == -1)
3282  {
3283  error = ER_TR_INTERNAL_ERROR;
3284  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, newname);
3285  }
3286  else
3287  {
3288  /* the name is the kept in the element immediately preceeding this one */
3289  db_make_string_copy (&value, newname);
3290  error = set_put_element (table, found - 1, &value);
3291  pr_clear_value (&value);
3292  }
3293 
3294  set_free (table);
3295 
3296 end:
3297  AU_ENABLE (save);
3298  return error;
3299 }
3300 
3301 /*
3302  * trigger_table_drop() - Removes a trigger entry from the global trigger name table
3303  * return: error code
3304  * name(in): trigger name
3305  *
3306  */
3307 static int
3308 trigger_table_drop (const char *name)
3309 {
3310  int error = NO_ERROR;
3311  DB_SET *table;
3312  DB_VALUE value;
3313  int max, i, found, save;
3314 
3315  AU_DISABLE (save);
3316 
3317  if (Au_root == NULL)
3318  {
3319  goto end;
3320  }
3321 
3322  error = obj_inst_lock (Au_root, 1);
3323  if (error != NO_ERROR)
3324  {
3325  goto end;
3326  }
3327 
3328  error = obj_get (Au_root, "triggers", &value);
3329  if (error != NO_ERROR)
3330  {
3331  goto end;
3332  }
3333 
3334  if (DB_IS_NULL (&value))
3335  {
3336  table = NULL;
3337  }
3338  else
3339  {
3340  table = db_get_set (&value);
3341  }
3342 
3343  if (table == NULL)
3344  {
3345  error = ER_TR_TRIGGER_NOT_FOUND;
3346  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, name);
3347  goto end;
3348  }
3349 
3350  error = set_filter (table);
3351  max = set_size (table);
3352  for (i = 0, found = -1; i < max && error == NO_ERROR && found == -1; i += 2)
3353  {
3354  error = set_get_element (table, i, &value);
3355  if (error == NO_ERROR)
3356  {
3357  if (DB_VALUE_TYPE (&value) == DB_TYPE_STRING && !DB_IS_NULL (&value) && db_get_string (&value) != NULL
3358  && COMPARE_TRIGGER_NAMES (db_get_string (&value), name) == 0)
3359  {
3360  found = i;
3361  }
3362  pr_clear_value (&value);
3363  }
3364  }
3365 
3366  if (error == NO_ERROR)
3367  {
3368  if (found == -1)
3369  {
3370  error = ER_TR_TRIGGER_NOT_FOUND;
3371  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, name);
3372  }
3373  else
3374  {
3375  error = set_drop_seq_element (table, found);
3376  if (error == NO_ERROR)
3377  {
3378  error = set_drop_seq_element (table, found);
3379  }
3380  /*
3381  * if we get an error on either of these, abort the
3382  * transaction since the trigger table is now in an
3383  * inconsistent state
3384  */
3385  }
3386  }
3387  set_free (table);
3388 
3389 end:
3390  AU_ENABLE (save);
3391 
3392  return error;
3393 }
3394 
3395 /*
3396  * check_authorization() - This checks authorization on a trigger structure
3397  * return: non-zero if authorization is ok
3398  * trigger(in): trigger to examine
3399  * alter_flag(in): non-zero if we're going to be modifying this trigger
3400  *
3401  * Note:
3402  * If the trigger is associated with a class, the current user must have appropriate class authorization.
3403  * If the trigger is associated with a user, the current user must be the owner of the trigger.
3404  * If the alter flag is set, it means that the trigger is about to be modified in some way.
3405  */
3406 static bool
3407 check_authorization (TR_TRIGGER * trigger, bool alter_flag)
3408 {
3409  int error;
3410  bool status = false;
3411 
3412  /* When classes are deleted, their associated triggers are marked as invalid but the triggers themselves are not
3413  * deleted. Need to recognize this. If the trigger is invalid then it can be dropped only by its owner.
3414  */
3415 
3416  if (trigger->status == TR_STATUS_INVALID)
3417  {
3419  {
3420  status = true;
3421  }
3422  }
3423  else if (IS_CLASS_EVENT (trigger->event))
3424  {
3425  if (trigger->class_mop != NULL)
3426  {
3427  /* must check authorization against the associated class */
3428  if (alter_flag)
3429  {
3430  error = au_check_authorization (trigger->class_mop, AU_ALTER);
3431  }
3432  else
3433  {
3434  error = au_check_authorization (trigger->class_mop, AU_SELECT);
3435  }
3436 
3437  if (error == NO_ERROR)
3438  {
3439  status = true;
3440  }
3441  }
3442  else
3443  {
3444  error = ER_TR_INTERNAL_ERROR;
3445  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
3446  }
3447  }
3448  else
3449  {
3450  /* its a user trigger, must be the active user */
3451  if (ws_is_same_object (trigger->owner, Au_user))
3452  {
3453  status = true;
3454  }
3455  }
3456 
3457  return status;
3458 }
3459 
3460 /*
3461  * find_all_triggers() - Returns a list of all trigger objects that have been defined.
3462  * return: error code
3463  * active_filter(in):
3464  * alter_filter(in):
3465  * list(out): trigger list (returned)
3466  *
3467  * Note:
3468  * List must be freed by db_objlist_free (ml_ext_free) when no longer required.
3469  */
3470 static int
3471 find_all_triggers (bool active_filter, bool alter_filter, DB_OBJLIST ** list)
3472 {
3473  int error = NO_ERROR;
3474  TR_TRIGGER *trigger;
3475  DB_SET *table;
3476  DB_VALUE value;
3477  int max, i;
3478 
3479  *list = NULL;
3480 
3481  if (Au_root == NULL)
3482  {
3483  return NO_ERROR;
3484  }
3485 
3486  error = obj_get (Au_root, "triggers", &value);
3487  if (error != NO_ERROR)
3488  {
3489  return NO_ERROR;
3490  }
3491 
3492  if (DB_IS_NULL (&value))
3493  {
3494  table = NULL;
3495  }
3496  else
3497  {
3498  table = db_get_set (&value);
3499  }
3500 
3501  if (table == NULL)
3502  {
3503  return NO_ERROR;
3504  }
3505 
3506  error = set_filter (table);
3507  max = set_size (table);
3508  for (i = 1; i < max && error == NO_ERROR; i += 2)
3509  {
3510  error = set_get_element (table, i, &value);
3511  if (error == NO_ERROR)
3512  {
3513  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && !DB_IS_NULL (&value) && db_get_object (&value) != NULL)
3514  {
3515  /* think about possibly avoiding this, especially if we're going to turn around and delete it */
3516  trigger = tr_map_trigger (db_get_object (&value), 1);
3517  if (trigger == NULL)
3518  {
3519  ASSERT_ERROR_AND_SET (error);
3520  }
3521  else
3522  {
3523  if ((!active_filter || trigger->status == TR_STATUS_ACTIVE)
3524  && check_authorization (trigger, alter_filter))
3525  {
3526  error = ml_ext_add (list, db_get_object (&value), NULL);
3527  }
3528  }
3529  }
3530  }
3531  }
3532  set_free (table);
3533 
3534  if (error != NO_ERROR && *list != NULL)
3535  {
3536  ml_ext_free (*list);
3537  *list = NULL;
3538  }
3539 
3540  return error;
3541 }
3542 
3543 /*
3544  * get_schema_trigger_objects() - Work function for find_event_triggers
3545  * return: error code
3546  * class(in): class object
3547  * attribute(in): attribute name
3548  * event(in): event type
3549  * active_flag(in): non-zero to check for active status
3550  * object_list(out): trigger object list (returned)
3551  *
3552  * Note:
3553  * Class has already been checked for user ALTER privilege in check_target called from tr_find_event_triggers.
3554  * Locate the trigger list for a particular schema event.
3555  */
3556 static int
3557 get_schema_trigger_objects (DB_OBJECT * class_mop, const char *attribute, DB_TRIGGER_EVENT event, bool active_flag,
3558  DB_OBJLIST ** object_list)
3559 {
3560  TR_SCHEMA_CACHE *cache;
3561  TR_TRIGLIST *t = NULL;
3562  int error = NO_ERROR;
3563 
3564  *object_list = NULL;
3565 
3566  if (sm_get_trigger_cache (class_mop, attribute, 0, (void **) &cache))
3567  {
3568  ASSERT_ERROR_AND_SET (error);
3569  return error;
3570  }
3571 
3572  if (cache == NULL)
3573  {
3574  return NO_ERROR;
3575  }
3576 
3577  if (tr_validate_schema_cache (cache, class_mop))
3578  {
3579  assert (er_errid () != NO_ERROR);
3580  return er_errid ();
3581  }
3582 
3583  if (event == TR_EVENT_ALL)
3584  {
3585  if (!active_flag)
3586  {
3587  /* if we're lucky we can just use the existing object list */
3588  *object_list = ml_ext_copy (cache->objects);
3589  }
3590  else
3591  {
3592  int e;
3593  /* get all active trigger objects */
3594  for (e = 0; e < cache->array_length; e++)
3595  {
3596  for (t = cache->triggers[e]; t && error == NO_ERROR; t = t->next)
3597  {
3598  if (t->trigger->status == TR_STATUS_ACTIVE)
3599  {
3600  error = ml_ext_add (object_list, t->trigger->object, NULL);
3601  }
3602  }
3603  }
3604  }
3605  }
3606  else if (event < cache->array_length)
3607  {
3608  for (t = cache->triggers[event]; t && error == NO_ERROR; t = t->next)
3609  {
3610  if (!active_flag || t->trigger->status == TR_STATUS_ACTIVE)
3611  {
3612  error = ml_ext_add (object_list, t->trigger->object, NULL);
3613  }
3614  }
3615  }
3616 
3617  if (error != NO_ERROR && *object_list != NULL)
3618  {
3619  ml_ext_free (*object_list);
3620  *object_list = NULL;
3621  }
3622 
3623  return error;
3624 }
3625 
3626 /*
3627  * find_event_triggers() - The following function finds all the triggers that have the given event, class, and attribute.
3628  * return: error code
3629  * event(in): event type
3630  * class(in): class object (optional)
3631  * attribute(in): attribute name (optinal)
3632  * active_filter(in): active status flag
3633  * list(out): trigger list (returned)
3634  *
3635  * Note:
3636  *
3637  * The following function finds all the triggers that have the given event, class, and attribute.
3638  * The trigger objects are returned in a moplist "list".
3639  * If there are no triggers with the given event, class, and attribute, the argument list returns NULL.
3640  * NOTE THAT THIS IS NOT AN ERROR (NO ERROR CODE IS SET).
3641  * The combination of trigger event, class, and attribute must have been validated.
3642  * The list needs to be freed using db_objlist_free when it is no longer needed.
3643  * Note that the constructed object list is an "external" object list so that it will be a GC root.
3644  * Note that the function does NOT need to take care of the implication that any event that raises a trigger
3645  * with a target class and a target attribute should also raise every trigger that has the same target class and no
3646  * target attribute. The implication is done in the trigger manager.
3647  */
3648 static int
3649 find_event_triggers (DB_TRIGGER_EVENT event, DB_OBJECT * class_mop, const char *attribute, bool active_filter,
3650  DB_OBJLIST ** list)
3651 {
3652  int error = NO_ERROR;
3653 
3654  *list = NULL;
3655 
3656  if (class_mop == NULL)
3657  {
3658  error = get_user_trigger_objects (event, active_filter, list);
3659  }
3660  else
3661  {
3662  error = get_schema_trigger_objects (class_mop, attribute, event, active_filter, list);
3663  }
3664 
3665  return error;
3666 }
3667 
3668 /* TRIGGER CREATION AND SEMANTIC ANALYSIS */
3669 
3670 /*
3671  * check_target() - This checks to see if the target parameters make sense
3672  * return: non-zero if target is valid
3673  * event(in): trigger event
3674  * class_mop(in): class
3675  * attribute(in): attribute name
3676  *
3677  */
3678 static bool
3679 check_target (DB_TRIGGER_EVENT event, DB_OBJECT * class_mop, const char *attribute)
3680 {
3681  bool status = false;
3682 
3683  /* If this is a class event, the class argument must be supplied */
3684  if (IS_CLASS_EVENT (event))
3685  {
3686  /* class event, at least the class must be specified */
3687  if (class_mop == NULL)
3688  {
3690  }
3691  /* User must have ALTER privilege for the class */
3692  else if (au_check_authorization (class_mop, AU_ALTER) == NO_ERROR)
3693  {
3694  if (attribute == NULL)
3695  {
3696  status = true;
3697  }
3698  else
3699  {
3700  /* attribute is only allowed for update events */
3701  if (event != TR_EVENT_UPDATE && event != TR_EVENT_STATEMENT_UPDATE && event != TR_EVENT_ALL)
3702  { /* <-- used in find_event_triggers */
3704  }
3705  /* attribute must be defined in the class */
3706  else if (db_get_attribute (class_mop, attribute) != NULL)
3707  {
3708  status = true;
3709  }
3710  }
3711  }
3712  }
3713  else
3714  {
3715  /* not a class event, class and attribute must be unspecified */
3716  if (class_mop != NULL)
3717  {
3719  }
3720  else if (attribute != NULL)
3721  {
3723  }
3724  else
3725  {
3726  status = true;
3727  }
3728  }
3729 
3730  return status;
3731 }
3732 
3733 /*
3734  * check_semantics() - This function checks the validity of a trigger structure about to be installed.
3735  * return: error code
3736  * trigger(in): proposed trigger structure
3737  *
3738  */
3739 static int
3741 {
3742  int error;
3743  DB_OBJECT *object;
3744  TR_ACTIVITY *condition, *action;
3745  const char *c_time, *a_time;
3746 
3747  /* See if the trigger already exists. */
3748  error = trigger_table_find (trigger->name, &object);
3749  if (error != NO_ERROR)
3750  {
3751  return error;
3752  }
3753 
3754  if (object != NULL)
3755  {
3757  return er_errid ();
3758  }
3759 
3760  /* Priority must be non-negative. */
3761  if (trigger->priority < 0)
3762  {
3764  return er_errid ();
3765  }
3766 
3767  /* Check event for usable trigger events */
3768  if (trigger->event == TR_EVENT_NULL || trigger->event == TR_EVENT_ALL)
3769  {
3771  return er_errid ();
3772  }
3773 
3774  /* Check target class, attribute, and authorization. */
3775  if (!check_target (trigger->event, trigger->class_mop, trigger->attribute))
3776  {
3777  ASSERT_ERROR_AND_SET (error);
3778  return error;
3779  }
3780 
3781  /*
3782  * CONDITION
3783  * Should compile if necessary.
3784  */
3785  condition = trigger->condition;
3786  if (condition != NULL && condition->type != TR_ACT_NULL)
3787  {
3788  /* Must be an expression suitable for EVALUATE */
3789  if (condition->type != TR_ACT_EXPRESSION)
3790  {
3792  return er_errid ();
3793  }
3794 
3795  /* Formerly, we checked here to make sure that there was no subquery in the search condition.
3796  * Not sure how to detect this, we may just want to make this a supported but "not recommended" option
3797  */
3798  }
3799 
3800  /*
3801  * ACTION
3802  * Should compile if necessary
3803  */
3804  action = trigger->action;
3805  if (action != NULL)
3806  {
3807  /* REJECT actions cannot be AFTER or DEFERRED */
3808  if (action->type == TR_ACT_REJECT && (action->time == TR_TIME_AFTER || action->time == TR_TIME_DEFERRED))
3809  {
3810  /*
3811  * REJECT action cannot be used with an action time of
3812  * AFTER or DEFERRED
3813  */
3815  return er_errid ();
3816  }
3817 
3818  /* REJECT actions cannot be applied to TIMEOUT or ABORT events */
3819  if (action->type == TR_ACT_REJECT && (trigger->event == TR_EVENT_ABORT || trigger->event == TR_EVENT_TIMEOUT))
3820  {
3821  /* REJECT action cannot be used with the ABORT or TIMEOUT events */
3823  return er_errid ();
3824  }
3825 
3826  /* INVALIDATE TRANSACTION events cannot be DEFERRED Why not?? */
3827 #if 0
3828  if (action->type == TR_ACT_INVALIDATE && action->time == TR_TIME_DEFERRED)
3829  {
3830  /* INVALIDATE TRANCACTION action cannot be DEFERRED */
3831  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TR_INVALIDATE_DEFERRED, 0);
3832  return er_errid ();
3833  }
3834 #endif /* 0 */
3835 
3836  /*
3837  * Formerly tested to allow only CALL statements in the action.
3838  * Others might be useful but "not recommended" since the side effects
3839  * of the statement might effect the behavior of the trigger.
3840  */
3841  }
3842 
3843  /*
3844  * TIME
3845  * action time must be greater or equal to condition time
3846  */
3847  if (trigger->condition != NULL && trigger->action != NULL && trigger->action->time < trigger->condition->time)
3848  {
3849  c_time = time_as_string (trigger->condition->time);
3850  a_time = time_as_string (trigger->action->time);
3852  return er_errid ();
3853  }
3854 
3855  return NO_ERROR;
3856 }
3857 
3858 /*
3859  * tr_check_correlation() - Trigger semantics disallow the use of "new" in a before insert trigger to reference the OID of
3860  * the (yet to be) inserted instance. So, we must walk the statement searching for this special case
3861  * return: the node
3862  * parser(in): the parser context
3863  * node(in): the activity statement
3864  * arg(in): unused
3865  * walk_on(in): controls traversal
3866  *
3867  */
3868 static PT_NODE *
3869 tr_check_correlation (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *walk_on)
3870 {
3871 
3872  /*
3873  * If we have a name node, then we already know it's a before insert
3874  * trigger, so check to see if the resolved name is "new".
3875  * If so, and there is no original, the it must be "new" and not "new.a".
3876  */
3877  /* TODO: char *info.name.original; compare with NULL?? */
3878  if (node->node_type == PT_NAME && node->info.name.resolved && node->info.name.original
3879  && (node->info.name.original == NULL) && !strcmp (node->info.name.resolved, NEW_REFERENCE_NAME))
3880  {
3881  PT_ERROR (parser, node, er_msg ());
3882  }
3883 
3884  return node;
3885 }
3886 
3887 /*
3888  * tr_create_trigger() - Primary interface function for defining a trigger
3889  * return: trigger object (persistent database object)
3890  * name(in): unique name
3891  * status(in): active/inactive
3892  * priority(in): relative priority (default is 0.0)
3893  * event(in): event type
3894  * class(in): target class
3895  * attribute(in): target attribute name
3896  * cond_time(in): condition time
3897  * cond_source(in): condition source string
3898  * action_time(in): action time
3899  * action_type(in): action type
3900  * action_source(in): action expression source
3901  * comment(in): trigger comment
3902  *
3903  * Note:
3904  * Errors: ER_TR_TRIGGER_EXISTS:
3905  * ER_TR_INVALIDE_PRIORITY:
3906  * ER_TR_MISSING_TARGET_CLASS:
3907  * ER_AU_ALTER_FAILURE:
3908  * ER_SM_ATTRIBUTE_NOT_FOUND:
3909  * ER_TR_INCONSISTENT_TARGET:
3910  * ER_TR_INVALID_ACTION_TIME:
3911  * ER_TR_INVALID_CONDITION:
3912  * ER_TR_INVALID_ACTION:
3913  * ER_TR_INVALID_EVENT:
3914  */
3915 DB_OBJECT *
3916 tr_create_trigger (const char *name, DB_TRIGGER_STATUS status, double priority, DB_TRIGGER_EVENT event,
3917  DB_OBJECT * class_mop, const char *attribute, DB_TRIGGER_TIME cond_time, const char *cond_source,
3918  DB_TRIGGER_TIME action_time, DB_TRIGGER_ACTION action_type, const char *action_source,
3919  const char *comment)
3920 {
3921  TR_TRIGGER *trigger;
3922  DB_OBJECT *object;
3923  char realname[SM_MAX_IDENTIFIER_LENGTH];
3924  bool tr_object_map_added = false;
3925  bool has_savepoint = false;
3926 
3927  object = NULL;
3928 
3929  trigger = tr_make_trigger ();
3930  if (trigger == NULL)
3931  {
3932  return NULL;
3933  }
3934 
3935  /* Initialize a trigger */
3936  trigger->owner = Au_user;
3937  trigger->status = status;
3938  trigger->priority = priority;
3939  trigger->event = event;
3940  trigger->class_mop = class_mop;
3941  trigger->comment = (comment == NULL) ? NULL : strdup (comment);
3942 
3943  if (class_mop != NULL)
3944  {
3945  int is_vclass = db_is_vclass (class_mop);
3946 
3947  if (is_vclass < 0)
3948  {
3949  goto error;
3950  }
3951  if (is_vclass)
3952  {
3954  goto error;
3955  }
3956  }
3957 
3958  trigger->name = tr_process_name (name);
3959  if (trigger->name == NULL)
3960  {
3961  goto error;
3962  }
3963 
3964  if (attribute != NULL)
3965  {
3966  sm_downcase_name (attribute, realname, SM_MAX_IDENTIFIER_LENGTH);
3967  trigger->attribute = strdup (realname);
3968  }
3969  else
3970  {
3971  trigger->attribute = NULL;
3972  }
3973 
3974  if (attribute != NULL && trigger->attribute == NULL)
3975  {
3976  goto error;
3977  }
3978 
3979  /* build the condition */
3980  if (cond_source != NULL)
3981  {
3982  trigger->condition = make_activity ();
3983  if (trigger->condition == NULL)
3984  {
3985  goto error;
3986  }
3987 
3988  trigger->condition->type = TR_ACT_EXPRESSION;
3989  trigger->condition->source = strdup (cond_source);
3990  if (trigger->condition->source == NULL)
3991  {
3992  goto error;
3993  }
3994 
3995  if (cond_time != TR_TIME_NULL)
3996  {
3997  trigger->condition->time = cond_time;
3998  }
3999  else if (action_time != TR_TIME_NULL)
4000  {
4001  trigger->condition->time = action_time;
4002  }
4003  else
4004  {
4005  trigger->condition->time = TR_TIME_AFTER;
4006  }
4007  }
4008 
4009  /* build the action */
4010  if (action_type != TR_ACT_NULL)
4011  {
4012  if (action_type == TR_ACT_EXPRESSION && action_source == NULL)
4013  {
4015  goto error;
4016  }
4017 
4018  trigger->action = make_activity ();
4019  if (trigger->action == NULL)
4020  {
4021  goto error;
4022  }
4023 
4024  trigger->action->type = action_type;
4025  if (action_source != NULL)
4026  {
4027  trigger->action->source = strdup (action_source);
4028  if (trigger->action->source == NULL)
4029  {
4030  goto error;
4031  }
4032  }
4033 
4034  if (action_time != TR_TIME_NULL)
4035  {
4036  trigger->action->time = action_time;
4037  }
4038  else if (cond_time != TR_TIME_NULL)
4039  {
4040  trigger->action->time = cond_time;
4041  }
4042  else
4043  {
4044  trigger->action->time = TR_TIME_AFTER;
4045  }
4046  }
4047 
4048  /* make sure everything looks ok */
4049  if (check_semantics (trigger))
4050  {
4051  goto error;
4052  }
4053 
4054  /* be sure that the condition and action expressions can be compiled */
4055  if (trigger->condition != NULL && compile_trigger_activity (trigger, trigger->condition, 1))
4056  {
4057  goto error;
4058  }
4059 
4060  if (trigger->action != NULL && compile_trigger_activity (trigger, trigger->action, 0))
4061  {
4062  goto error;
4063  }
4064 
4065  if (TM_TRAN_ISOLATION () >= TRAN_REP_READ)
4066  {
4067  /* protect against multiple flushes to server */
4069  {
4070  goto error;
4071  }
4072 
4073  has_savepoint = true;
4074  }
4075 
4076  /* from here down, the unwinding when errors are encountered gets rather complex */
4077 
4078  /* convert to a persistent instance */
4079  object = trigger_to_object (trigger);
4080  if (object == NULL)
4081  {
4082  goto error;
4083  }
4084 
4085  /* put it on the "new" trigger list */
4086  if (insert_trigger_list (&tr_Uncommitted_triggers, trigger))
4087  {
4088  /*
4089  * we could't delete the trigger objects we just created ?
4090  * db_drop(object);
4091  */
4092  goto error;
4093  }
4094 
4095  /* add to global name table */
4096  if (trigger_table_add (trigger->name, object))
4097  {
4098  goto error;
4099  }
4100 
4101  /*
4102  * add to object map table, could check for trigger already at this
4103  * location but since this is a new MOP that "can't" happen
4104  */
4105  if (mht_put (tr_object_map, object, trigger) == NULL)
4106  {
4107  goto error;
4108  }
4109 
4110  tr_object_map_added = true;
4111 
4112  /* cache the trigger in the the schema or the user object for later reference */
4113  if (trigger->class_mop != NULL)
4114  {
4115  if (sm_add_trigger (trigger->class_mop, trigger->attribute, 0, trigger->object))
4116  {
4117  goto error;
4118  }
4119  }
4120  else
4121  {
4122  if (register_user_trigger (object))
4123  {
4124  goto error;
4125  }
4126  }
4127 
4128  if (TM_TRAN_ISOLATION () >= TRAN_REP_READ)
4129  {
4130  /* need to flush in isolation level >= RR, since in case of serializable conflict we have to abort the current
4131  * command */
4132  if (locator_all_flush () != NO_ERROR)
4133  {
4134  goto error;
4135  }
4136  }
4137 
4138  return object;
4139 
4140 error:
4141 
4142  if (trigger != NULL)
4143  {
4144  if (object != NULL)
4145  {
4146  if (tr_object_map_added)
4147  {
4148  (void) mht_rem (tr_object_map, trigger->object, NULL, NULL);
4149  }
4150 
4151  (void) trigger_table_drop (trigger->name);
4152  }
4153  remove_trigger_list (&tr_Uncommitted_triggers, trigger);
4155  free_trigger (trigger);
4156  }
4157 
4158  if (has_savepoint && er_errid () != ER_LK_UNILATERALLY_ABORTED)
4159  {
4161  }
4162 
4163  return NULL;
4164 }
4165 
4166 
4167 /* TRIGGER OBJECT LOCATION */
4168 
4169 /*
4170  * These functions locate triggers and return trigger instances.
4171  *
4172  */
4173 
4174 /*
4175  * tr_find_all_triggers() - This function returns a list of object pointers
4176  * return: error code
4177  * list(out): pointer to the return trigger object list
4178  *
4179  * Note:
4180  * The return list contains every user trigger owned by the user, and every class trigger such that the user has
4181  * the SELECT privilege for the class in its event target. The return object pointer list
4182  * must be freed using db_objlist_free it is no longer needed.
4183  *
4184  */
4185 int
4187 {
4188  int error;
4189  int save;
4190 
4191  AU_DISABLE (save);
4192 
4193  error = find_all_triggers (false, false, list);
4194 
4195  AU_ENABLE (save);
4196  return error;
4197 }
4198 
4199 /*
4200  * tr_find_trigger() - This function returns the object pointer of the trigger with the input name.
4201  * return: DB_OBJECT
4202  * name(in): trigger name
4203  * Note :
4204  * If no existing trigger has the name, or the user does not have the access privilege of the trigger, NULL
4205  * will be returned. If NULL is returned, the system will set the global error status indicating
4206  * the exact nature of the error.
4207  *
4208  * Errors:
4209  * ER_TR_TRIGGER_NOT_FOUND: A trigger with the specified name could not be located.
4210  * ER_TR_TRIGGER_SELECT_FAILURE: The trigger is a user trigger that does not belong to the user.
4211  * ER_AU_SELECT_FAILURE: The user does not have the SELECT privilege for the target class
4212  * of the specified target (the trigger must be a class trigger).
4213  *
4214  */
4215 DB_OBJECT *
4216 tr_find_trigger (const char *name)
4217 {
4218  DB_OBJECT *object;
4219  TR_TRIGGER *trigger;
4220  int save;
4221 
4222  object = NULL;
4223  AU_DISABLE (save);
4224 
4225  if (trigger_table_find (name, &object) == NO_ERROR)
4226  {
4227  if (object == NULL)
4228  {
4230  }
4231  else
4232  {
4233  trigger = tr_map_trigger (object, 1);
4234  if (trigger == NULL)
4235  {
4236  object = NULL;
4237  }
4238  else
4239  {
4240  if (!check_authorization (trigger, 0))
4241  {
4243  object = NULL;
4244  }
4245  }
4246  }
4247  }
4248 
4249  AU_ENABLE (save);
4250  return object;
4251 }
4252 
4253 /*
4254  * tr_find_event_triggers() - Locate all triggers that are defined for a particular event
4255  * return: int
4256  * event(in): event type
4257  * class_mop(in): target class
4258  * attribute(in): target attribute
4259  * active(in): flag to retrieve active status triggers only
4260  * list(out): pointer to the return list of object pointers
4261  *
4262  */
4263 int
4264 tr_find_event_triggers (DB_TRIGGER_EVENT event, DB_OBJECT * class_mop, const char *attribute, bool active,
4265  DB_OBJLIST ** list)
4266 {
4267  int error = NO_ERROR;
4268  int save;
4269 
4270  AU_DISABLE (save);
4271 
4272  /* check for sensible parameters and ALTER authorization for class */
4273  if (!check_target (event, class_mop, attribute))
4274  {
4275  ASSERT_ERROR_AND_SET (error);
4276  }
4277  else
4278  {
4279  error = find_event_triggers (event, class_mop, attribute, active, list);
4280  }
4281 
4282  AU_ENABLE (save);
4283  return error;
4284 }
4285 
4286 /*
4287  * tr_check_authorization() - This is used to see if a particular authorization is enabled for a trigger object
4288  * return: error code
4289  * trigger_object(in): trigger object
4290  * alter_flag(in): non-zero if needing alter authorization
4291  *
4292  * Note:
4293  * This is used to see if a particular authorization is enabled for a trigger object.
4294  * It is intended to be called by do_trigger to make sure that statement operations involving multiple triggers
4295  * can be performed without authorization errors.
4296  * Since trigger objects are individually authorized, we can't use db_check_authorization because the db_trigger class
4297  * is normally completely protected.
4298  * If the alter-flag is zero, we just check for basic read authorization
4299  * if the flag is non-zero, we also check for ALTER authorization on the associated class.
4300  */
4301 int
4302 tr_check_authorization (DB_OBJECT * trigger_object, int alter_flag)
4303 {
4304  int error = NO_ERROR;
4305  TR_TRIGGER *trigger;
4306  int save;
4307 
4308  AU_DISABLE (save);
4309 
4310  trigger = tr_map_trigger (trigger_object, 1);
4311 
4312  if (trigger == NULL)
4313  {
4314  ASSERT_ERROR_AND_SET (error);
4315  }
4316  else
4317  {
4318  if (!check_authorization (trigger, alter_flag))
4319  {
4320  ASSERT_ERROR_AND_SET (error);
4321  }
4322  }
4323 
4324  AU_ENABLE (save);
4325  return error;
4326 }
4327 
4328 /* TRIGGER REMOVAL */
4329 
4330 /*
4331  * tr_drop_trigger_internal() - This is a work function for tr_drop_trigger and is also called by tr_check_rollback_event
4332  * to get rid of triggers created during the current transaction
4333  * return: error code
4334  * trigger(in): trigger cache structure
4335  * rollback(in):
4336  *
4337  * Note:
4338  * It removes the trigger from the various structures it may be attached to and deletes it.
4339  * If this is part of the rollback operation, we're more tolerant of errors since this operation has to be
4340  * performed regardless.
4341  * ROLLBACK NOTES:
4342  * It probably isn't necessary that we remove things from the schema cache because the class will have been marked
4343  * dirty and will be re-loaded with the old trigger state during the next transaction.
4344  * The main thing this does is remove the object from the trigger mapping table.
4345  *
4346  */
4347 static int
4348 tr_drop_trigger_internal (TR_TRIGGER * trigger, int rollback, bool need_savepoint)
4349 {
4350  int error = NO_ERROR;
4351  int save;
4352  bool has_savepoint = false;
4353 
4354  if (need_savepoint)
4355  {
4356  /* protect against multiple flushes to server */
4358  if (error != NO_ERROR)
4359  {
4360  return error;
4361  }
4362 
4363  has_savepoint = true;
4364  }
4365 
4366  AU_DISABLE (save);
4367 
4368  /* remove it from the class or user cache */
4369  if (trigger->class_mop == NULL)
4370  {
4371  error = unregister_user_trigger (trigger, rollback);
4372  }
4373  else
4374  {
4375  error = sm_drop_trigger (trigger->class_mop, trigger->attribute, 0, trigger->object);
4376  /* if the class has been deleted, just ignore the error */
4377  if (error == ER_HEAP_UNKNOWN_OBJECT)
4378  {
4379  error = NO_ERROR;
4380  }
4381  }
4382 
4383  if (error == NO_ERROR || rollback)
4384  {
4385  /* remove it from the uncommitted trigger list (if its on there) */
4386  remove_trigger_list (&tr_Uncommitted_triggers, trigger);
4387 
4388  /* remove it from the memory cache */
4389  error = tr_unmap_trigger (trigger);
4390 
4391  if (error == NO_ERROR || rollback)
4392  {
4393  /* remove it from the global name table */
4394  error = trigger_table_drop (trigger->name);
4395 
4396  if (error == NO_ERROR && !rollback)
4397  {
4398  /*
4399  * if this isn't a rollback, delete the object, otherwise
4400  * it will already be marked as deleted as part of the normal transaction cleanup
4401  */
4402  db_drop (trigger->object);
4403 
4404  /*
4405  * flush, decache object; no need to check if the object was indeed deleted;
4406  * it is supposed that the last version of the object was locked and deleted
4407  * because only the last version can be locked; previous versions are in the log
4408  */
4409  error = locator_flush_instance (trigger->object);
4410  if (error == NO_ERROR)
4411  {
4412  ws_decache (trigger->object);
4413  ws_clear_hints (trigger->object, false);
4414  }
4415  }
4416 
4417  /* free the cache structure */
4418  free_trigger (trigger);
4419  }
4420  }
4421 
4422  AU_ENABLE (save);
4423 
4424  if (need_savepoint && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
4425  {
4427  }
4428 
4429  return error;
4430 }
4431 
4432 /*
4433  * tr_drop_trigger() - Removes a trigger from the system.
4434  * return: error
4435  * obj(in): trigger object
4436  * call_from_api(in): call from api flag
4437  *
4438  * Note:
4439  * We still check to make sure the active user is the owner of the trigger before proceeding.
4440  */
4441 int
4442 tr_drop_trigger (DB_OBJECT * obj, bool call_from_api)
4443 {
4444  int error = NO_ERROR;
4445  TR_TRIGGER *trigger;
4446  char *trigger_name = NULL;
4447  int save;
4448 
4449  /* Do we need to disable authorization just for check_authorization ? */
4450  AU_DISABLE (save);
4451 
4452  /*
4453  * Turn off the "fetch" flag to tr_map_trigger so we don't attempt to validate the trigger by compiling
4454  * the statements, etc. As we're going to delete it, we don't care if the trigger is valid or not.
4455  * In particular this is necessary if any of the triggers referenced classes have been deleted
4456  * because the validation will fail tr_map_trigger would return an error.
4457  */
4458 
4459  trigger = tr_map_trigger (obj, false);
4460  if (trigger == NULL)
4461  {
4462  ASSERT_ERROR_AND_SET (error);
4463  }
4464  else
4465  {
4466  trigger_name = strdup (trigger->name);
4467  }
4468 
4469  if (trigger == NULL)
4470  {
4471  ;
4472  }
4473  else if (!check_authorization (trigger, true))
4474  {
4476  error = er_errid ();
4477  }
4478  else
4479  {
4480  if ((trigger->condition && trigger->condition->time == TR_TIME_DEFERRED)
4481  || (trigger->action && trigger->action->time == TR_TIME_DEFERRED))
4482  {
4483  error = tr_drop_deferred_activities (obj, NULL);
4484  }
4485 
4486  if (error == NO_ERROR)
4487  {
4488  bool need_savepoint = (TM_TRAN_ISOLATION () >= TRAN_REP_READ);
4489 
4490  error = tr_drop_trigger_internal (trigger, 0, need_savepoint);
4491  }
4492  }
4493 
4494  AU_ENABLE (save);
4495 
4496  if (trigger_name)
4497  {
4498  free_and_init (trigger_name);
4499  }
4500 
4501  return error;
4502 }
4503 
4504 /* CONDITION & ACTION EVALUATION */
4505 
4506 /*
4507  * value_as_boolean() - This maps a value container into a boolean value.
4508  * return: boolean (zero or non-zero)
4509  * value(in): standard value container
4510  *
4511  * Note:
4512  * It is intended to be used where condition expressions can return any value but the result must be treated as a boolean.
4513  * The status will be false if the value contains one of the numeric types whose value is zero.
4514  * The status will also be false if the value is of type DB_TYPE_NULL. For all other data types, the status will be true.
4515  * NOTE: This means that an empty string will be true as will sets with no elements.
4516  */
4517 static bool
4519 {
4520  bool status = true;
4521 
4522  switch (DB_VALUE_TYPE (value))
4523  {
4524  case DB_TYPE_NULL:
4525  status = false;
4526  break;
4527  case DB_TYPE_SHORT:
4528  status = (db_get_short (value) == 0) ? false : true;
4529  break;
4530  case DB_TYPE_INTEGER:
4531  status = (db_get_int (value) == 0) ? false : true;
4532  break;
4533  case DB_TYPE_BIGINT:
4534  status = (db_get_bigint (value) == 0) ? false : true;
4535  break;
4536  case DB_TYPE_FLOAT:
4537  status = (db_get_float (value) == 0) ? false : true;
4538  break;
4539  case DB_TYPE_DOUBLE:
4540  status = (db_get_double (value) == 0) ? false : true;
4541  break;
4542  case DB_TYPE_TIME:
4543  status = (*db_get_time (value) == 0) ? false : true;
4544  break;
4545  case DB_TYPE_TIMESTAMP:
4546  case DB_TYPE_TIMESTAMPLTZ:
4547  status = (*db_get_timestamp (value) == 0) ? false : true;
4548  break;
4549  case DB_TYPE_TIMESTAMPTZ:
4550  {
4551  DB_TIMESTAMPTZ *ts_tz = db_get_timestamptz (value);
4552 
4553  status = (ts_tz->timestamp == 0) ? false : true;
4554  }
4555  break;
4556  case DB_TYPE_DATETIME:
4557  case DB_TYPE_DATETIMELTZ:
4558  status = (db_get_datetime (value)->date == 0 && db_get_datetime (value)->time == 0) ? false : true;
4559  break;
4560  case DB_TYPE_DATETIMETZ:
4561  {
4562  DB_DATETIMETZ *dt_tz = db_get_datetimetz (value);
4563 
4564  status = (dt_tz->datetime.date == 0 && dt_tz->datetime.time == 0) ? false : true;
4565  }
4566  break;
4567  case DB_TYPE_DATE:
4568  status = (*db_get_date (value) == 0) ? false : true;
4569  break;
4570  case DB_TYPE_MONETARY:
4571  status = (db_get_monetary (value)->amount == 0) ? false : true;
4572  break;
4573 
4574  default:
4575  status = true;
4576  }
4577 
4578  return status;
4579 }
4580 
4581 /*
4582  * signal_evaluation_error() - This is called when a trigger condition or action could not be evaluated.
4583  * return: error code
4584  * trigger(in): trigger of interest
4585  * error(in):
4586  *
4587  * Note:
4588  * We take whatever the last error was set by the parser and package it up into an error that contains the name
4589  * of the trigger so we have some context to determine what went wrong. This is especially if the error happens
4590  * during the evaluation of a deferred trigger at commit time.
4591  * Note that since the error text is kept in a static buffer, we can't pass it to er_set() without corrupting things.
4592  * Must copy it into a temp buffer.
4593  */
4594 static int
4596 {
4597  char buffer[MAX_ERROR_STRING];
4598  const char *msg;
4599 
4600  /*
4601  * if we've already set this error, don't do it again, this is for recursive triggers so we don't keep tacking
4602  * on the name 'n' times for each level of call
4603  */
4605  {
4606  msg = er_msg ();
4607  if (msg == NULL)
4608  {
4609  strcpy (buffer, "");
4610  }
4611  else
4612  {
4613  strncpy (buffer, msg, sizeof (buffer) - 1);
4614  buffer[MAX_ERROR_STRING - 1] = '\0';
4615  }
4616 
4617  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, trigger->name, buffer);
4618  }
4619 
4620  return error;
4621 }
4622 
4623 /*
4624  * eval_condition() - The function evaluates the input trigger condition.
4625  * return: TR_RETURN_ERROR/TR_RETURN_TRUE/TR_RETURN_FALSE
4626  * trigger(in):
4627  * current(in):
4628  * temp(in):
4629  * status(in):
4630  *
4631  */
4632 static int
4633 eval_condition (TR_TRIGGER * trigger, DB_OBJECT * current, DB_OBJECT * temp, bool * status)
4634 {
4635  int error = NO_ERROR;
4636  TR_ACTIVITY *act;
4637  DB_VALUE value;
4638  int pt_status;
4639 
4640  act = trigger->condition;
4641  if (act == NULL)
4642  {
4643  return NO_ERROR;
4644  }
4645 
4646  if (tr_Trace)
4647  {
4648  fprintf (stdout, "TRACE: Evaluating condition for trigger \"%s\".\n", trigger->name);
4649  }
4650 
4651  if (act->type != TR_ACT_EXPRESSION)
4652  {
4653  /* this should have been checked by now */
4655  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
4656  }
4657  else
4658  {
4659  /* should have been done by now */
4660  if (tr_Current_depth <= 1 && ++act->exec_cnt > prm_get_integer_value (PRM_ID_RESET_TR_PARSER)
4662  {
4663  if (act->parser != NULL)
4664  {
4666  act->parser = NULL;
4667  }
4668  act->exec_cnt = 0;
4669  }
4670 
4671  if (act->parser == NULL)
4672  {
4673  error = compile_trigger_activity (trigger, act, 1);
4674  }
4675 
4676  if (error == NO_ERROR)
4677  {
4678  if (act->parser == NULL || act->statement == NULL)
4679  {
4680  /* shouldn't happen */
4681  error = ER_TR_INTERNAL_ERROR;
4682  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
4683  }
4684  else
4685  {
4686  if (current == NULL)
4687  {
4688  current = temp;
4689  temp = NULL;
4690  }
4691 
4692  pt_status = pt_exec_trigger_stmt ((PARSER_CONTEXT *) act->parser, (PT_NODE *) act->statement, current,
4693  temp, &value);
4694  /*
4695  * recall that pt_exec_trigger_stmt can return a positive
4696  * value for success, errors must be checked against negative
4697  */
4698  if (pt_status < 0)
4699  {
4700  error = signal_evaluation_error (trigger, ER_TR_CONDITION_EVAL);
4701  }
4702  else
4703  {
4704  *status = value_as_boolean (&value);
4705  }
4706 
4707  /*
4708  * kludage, until we figure out how to reuse the same
4709  * parser over and over, we have to throw away the
4710  * copmiled expression and do it again the next time
4711  */
4712 #if 0
4713  parser_free_parser (act->parser);
4714  act->parser = NULL;
4715  act->statement = NULL;
4716 #endif /* 0 */
4717 
4718  }
4719  }
4720  }
4721 
4722  return error;
4723 }
4724 
4725 /*
4726  * tr_check_recursivity() - Analyze the trigger stack and detect if the given trigger has occured earlier: this is a way
4727  * to detect recursive trigger chains at runtime.
4728  * return: TR_DECISION_CONTINUE - no recursion found
4729  * TR_DECISION_HALT_WITH_ERROR - found recursive triggers
4730  * TR_DECISION_DO_NOT_CONTINUE - found recursive STATEMENT trigger
4731  * oid (in): OID of trigger to analyze
4732  * stack(in): array of stack_size OIDs of the calling triggers
4733  * stack_size(in):
4734  * is_statement(in): if the current trigger is a STATEMENT one and it turns out it is recursive,
4735  * ignore it silently, with no error
4736  */
4737 static TR_RECURSION_DECISION
4738 tr_check_recursivity (OID oid, OID stack[], int stack_size, bool is_statement)
4739 {
4740  int i, min;
4741 
4742  assert (stack);
4743  assert (stack_size < TR_MAX_RECURSION_LEVEL);
4744 
4745  /* we allow recursive triggers, if they are not STATEMENT triggers */
4746  if (!is_statement)
4747  {
4748  return TR_DECISION_CONTINUE;
4749  }
4750 
4751  min = MIN (stack_size, TR_MAX_RECURSION_LEVEL);
4752  for (i = 0; i < min; i++)
4753  {
4754  if (oid_compare (&oid, &stack[i]) == 0)
4755  {
4756  /* this is a STATEMENT trigger, we should not go further with the action, but we should allow the call to
4757  * succeed.
4758  */
4760  }
4761  }
4762 
4763  return TR_DECISION_CONTINUE;
4764 }
4765 
4766 /*
4767  * eval_action() - The function evaluates the input trigger action.
4768  * return: int
4769  * trigger(in):
4770  * current(in):
4771  * temp(in):
4772  * reject(in):
4773  *
4774  */
4775 static int
4776 eval_action (TR_TRIGGER * trigger, DB_OBJECT * current, DB_OBJECT * temp, bool * reject)
4777 {
4778  int error = NO_ERROR;
4779  TR_ACTIVITY *act;
4780  DB_VALUE value;
4781  int pt_status;
4782  OID oid_of_trigger;
4784  bool is_statement = false;
4785  bool used_cached_statement = true;
4786 
4787  if (trigger->object)
4788  {
4789  oid_of_trigger = trigger->object->oid_info.oid;
4790  }
4791  else
4792  {
4793  error = ER_TR_INTERNAL_ERROR;
4794  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
4795  return error;
4796  }
4797 
4798  assert (0 < tr_Current_depth);
4799 
4800  /* If this is NOT a statement trigger, we just continue through. Recursive triggers will step past the max depth and
4801  * will be rejected. STATEMENT triggers, on the other side, should be fired only once. This is why we keep the OID
4802  * stack and we check it if we have a STATEMENT trig.
4803  */
4804  is_statement = (trigger->event == TR_EVENT_STATEMENT_DELETE || trigger->event == TR_EVENT_STATEMENT_INSERT
4805  || trigger->event == TR_EVENT_STATEMENT_UPDATE);
4806 
4807  if (is_statement)
4808  {
4809  dec = tr_check_recursivity (oid_of_trigger, tr_Stack, tr_Current_depth - 1, is_statement);
4810  switch (dec)
4811  {
4815  return error;
4816 
4818  return NO_ERROR;
4819 
4820  case TR_DECISION_CONTINUE:
4821  break;
4822  }
4823  }
4824 
4826  {
4827  tr_Stack[tr_Current_depth - 1] = oid_of_trigger;
4828  }
4829  else
4830  {
4831  assert (false);
4832  }
4833 
4834  act = trigger->action;
4835  if (act != NULL)
4836  {
4837  if (tr_Trace)
4838  {
4839  fprintf (stdout, "TRACE: Executing action for trigger \"%s\".\n", trigger->name);
4840  }
4841 
4842  switch (act->type)
4843  {
4844  case TR_ACT_REJECT:
4845  *reject = true;
4846  break;
4847 
4848  case TR_ACT_INVALIDATE:
4849  tr_Invalid_transaction = true;
4850  /* remember the name for the error message */
4851  strncpy (tr_Invalid_transaction_trigger, trigger->name, sizeof (tr_Invalid_transaction_trigger) - 1);
4852  break;
4853 
4854  case TR_ACT_PRINT:
4855  if (trigger->action->source != NULL)
4856  {
4857  fprintf (stdout, "%s\n", trigger->action->source);
4858  }
4859  break;
4860 
4861  case TR_ACT_EXPRESSION:
4862  compile_stmt_again:
4863  if (tr_Current_depth <= 1 && ++act->exec_cnt > prm_get_integer_value (PRM_ID_RESET_TR_PARSER)
4865  {
4866  if (act->parser != NULL)
4867  {
4869  act->parser = NULL;
4870  }
4871  act->exec_cnt = 0;
4872  }
4873  if (act->parser == NULL)
4874  {
4875  error = compile_trigger_activity (trigger, act, 0);
4876  used_cached_statement = false;
4877  }
4878 
4879  if (error != NO_ERROR)
4880  {
4881  break;
4882  }
4883 
4884  if (act->parser == NULL || act->statement == NULL)
4885  {
4886  /* shouldn't happen */
4887  error = ER_TR_INTERNAL_ERROR;
4888  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
4889  }
4890  else
4891  {
4892  if (current == NULL)
4893  {
4894  current = temp;
4895  temp = NULL;
4896  }
4897 
4898  pt_status =
4899  pt_exec_trigger_stmt ((PARSER_CONTEXT *) act->parser, (PT_NODE *) act->statement, current, temp,
4900  &value);
4901 
4902  /* If using the cached statement and ER_QPROC_INVALID_XASLNODE error returned, It means that the
4903  * act->statement is old or invalid. It should be re-compiled again.
4904  */
4905  if (pt_status == ER_QPROC_INVALID_XASLNODE && used_cached_statement)
4906  {
4908  act->parser = NULL;
4909  act->statement = NULL;
4910 
4911  er_clear ();
4912  goto compile_stmt_again;
4913  }
4914 
4915  /*
4916  * recall that pt_exec_trigger_stmt can return positive
4917  * values to indicate success, errors must be explicitly
4918  * checked for < 0
4919  */
4920 
4921  if (pt_status < 0)
4922  {
4923  error = signal_evaluation_error (trigger, ER_TR_ACTION_EVAL);
4924  /*
4925  * Reset the error stuff so that we'll try things
4926  * afresh the next time we reuse this parser.
4927  */
4929  }
4930 
4931  /*
4932  * kludge, until we figure out how to reuse the same
4933  * parser over and over, we have to throw away the
4934  * copmiled expression and do it again the next time
4935  */
4936 #if 0
4937  parser_free_parser (act->parser);
4938  act->parser = NULL;
4939  act->statement = NULL;
4940 #endif /* 0 */
4941  }
4942  break;
4943 
4944  default:
4945  error = ER_TR_INTERNAL_ERROR;
4946  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
4947  break;
4948  }
4949  }
4950 
4951  return error;
4952 }
4953 
4954 /*
4955  * execute_activity() - The function executes the condition or action or condition and action of the trigger according to
4956  * the following rules.
4957  * return: int
4958  * trigger(in): trigger
4959  * tr_time(in): execution time
4960  * current(in):
4961  * temp(in):
4962  * rejected(in):
4963  *
4964  * Note:
4965  * If the execution of the condition is the same as the argument time, the condition will be evaluated.
4966  * If the condition is evaluated as true, or the execution time of the condition is less than the argument time,
4967  * the action will be considered.
4968  * If the action is considered and the execution time of the action is the same as the argument time,
4969  * the action will be executed.
4970  * The function returns TR_RETURN_ERROR if there is an error.
4971  * Otherwise, it returns TR_RETURN_TRUE if the action is executed or does not need to be executed (because of the
4972  * condition), or TR_RETURN_FALSE for the other cases.
4973  * If the action is "REJECT", the argument is_reject_action returns true.
4974  */
4975 static int
4976 execute_activity (TR_TRIGGER * trigger, DB_TRIGGER_TIME tr_time, DB_OBJECT * current, DB_OBJECT * temp, bool * rejected)
4977 {
4978  int rstatus;
4979  bool execute_action;
4980  DB_OBJECT *save_user;
4981 
4982  save_user = NULL;
4983  if (trigger->owner != NULL)
4984  {
4985  save_user = Au_user;
4986  if (AU_SET_USER (trigger->owner))
4987  {
4988  return TR_RETURN_ERROR;
4989  }
4990  }
4991 
4992  rstatus = TR_RETURN_TRUE;
4993  *rejected = false;
4994 
4995  /* assume that we will be removing the trigger by returning true */
4996  execute_action = true;
4997 
4998  /*
4999  * If the trigger isn't active, ignore it. It would be more effecient if the inactive triggers could be filtered from
5000  * the lists as the combined list is built
5001  */
5002  if (trigger->status == TR_STATUS_ACTIVE)
5003  {
5004  if (trigger->condition != NULL)
5005  {
5006  execute_action = false;
5007  if (trigger->condition->time == tr_time)
5008  {
5009  if (eval_condition (trigger, current, temp, &execute_action) != NO_ERROR)
5010  {
5011  rstatus = TR_RETURN_ERROR;
5012  }
5013  }
5014  else if ((int) trigger->condition->time > (int) tr_time)
5015  {
5016  /* activity is to be considered later, return false */
5017  rstatus = TR_RETURN_FALSE;
5018  }
5019 
5020  else
5021  {
5022  /*
5023  * else, the time has passed, only see this if the condition has
5024  * been fired but the action comes later
5025  */
5026  execute_action = true;
5027  }
5028  }
5029 
5030  if (execute_action && trigger->action != NULL)
5031  {
5032  if (trigger->action->time == tr_time)
5033  {
5034  if (eval_action (trigger, current, temp, rejected) != NO_ERROR)
5035  {
5036  rstatus = TR_RETURN_ERROR;
5037  }
5038 
5039  }
5040  else
5041  {
5042  /*
5043  * the action is not ready yet, return false to keep it
5044  * on the list
5045  */
5046 
5047  rstatus = TR_RETURN_FALSE;
5048  }
5049  }
5050  }
5051 
5052  if (save_user != NULL)
5053  {
5054  if (AU_SET_USER (save_user))
5055  {
5056  /* what can this mean ? */
5057  rstatus = TR_RETURN_ERROR;
5058  }
5059  }
5060 
5061  return rstatus;
5062 }
5063 
5064 /*
5065  * tr_execute_activities() - The function executes the conditions or actions or conditions and actions of all triggers
5066  * in the array that have the input execution time
5067  * return: int
5068  * state(in): trigger state
5069  * tr_time(in): execution time
5070  * current(in): object associated with "current"
5071  * temp(in): object associated with "new" or "old"
5072  *
5073  * Note:
5074  * The input execution time must not be TR_TIME_DEFERRED. For triggers in the array whose conditions are executed
5075  * and evaluated as true, their actions are also executed if they have the same execution time.
5076  * These triggers are then removed from the array. If any of these triggers has an action whose execution time is greater
5077  * than the execution time of its condition, the trigger is still kept in the array.
5078  * In the course of evaluating conditions and actions, if a "REJECT" action is encountered, the event action and
5079  * all the conditions and actions that are not yet executed will be suspended.
5080  */
5081 static int
5083 {
5084  int error = NO_ERROR;
5085  TR_TRIGLIST *t, *next;
5086  int status;
5087  bool rejected;
5088 
5089  for (t = state->triggers, next = NULL; t != NULL && error == NO_ERROR; t = next)
5090  {
5091  next = t->next;
5092 
5093  status = execute_activity (t->trigger, tr_time, current, temp, &rejected);
5094 
5095  if (status == TR_RETURN_TRUE)
5096  {
5097  /* if rejected, signal an error and abort */
5098  if (rejected)
5099  {
5100  error = ER_TR_REJECTED;
5102  }
5103 
5104  /* successful processing, remove it from the list */
5106  }
5107  else if (status == TR_RETURN_ERROR)
5108  {
5109  ASSERT_ERROR_AND_SET (error);
5110  }
5111 
5112  /* else the trigger isn't ready yet, leave it on the list */
5113  }
5114 
5115  return error;
5116 }
5117 
5118 /*
5119  * run_user_triggers() - This runs triggers on the user trigger cache.
5120  * return: error code
5121  * event(in): event type to run
5122  * time(in):
5123  *
5124  * Note:
5125  * It is called by the various functions that handle various types of user trigger events.
5126  * Because the user triggers are maintained on a cache, we have to validate it before we can proceed.
5127  * We don't really have to worry about times right now because the user triggers all have limitations on their times.
5128  * The trigger cache will be sorted in priority order. We could have multiple lists for each type
5129  * but don't bother right now since there aren't likely to be very many of these.
5130  */
5131 static int
5133 {
5134  TR_TRIGLIST *t;
5135  TR_STATE *state_p;
5136  int error = NO_ERROR;
5137  int status;
5138  bool rejected;
5139 
5140  /* check the cache */
5142  {
5143  if (tr_update_user_cache () != NO_ERROR)
5144  {
5145  ASSERT_ERROR_AND_SET (error);
5146  return error;
5147  }
5148  }
5149 
5150  for (t = tr_User_triggers; t != NULL && !error; t = t->next)
5151  {
5152  if (t->trigger->event == event && t->trigger->status == TR_STATUS_ACTIVE)
5153  {
5154  state_p = NULL;
5155  if (start_state (&state_p, t->trigger->name) == NULL)
5156  {
5157  ASSERT_ERROR_AND_SET (error);
5158  break;
5159  }
5160 
5161  status = execute_activity (t->trigger, time, NULL, NULL, &rejected);
5162 
5163  tr_finish (state_p);
5164 
5165  if (status == TR_RETURN_TRUE)
5166  {
5167  /* if rejected, signal an error and abort */
5168  if (rejected)
5169  {
5170  error = ER_TR_REJECTED;
5172  }
5173  }
5174  else if (status == TR_RETURN_ERROR)
5175  {
5176  ASSERT_ERROR_AND_SET (error);
5177  }
5178  }
5179  }
5180 
5181  return error;
5182 }
5183 
5184 /* TRIGGER SIGNALING */
5185 
5186 /*
5187  * compare_recursion_levels() - The function compares two recursion levels.
5188  * return: int
5189  * rl_1(in): a recursion level
5190  * rl_2(in): a recursion level
5191  *
5192  * Note:
5193  * It returns 0 if they are equal,
5194  * 1 if the the first is greater than the second, or
5195  * -1 if the first is less than the second.
5196  */
5197 static int
5198 compare_recursion_levels (int rl_1, int rl_2)
5199 {
5200  int ret;
5201 
5202  if (rl_1 == rl_2)
5203  {
5204  ret = 0;
5205  }
5206  else
5207  {
5208  ret = (rl_1 > rl_2) ? 1 : -1;
5209  }
5210 
5211  return ret;
5212 }
5213 
5214 /*
5215  * start_state() - This is used to create a new state or validate an existing one.
5216  * return: state structure
5217  * current(in): existing state pointer
5218  * name(in):
5219  *
5220  * Note:
5221  * If we have to create a new one, check the recursion level for runaway triggers.
5222  */
5223 static TR_STATE *
5224 start_state (TR_STATE ** current, const char *name)
5225 {
5226  TR_STATE *state;
5227 
5228  state = *current;
5229  if (state == NULL)
5230  {
5231  ++tr_Current_depth;
5233  {
5235  --tr_Current_depth;
5236  }
5237  else
5238  {
5239  state = make_state ();
5240  if (state != NULL)
5241  {
5242  *current = state;
5243  }
5244  }
5245  }
5246 
5247  return state;
5248 }
5249 
5250 /*
5251  * tr_prepare_statement() - This is called by do_statement() to prepare a trigger state structure for triggers that
5252  * will be raised by a statement.
5253  * return: error code
5254  * state_p(out):
5255  * event(in): event type
5256  * class(in): class being touched
5257  * attcount(in): number of entries in attribute name array
5258  * attnames(in): attribute name array
5259  *
5260  * Note:
5261  * Could build the trigger list separately and pass it to tr_prepare() but in this case we will always
5262  * be throwing away the merged list so it doesn't really matter.
5263  * If the statement is repeatable (in ESQL) it would be better if we could cache the trigger list in the parse tree
5264  * rather than having to derive it each time.
5265  */
5266 int
5267 tr_prepare_statement (TR_STATE ** state_p, DB_TRIGGER_EVENT event, DB_OBJECT * class_mop, int attcount,
5268  const char **attnames)
5269 {
5270  int error = NO_ERROR;
5271  TR_STATE *state;
5272  TR_TRIGLIST *triggers;
5273  TR_SCHEMA_CACHE *cache;
5274  int i, save;
5275 
5276  /*
5277  * Since we may be accessing this through a view, disable authorization during the building of the trigger lists.
5278  * Later when we actually evaluate the trigger condition/action, we will temporarily set the effective user
5279  * to the owner of the trigger.
5280  */
5281  AU_DISABLE (save);
5282 
5283  /* locate the list of triggers for this event */
5284  triggers = NULL;
5285 
5286  /* could avoid repeated schema authorization checks */
5287  error = sm_get_trigger_cache (class_mop, NULL, 0, (void **) &cache);
5288  if (error != NO_ERROR)
5289  {
5290  if (error == ER_HEAP_UNKNOWN_OBJECT)
5291  {
5292  /* Probably the client re-uses existing parse tree which refers a dropped table. To confirm it includes a
5293  * modified table, raise ER_QPROC_INVALID_XASLNODE.
5294  */
5296  }
5297 
5298  goto error_return;
5299  }
5300 
5301  if (cache != NULL)
5302  {
5303  if (tr_validate_schema_cache (cache, class_mop))
5304  {
5305  goto error_return;
5306  }
5307 
5308  if (event < cache->array_length)
5309  {
5310  if (merge_trigger_list (&triggers, cache->triggers[event], 0))
5311  {
5312  goto error_return;
5313  }
5314  }
5315  /* else error ? */
5316  }
5317 
5318  for (i = 0; i < attcount; i++)
5319  {
5320  error = sm_get_trigger_cache (class_mop, attnames[i], 0, (void **) &cache);
5321  if (error != NO_ERROR)
5322  {
5323  if (error == ER_HEAP_UNKNOWN_OBJECT)
5324  {
5325  /* Probably the client re-uses existing parse tree which refers a dropped table. To confirm it includes a
5326  * modified table, raise ER_QPROC_INVALID_XASLNODE.
5327  */
5329  }
5330  goto error_return;
5331  }
5332 
5333  if (cache != NULL)
5334  {
5335  if (tr_validate_schema_cache (cache, class_mop))
5336  {
5337  goto error_return;
5338  }
5339  else
5340  {
5341  if (event < cache->array_length)
5342  {
5343  error = merge_trigger_list (&triggers, cache->triggers[event], 0);
5344  if (error != NO_ERROR)
5345  {
5346  goto error_return;
5347  }
5348  }
5349  }
5350  }
5351  }
5352 
5353  /*
5354  * Construct a state structure for these events. If we get to the point where we can cache the trigger list
5355  * in the parse tree, the list should be returned here and passed to tr_prepare().
5356  */
5357  if (triggers != NULL)
5358  {
5359  /* pass in the first trigger name for the recursion error message */
5360  state = start_state (state_p, triggers->trigger->name);
5361  if (state == NULL)
5362  {
5363  ASSERT_ERROR_AND_SET (error);
5364  goto error_return;
5365  }
5366  else
5367  {
5368  if (state->triggers == NULL)
5369  {
5370  state->triggers = triggers;
5371  }
5372  else
5373  {
5374  error = merge_trigger_list (&state->triggers, triggers, 1);
5375  if (error != NO_ERROR)
5376  {
5377  ASSERT_ERROR_AND_SET (error);
5378  goto error_return;
5379  }
5380  }
5381  }
5382  }
5383 
5384  AU_ENABLE (save);
5385  return error;
5386 
5387 error_return:
5388  if (triggers != NULL)
5389  {
5390  tr_free_trigger_list (triggers);
5391  }
5392 
5393  AU_ENABLE (save);
5394 
5395  ASSERT_ERROR_AND_SET (error);
5396  return error;
5397 }
5398 
5399 #if defined(ENABLE_UNUSED_FUNCTION)
5400 /*
5401  * tr_prepare() - This begins the preparation for trigger evaluation.
5402  * It may be called multiple times before calling tr_before().
5403  * return: error code
5404  * state_p(in): list of triggers to be prepared
5405  * triggers(in):
5406  *
5407  */
5408 int
5409 tr_prepare (TR_STATE ** state_p, TR_TRIGLIST * triggers)
5410 {
5411  int error = NO_ERROR;
5412  TR_STATE *state;
5413  const char *name;
5414  int save;
5415 
5416  /*
5417  * Disable authorization here since trigger scheduling is independent
5418  * of the current user. This will only only be necessary if we
5419  * have to fetch the trigger's owning class for some reason here.
5420  */
5421  AU_DISABLE (save);
5422 
5423  /* pass in the first trigger name for the recursion error message */
5424  name = (triggers != NULL) ? triggers->trigger->name : NULL;
5425  state = start_state (state_p, name);
5426  if (state == NULL)
5427  {
5428  assert (er_errid () != NO_ERROR);
5429  error = er_errid ();
5430  }
5431  else
5432  {
5433  merge_trigger_list (&state->triggers, triggers, 0);
5434  }
5435 
5436  AU_ENABLE (save);
5437 
5438  return error;
5439 }
5440 #endif /* ENABLE_UNUSED_FUNCTION */
5441 
5442 /*
5443  * tr_prepare_class() - This is used to prepare a trigger state for an event on a class.
5444  * return: error code
5445  * state_p(in/out): trigger state pointer
5446  * cache(in): class trigger cache
5447  * class_mop(in): class mop
5448  * event(in): event being raised
5449  *
5450  */
5451 int
5452 tr_prepare_class (TR_STATE ** state_p, TR_SCHEMA_CACHE * cache, MOP class_mop, DB_TRIGGER_EVENT event)
5453 {
5454  int error = NO_ERROR;
5455  TR_STATE *state;
5456  TR_TRIGLIST *triggers;
5457  const char *name;
5458  int save;
5459 
5460  if (!TR_EXECUTION_ENABLED)
5461  {
5462  *state_p = NULL;
5463  return NO_ERROR;
5464  }
5465 
5466  if (cache == NULL)
5467  {
5468  return NO_ERROR;
5469  }
5470 
5471  /*
5472  * Disable authorization here since trigger scheduling is independent * of the current user.
5473  * This will only only be necessary if we have to fetch the trigger's owning class for some reason here.
5474  */
5475  AU_DISABLE (save);
5476 
5477  if (tr_validate_schema_cache (cache, class_mop) != NO_ERROR)
5478  {
5479  assert (er_errid () != NO_ERROR);
5480  error = er_errid ();
5481  }
5482  else if (event < cache->array_length)
5483  {
5484  triggers = cache->triggers[event];
5485 
5486  /* pass in name of first trigger for message */
5487  name = (triggers != NULL) ? triggers->trigger->name : NULL;
5488  state = start_state (state_p, name);
5489  if (state == NULL)
5490  {
5491  ASSERT_ERROR_AND_SET (error);
5492  }
5493  else
5494  {
5495  merge_trigger_list (&state->triggers, triggers, 0);
5496  }
5497  }
5498  else
5499  {
5500  assert (false);
5501  }
5502 
5503  AU_ENABLE (save);
5504  return error;
5505 }
5506 
5507 /*
5508  * tr_finish() - The function wraps up the firing of a trigger.
5509  * return: none
5510  * state(in): trigger execution state
5511  *
5512  * Note: The function wraps up the firing of a trigger.
5513  * Note that at this point, only triggers containing deferred conditions or actions remain in the array and
5514  * the list of raised triggers.
5515  */
5516 static void
5518 {
5519  /* if we have to touch the trigger class for any reason, we'll need to disable authorization here */
5520 
5521  if (state)
5522  {
5523  free_state (state);
5524  --tr_Current_depth;
5525  }
5526 }
5527 
5528 /*
5529  * tr_abort() - The function aborts the rest of the trigger firing operation.
5530  * In addition to freeing the state, this will also cancel anything on the raised trigger list.
5531  * return: none
5532  * state(in): trigger execution state
5533  *
5534  */
5535 void
5537 {
5538  /* if we have to touch the trigger class for any reason, we'll need to disable authorization here */
5539 
5540  /* don't really need to do anything other than free the existing state */
5541  if (state)
5542  {
5543  tr_finish (state);
5544  }
5545 }
5546 
5547 /*
5548  * tr_before_object() - The function tr_before_object should be used after tr_prepare.
5549  * return: error
5550  * state(in): trigger execution state
5551  * current(in): current event object
5552  * temp(in): temporary event object
5553  *
5554  * Note:
5555  * See the Note of tr_prepare.
5556  * Trigger conditions and actions with execution time BEFORE are evaluated and executed in tr_before_object other
5557  * conditions and actions are handled in tr_after_object.
5558  *
5559  */
5560 int
5561 tr_before_object (TR_STATE * state, DB_OBJECT * current, DB_OBJECT * temp)
5562 {
5563  int error = NO_ERROR;
5564 
5565  if (!TR_EXECUTION_ENABLED)
5566  {
5567  return NO_ERROR;
5568  }
5569 
5570  if (state)
5571  {
5572  error = tr_execute_activities (state, TR_TIME_BEFORE, current, temp);
5573  if (error != NO_ERROR)
5574  {
5575  tr_abort (state);
5576  }
5577  }
5578 
5579  return error;
5580 }
5581 
5582 /*
5583  * tr_before() - The function tr_before should be used after tr_prepare.
5584  * return: error code
5585  * state(in): trigger execution state
5586  *
5587  * Note:
5588  * See the Note of tr_prepare.
5589  * Trigger conditions and actions with execution time BEFORE are evaluated and executed in tr_before;
5590  * other conditions and actions are handled in tr_after.
5591  */
5592 int
5594 {
5595  return tr_before_object (state, NULL, NULL);
5596 }
5597 
5598 /*
5599  * tr_after_object() - The function executes all AFTER conditions and actions,
5600  * and does preparation work for all DEFERRED conditions and actions of the triggers fired.
5601  * return: error code
5602  * state(in): trigger execution state
5603  * current(in): current event object
5604  * temp(in): temporary event object
5605  *
5606  */
5607 int
5608 tr_after_object (TR_STATE * state, DB_OBJECT * current, DB_OBJECT * temp)
5609 {
5610  int error = NO_ERROR;
5611 
5612  if (!TR_EXECUTION_ENABLED)
5613  {
5614  return NO_ERROR;
5615  }
5616 
5617  if (state)
5618  {
5619  error = tr_execute_activities (state, TR_TIME_AFTER, current, temp);
5620 
5621  if (error != NO_ERROR)
5622  {
5623  tr_abort (state);
5624  }
5625  else
5626  {
5627  /*
5628  * at this point, the only things remaining on the state trigger list are deferred conditions and actions.
5629  * Add them to the end of the global list.
5630  */
5631  if (state->triggers != NULL)
5632  {
5633  add_deferred_activities (state->triggers, current);
5634  state->triggers = NULL;
5635  }
5636  tr_finish (state);
5637  }
5638  }
5639 
5640  return error;
5641 }
5642 
5643 /*
5644  * tr_after() - The function executes all AFTER conditions and actions, and
5645  * does preparation work for all DEFERRED conditions and actions of the triggers fired.
5646  * return: error code
5647  * state(in): trigger execution state
5648  *
5649  */
5650 int
5652 {
5653  return tr_after_object (state, NULL, NULL);
5654 }
5655 
5656 /*
5657  * tr_has_user_trigger() - Check whether has a trigger to execute at commit|rollback
5658  * return: error code
5659  * has_user_trigger(out): true, if has user trigger to execute, otherwise false
5660  */
5661 int
5662 tr_has_user_trigger (bool * has_user_trigger)
5663 {
5664  TR_TRIGLIST *t;
5665  int error = NO_ERROR;
5666  bool has_user_trigger_local;
5667 
5668  assert (has_user_trigger != NULL);
5669  if (!TR_EXECUTION_ENABLED)
5670  {
5671  *has_user_trigger = false;
5672  return NO_ERROR;
5673  }
5674 
5675  if (tr_Deferred_activities)
5676  {
5677  *has_user_trigger = true;
5678  return NO_ERROR;
5679  }
5680 
5682  {
5683  if (tr_update_user_cache () != NO_ERROR)
5684  {
5685  ASSERT_ERROR_AND_SET (error);
5686  return error;
5687  }
5688  }
5689 
5690  has_user_trigger_local = false;
5691  for (t = tr_User_triggers; t != NULL; t = t->next)
5692  {
5693  if (t->trigger->status == TR_STATUS_ACTIVE)
5694  {
5695  has_user_trigger_local = true;
5696  break;
5697  }
5698  }
5699 
5700  *has_user_trigger = has_user_trigger_local;
5701  return NO_ERROR;
5702 }
5703 
5704 /*
5705  * tr_check_commit_triggers() - This is called by tran_commit() early in the commit sequence.
5706  * return: error code
5707  * time(in):
5708  *
5709  * Note:
5710  * This is called by tran_commit() early in the commit sequence.
5711  * It will execute any deferred trigger activities.
5712  * It may return an error which means that the transaction is not committable.
5713  */
5714 int
5716 {
5717  int error = NO_ERROR;
5718 
5719  /*
5720  * If trigger firing has been disabled, do nothing.
5721  * This is currently used by the loader to disable triggers firing.
5722  */
5723  if (!TR_EXECUTION_ENABLED)
5724  {
5725  return NO_ERROR;
5726  }
5727 
5728  /*
5729  * Do we run the deferred activities before the commit triggers ?
5730  * If not, the commit trigger can schedule deferred activities as well.
5731  */
5732 
5733  if (run_user_triggers (TR_EVENT_COMMIT, time))
5734  {
5735  ASSERT_ERROR_AND_SET (error);
5736  return error;
5737  }
5738 
5739  /*
5740  * if this returns an error, we may wish to override it with a more generic trigger error.
5741  */
5742  if (time == TR_TIME_BEFORE)
5743  {
5745  {
5746  ASSERT_ERROR_AND_SET (error);
5747  return error;
5748  }
5749 
5751  {
5754  }
5755  else if (tr_Uncommitted_triggers != NULL)
5756  {
5757  /* the things on this list are going to make it */
5758  tr_free_trigger_list (tr_Uncommitted_triggers);
5759  tr_Uncommitted_triggers = NULL;
5760  }
5761  }
5762 
5763  /*
5764  * clear this flag so we know when triggers are updated during a transaction
5765  */
5767 
5768  return error;
5769 }
5770 
5771 /*
5772  * tr_check_rollback_triggers() - This is called by tran_abort early in the abort sequence.
5773  * return: none
5774  * time(in):
5775  *
5776  * Note:
5777  * It will toss out any deferred activities and raise any triggers on the abort event.
5778  * The abort operation itself cannot be rejected.
5779  * We also perform some housekeeping here for the user trigger cache.
5780  */
5781 void
5783 {
5784  TR_TRIGLIST *t, *next;
5785 
5786  /*
5787  * If trigger firing has been disabled, do nothing.
5788  * This is currently used by the loader to disable triggers firing.
5789  */
5790  if (!TR_EXECUTION_ENABLED)
5791  {
5792  return;
5793  }
5794 
5795  /*
5796  * Run user triggers FIRST, even if they were created during this transaction.
5797  */
5798  (void) run_user_triggers (TR_EVENT_ROLLBACK, time);
5799 
5800  /*
5801  * can the rollback triggers have deferred activities ? if so need to execute the deferred list now
5802  */
5803 
5804  /*
5805  * make sure that any triggers created during this session are removed,
5806  * especially those on the rollback event itself
5807  */
5808  if (tr_Uncommitted_triggers != NULL)
5809  {
5810  for (t = tr_Uncommitted_triggers, next = NULL; t != NULL; t = next)
5811  {
5812  next = t->next;
5813  /* this will also remove it from the tr_Uncommitted_triggers list */
5814  tr_drop_trigger_internal (t->trigger, 1, false);
5815  }
5816  /*
5817  * shouldn't be necessary if tr_drop_trigger_intenral is doing its job
5818  */
5819  tr_free_trigger_list (tr_Uncommitted_triggers);
5820  tr_Uncommitted_triggers = NULL;
5821  }
5822 
5823  /* ignore any deferred activities */
5825 
5826  /* this always gets cleared when the transaction aborts */
5827  tr_Invalid_transaction = false;
5828 
5830  {
5833  }
5834 }
5835 
5836 #if defined(ENABLE_UNUSED_FUNCTION)
5837 /*
5838  * tr_check_timeout_triggers() - This is called whenever a lock timeout ocurrs.
5839  * return: none
5840  *
5841  * Note:
5842  * The timeout can't be prevented but the user may wish to insert triggers for side effects.
5843  */
5844 void
5845 tr_check_timeout_triggers (void)
5846 {
5847  if (!TR_EXECUTION_ENABLED)
5848  {
5849  return;
5850  }
5852 }
5853 #endif /* ENABLE_UNUSED_FUNCTION */
5854 
5855 /*
5856  * tr_check_abort_triggers() - This is called whenever the client is unilaterally aborted for some reason.
5857  * return: none
5858  *
5859  * Note:
5860  * This is called whenever the client is unilaterally aborted for some reason.
5861  * This is different than tr_check_rollback_triggers() because that function is only called
5862  * if the user voluntarily calls tran_abort().
5863  */
5864 void
5866 {
5867  /*
5868  * If trigger firing has been disabled, do nothing.
5869  * This is currently used by the loader to disable triggers firing.
5870  */
5871  if (!TR_EXECUTION_ENABLED)
5872  {
5873  return;
5874  }
5875 
5877 
5878  /*
5879  * can the abort triggers have deferred activities ? if so
5880  * need to execute the deferred list now
5881  */
5882 
5883  /* ignore any deferred activities */
5885 
5886  /* this always gets cleared when the transaction aborts */
5887  tr_Invalid_transaction = false;
5888 }
5889 
5890 /* DEFERRED ACTIVITY CONTROL */
5891 
5892 /*
5893  * its_deleted() - This is called to look at objects associated with deferred triggers to make sure they still exist.
5894  * return: non-zero if the object is deleted
5895  * object(in): object to examine
5896  *
5897  * Note:
5898  * Try to determine this as quickly as posible. This should be a general ws_ function or something.
5899  */
5900 static int
5902 {
5903  int deleted = 0;
5904 
5905  /*
5906  * Ok, in order for the object to be on the deferred trigger list,
5907  * it must have existed at the time the trigger was raised. If it was deleted, the MOP will have the deleted bit set.
5908  * The only time we can be referencing a deleted MOP that doesn't have the deleted bit set is if the MOP has never
5909  * been locked by this transaction.
5910  * Since we must have locked this object in order to fire a trigger on it, that case isn't possible.
5911  */
5912 
5913  if (object != NULL)
5914  {
5915  /* fast way */
5916  if (object->decached == 0)
5917  {
5918  deleted = WS_IS_DELETED (object);
5919  }
5920  else
5921  {
5922  int error;
5923 
5925  if (error == ER_HEAP_UNKNOWN_OBJECT)
5926  {
5927  deleted = 1;
5928  }
5929  }
5930 
5931  /* Slow but safe way */
5932 #if 0
5933  error = au_fetch_instance_force (object, &mem, AU_FETCH_READ);
5935  deleted = 1;
5936 #endif /* 0 */
5937  }
5938 
5939  return deleted;
5940 }
5941 
5942 /*
5943  * tr_execute_deferred_activities() - This function executes any deferred activities for a trigger.
5944  * return: error code
5945  * trigger_object(in): trigger object
5946  * target(in): associated target instance
5947  *
5948  * Note:
5949  * This function executes any deferred activities for a trigger.
5950  * If the object argument is NULL, all of the deferred activities for the given trigger are executed.
5951  * If supplied, only those activities that are associated with the given target object are executed.
5952  * If the target argument is NULL, all deferred activities for the given trigger are executed.
5953  * If both arguments are NULL, all deferred activities are executed unconditionally.
5954  *
5955  */
5956 int
5958 {
5959  int error = NO_ERROR;
5960  TR_DEFERRED_CONTEXT *c, *c_next;
5961  TR_TRIGLIST *t, *next;
5962  TR_TRIGGER *trigger;
5963  TR_STATE *state_p;
5964  int status;
5965  bool rejected;
5966 
5967  /*
5968  * If trigger firing has been disabled, do nothing.
5969  * This is currently used by the loader to disable trigger firing.
5970  */
5971  if (!TR_EXECUTION_ENABLED)
5972  {
5973  return NO_ERROR;
5974  }
5975 
5976  for (c = tr_Deferred_activities, c_next = NULL; c != NULL && !error; c = c_next)
5977  {
5978  c_next = c->next;
5979 
5980  for (t = c->head, next = NULL; t != NULL && !error; t = next)
5981  {
5982  next = t->next;
5983  trigger = t->trigger;
5984 
5985  if ((trigger_object == NULL || trigger->object == trigger_object) && (target == NULL || t->target == target))
5986  {
5987  if (its_deleted (t->target))
5988  {
5989  /*
5990  * Somewhere along the line, the target object was deleted, quietly ignore the deferred activity.
5991  * If it turns out that we really want to keep these active, we'll have to contend with
5992  * what pt_exec_trigger_stmt is going to do when we pass it deleted objects.
5993  */
5994  remove_deferred_activity (c, t);
5995  }
5996  else
5997  {
5998  state_p = NULL;
5999  if (start_state (&state_p, t->trigger->name) == NULL)
6000  {
6001  ASSERT_ERROR_AND_SET (error);
6002  break;
6003  }
6004 
6005  status = execute_activity (trigger, TR_TIME_DEFERRED, t->target, NULL, &rejected);
6006 
6007  tr_finish (state_p);
6008 
6009  /* execute_activity() maybe include trigger and change the next pointer. we need get it again. */
6010  next = t->next;
6011  if (status == TR_RETURN_TRUE)
6012  {
6013  /* successful processing, remove it from the list */
6014  remove_deferred_activity (c, t);
6015 
6016  /* reject can't happen here, even if it does, it is unclear what it would mean */
6017  }
6018  else if (status == TR_RETURN_ERROR)
6019  {
6020  /*
6021  * if an error happens, should we invalidate the transaction ?
6022  */
6023  ASSERT_ERROR_AND_SET (error);
6024  }
6025 
6026  /* else, thinks the trigger can't be evaluated yet, shouldn't happen */
6027  }
6028  }
6029  }
6030 
6031  /*
6032  * if we deleted all of the deferred triggers in this context, remove the context as well
6033  */
6034  if (c->head == NULL)
6035  {
6037  }
6038  }
6039 
6040  return error;
6041 }
6042 
6043 /*
6044  * tr_drop_deferred_activities() - This functio removes any deferred activities for a trigger.
6045  * return: error code
6046  * trigger_object(in): trigger object
6047  * target(in): target object
6048  *
6049  * Note:
6050  * This function removes any deferred activities for a trigger.
6051  * If the target argument is NULL, all of the deferred activities for the given trigger are removed.
6052  * If supplied, only those activities associated with the target object are removed.
6053  */
6054 int
6056 {
6057  int error = NO_ERROR;
6058  TR_DEFERRED_CONTEXT *c, *c_next;
6059  TR_TRIGLIST *t, *next;
6060 
6061  /* could signal some errors here if the trigger isn't deferrable etc. */
6062 
6063  for (c = tr_Deferred_activities, c_next = NULL; c != NULL && !error; c = c_next)
6064  {
6065  c_next = c->next;
6066 
6067  for (t = c->head, next = NULL; t != NULL && !error; t = next)
6068  {
6069  next = t->next;
6070 
6071  if ((trigger_object == NULL || t->trigger->object == trigger_object)
6072  && (target == NULL || t->target == target))
6073  {
6075  {
6076  remove_deferred_activity (c, t);
6077  }
6078  else
6079  {
6080  error = ER_TR_ACTIVITY_NOT_OWNED;
6081  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
6082  }
6083  }
6084  }
6085 
6086  if (c->head == NULL)
6087  {
6089  }
6090  }
6091 
6092  return error;
6093 }
6094 
6095 /* TRIGGER OBJECT ACCESSORS */
6096 
6097 /*
6098  * tr_trigger_name() - This function finds the name of the input trigger.
6099  * return: const char
6100  * trigger_object(in): trigger object
6101  * name(out):
6102  *
6103  * Note:
6104  * If access to the internal object that contains the trigger definition can not be obtained,
6105  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6106  * for the class in the trigger's event target, an error code will be returned.
6107  */
6108 int
6109 tr_trigger_name (DB_OBJECT * trigger_object, char **name)
6110 {
6111  int error = NO_ERROR;
6112  TR_TRIGGER *trigger;
6113  int save;
6114 
6115  *name = NULL;
6116  AU_DISABLE (save);
6117 
6118  trigger = tr_map_trigger (trigger_object, 1);
6119  if (trigger == NULL)
6120  {
6121  ASSERT_ERROR_AND_SET (error);
6122  }
6123  else
6124  {
6125  *name = ws_copy_string (trigger->name);
6126  }
6127 
6128  AU_ENABLE (save);
6129  return error;
6130 }
6131 
6132 /*
6133  * tr_trigger_status() - This function finds the status of the input trigger.
6134  * return: error
6135  * trigger_object(in): trigger object
6136  * status(in): pointer to the return status of the trigger
6137  *
6138  * Note:
6139  * If access to the internal object that contains the trigger definition can not be obtained,
6140  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6141  * for the class in the trigger's event target, an error code will be returned.
6142  */
6143 int
6144 tr_trigger_status (DB_OBJECT * trigger_object, DB_TRIGGER_STATUS * status)
6145 {
6146  int error = NO_ERROR;
6147  TR_TRIGGER *trigger;
6148  int save;
6149 
6150  *status = TR_STATUS_INACTIVE;
6151  AU_DISABLE (save);
6152 
6153  trigger = tr_map_trigger (trigger_object, 1);
6154  if (trigger == NULL)
6155  {
6156  ASSERT_ERROR_AND_SET (error);
6157  }
6158  else
6159  {
6160  *status = trigger->status;
6161  }
6162 
6163  AU_ENABLE (save);
6164  return error;
6165 }
6166 
6167 /*
6168  * tr_trigger_priority() - This function finds the priority of the input trigger.
6169  * return: error code
6170  * trigger_object(in): trigger object
6171  * priority(out): pointer to the return trigger priority
6172  *
6173  * Note:
6174  * If access to the internal object that contains the trigger definition can not be obtained,
6175  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6176  * for the class in the trigger's event target, an error code will be returned.
6177  */
6178 int
6179 tr_trigger_priority (DB_OBJECT * trigger_object, double *priority)
6180 {
6181  int error = NO_ERROR;
6182  TR_TRIGGER *trigger;
6183  int save;
6184 
6185  *priority = TR_LOWEST_PRIORITY;
6186  AU_DISABLE (save);
6187 
6188  trigger = tr_map_trigger (trigger_object, 1);
6189  if (trigger == NULL)
6190  {
6191  ASSERT_ERROR_AND_SET (error);
6192  }
6193  else
6194  {
6195  *priority = trigger->priority;
6196  }
6197 
6198  AU_ENABLE (save);
6199  return error;
6200 }
6201 
6202 /*
6203  * tr_trigger_event() - This function finds the event type of the input trigger.
6204  * return: error code
6205  * trigger_object(in): trigger object
6206  * event(in): pointer to the return event type of the trigger
6207  *
6208  * Note:
6209  * If access to the internal object that contains the trigger definition can not be obtained,
6210  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6211  * for the class in the trigger's event target, an error code will be returned.
6212  */
6213 int
6214 tr_trigger_event (DB_OBJECT * trigger_object, DB_TRIGGER_EVENT * event)
6215 {
6216  int error = NO_ERROR;
6217  TR_TRIGGER *trigger;
6218  int save;
6219 
6220  *event = TR_EVENT_NULL;
6221  AU_DISABLE (save);
6222 
6223  trigger = tr_map_trigger (trigger_object, 1);
6224  if (trigger == NULL)
6225  {
6226  ASSERT_ERROR_AND_SET (error);
6227  }
6228  else
6229  {
6230  *event = trigger->event;
6231  }
6232 
6233  AU_ENABLE (save);
6234  return error;
6235 }
6236 
6237 /*
6238  * tr_trigger_class() - This function finds the target class of the input trigger
6239  * return: error code
6240  * trigger_object(in): trigger object
6241  * class(in): pointer to the return class of the input trigger
6242  *
6243  * Note:
6244  * A trigger may not have a target class. In this case, the argument class returns NULL.
6245  * If access to the internal object that contains the trigger definition can not be obtained,
6246  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6247  * for the class in the trigger's event target, an error code will be returned.
6248  */
6249 int
6250 tr_trigger_class (DB_OBJECT * trigger_object, DB_OBJECT ** class_mop_p)
6251 {
6252  int error = NO_ERROR;
6253  TR_TRIGGER *trigger;
6254  int save;
6255 
6256  *class_mop_p = NULL;
6257  AU_DISABLE (save);
6258 
6259  trigger = tr_map_trigger (trigger_object, 1);
6260  if (trigger == NULL)
6261  {
6262  ASSERT_ERROR_AND_SET (error);
6263  }
6264  else
6265  {
6266  *class_mop_p = trigger->class_mop;
6267  }
6268 
6269  AU_ENABLE (save);
6270  return error;
6271 }
6272 
6273 /*
6274  * tr_trigger_attribute() - This function finds the target attribute of the input trigger.
6275  * return: error code
6276  * trigger_object(in): trigger object
6277  * attribute(in): pointer to the return target attribute of the trigger
6278  *
6279  * Note:
6280  * A trigger may not have a target attribute. In this case, the argument attribute returns NULL.
6281  * If access to the internal object that contains the trigger definition can not be obtained,
6282  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6283  * for the class in the trigger's event target, an error code will be returned.
6284  */
6285 int
6286 tr_trigger_attribute (DB_OBJECT * trigger_object, char **attribute)
6287 {
6288  int error = NO_ERROR;
6289  TR_TRIGGER *trigger;
6290  int save;
6291 
6292  *attribute = NULL;
6293  AU_DISABLE (save);
6294 
6295  trigger = tr_map_trigger (trigger_object, 1);
6296  if (trigger == NULL)
6297  {
6298  ASSERT_ERROR_AND_SET (error);
6299  }
6300  else
6301  {
6302  *attribute = ws_copy_string (trigger->attribute);
6303  }
6304 
6305  AU_ENABLE (save);
6306  return error;
6307 }
6308 
6309 /*
6310  * tr_trigger_condition() - This function finds the condition of the input trigger.
6311  * return: error code
6312  * trigger_object(in): trigger object
6313  * condition(out): pointer to the return trigger condition
6314  *
6315  * Note:
6316  * A trigger may not have a condition. In this case, the argument condition returns NULL.
6317  * If access to the internal object that contains the trigger definition can not be obtained,
6318  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6319  * for the class in the trigger's event target, an error code will be returned.
6320  */
6321 int
6322 tr_trigger_condition (DB_OBJECT * trigger_object, char **condition)
6323 {
6324  int error = NO_ERROR;
6325  TR_TRIGGER *trigger;
6326  int save;
6327 
6328  *condition = NULL;
6329  AU_DISABLE (save);
6330 
6331  trigger = tr_map_trigger (trigger_object, 1);
6332  if (trigger == NULL)
6333  {
6334  ASSERT_ERROR_AND_SET (error);
6335  }
6336  else if (trigger->condition != NULL && trigger->condition->type == TR_ACT_EXPRESSION)
6337  {
6338  *condition = ws_copy_string (trigger->condition->source);
6339  }
6340 
6341  AU_ENABLE (save);
6342  return error;
6343 }
6344 
6345 /*
6346  * tr_trigger_condition_time() - This function finds the execution time of the trigger condition
6347  * return: error code
6348  * trigger_object(in): trigger object
6349  * tr_time(in): pointer to the return execution time of the trigger condition
6350  *
6351  * Note:
6352  * Even if the given trigger does not have a condition, the argument time still returns a default execution time.
6353  * If access to the internal object that contains the trigger definition can not be obtained, the trigger cannot be
6354  * identified or seen by the user, or the user does not have the SELECT privilege for the class in the trigger's
6355  * event target, an error code will be returned.
6356  */
6357 int
6359 {
6360  int error = NO_ERROR;
6361  TR_TRIGGER *trigger;
6362  int save;
6363 
6364  *tr_time = TR_TIME_NULL;
6365  AU_DISABLE (save);
6366 
6367  trigger = tr_map_trigger (trigger_object, 1);
6368  if (trigger == NULL)
6369  {
6370  ASSERT_ERROR_AND_SET (error);
6371  }
6372  else if (trigger->condition != NULL)
6373  {
6374  *tr_time = trigger->condition->time;
6375  }
6376 
6377  AU_ENABLE (save);
6378  return error;
6379 }
6380 
6381 /*
6382  * tr_trigger_action() - This function finds the action of the input trigger.
6383  * return: error code
6384  * trigger_object(in): trigger object
6385  * action(out): pointer to the return trigger action
6386  *
6387  * Note:
6388  * If access to the internal object that contains the trigger definition can not be obtained,
6389  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6390  * for the class in the trigger's event target, an error code will be returned.
6391  */
6392 int
6393 tr_trigger_action (DB_OBJECT * trigger_object, char **action)
6394 {
6395  int error = NO_ERROR;
6396  TR_TRIGGER *trigger;
6397  int save;
6398  char buf[TR_MAX_PRINT_STRING + 32];
6399 
6400  *action = NULL;
6401  AU_DISABLE (save);
6402 
6403  trigger = tr_map_trigger (trigger_object, 1);
6404  if (trigger == NULL)
6405  {
6406  ASSERT_ERROR_AND_SET (error);
6407  }
6408  else if (trigger->action != NULL)
6409  {
6410  switch (trigger->action->type)
6411  {
6412  case TR_ACT_NULL:
6413  /* no condition */
6414  break;
6415 
6416  case TR_ACT_EXPRESSION:
6417  *action = ws_copy_string (trigger->action->source);
6418  break;
6419 
6420  case TR_ACT_REJECT:
6421  *action = ws_copy_string ("REJECT");
6422  break;
6423 
6424  case TR_ACT_INVALIDATE:
6425  *action = ws_copy_string ("INVALIDATE TRANSACTION");
6426  break;
6427 
6428  case TR_ACT_PRINT:
6429  /* sigh, need a nice adjustable string array package */
6430  snprintf (buf, sizeof (buf) - 1, "PRINT '%s'", trigger->action->source);
6431  *action = ws_copy_string (buf);
6432  break;
6433 
6434  default:
6435  /* error ? */
6436  break;
6437  }
6438  }
6439 
6440  AU_ENABLE (save);
6441  return error;
6442 }
6443 
6444 /*
6445  * tr_trigger_action_time() - This function finds the execution time of the trigger action.
6446  * return: error code
6447  * trigger_object(in): trigger object
6448  * tr_time(in): pointer to the return execution time of the trigger action
6449  *
6450  * Note:
6451  * If access to the internal object that contains the trigger definition can not be obtained,
6452  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6453  * for the class in the trigger's event target, an error code will be returned.
6454  */
6455 int
6456 tr_trigger_action_time (DB_OBJECT * trigger_object, DB_TRIGGER_TIME * tr_time)
6457 {
6458  int error = NO_ERROR;
6459  TR_TRIGGER *trigger;
6460  int save;
6461 
6462  *tr_time = TR_TIME_NULL;
6463  AU_DISABLE (save);
6464 
6465  trigger = tr_map_trigger (trigger_object, 1);
6466  if (trigger == NULL)
6467  {
6468  ASSERT_ERROR_AND_SET (error);
6469  }
6470  else if (trigger->action != NULL)
6471  {
6472  *tr_time = trigger->action->time;
6473  }
6474 
6475  AU_ENABLE (save);
6476  return error;
6477 }
6478 
6479 /*
6480  * tr_trigger_action_type() - This returns the action type.
6481  * return: error code
6482  * trigger_object(in): trigger object
6483  * type(out): trigger action type
6484  *
6485  * Note:
6486  * An application would generally call this first to see if the type is TR_ACT_EXPRESSION and then use
6487  * tr_trigger_action to get the expression string.
6488  */
6489 int
6491 {
6492  int error = NO_ERROR;
6493  TR_TRIGGER *trigger;
6494  int save;
6495 
6496  *type = TR_ACT_NULL;
6497  AU_DISABLE (save);
6498 
6499  trigger = tr_map_trigger (trigger_object, 1);
6500  if (trigger == NULL)
6501  {
6502  ASSERT_ERROR_AND_SET (error);
6503  }
6504  else if (trigger->action != NULL)
6505  {
6506  *type = trigger->action->type;
6507  }
6508 
6509  AU_ENABLE (save);
6510  return error;
6511 }
6512 
6513 /*
6514  * tr_trigger_comment() - This function finds the comment of the input trigger.
6515  * return: const char
6516  * trigger_object(in): trigger object
6517  * comment(out):
6518  *
6519  * Note:
6520  * If access to the internal object that contains the trigger definition can not be obtained,
6521  * the trigger cannot be identified or seen by the user, or the user does not have the SELECT privilege
6522  * for the class in the trigger's event target, an error code will be returned.
6523  */
6524 int
6525 tr_trigger_comment (DB_OBJECT * trigger_object, char **comment)
6526 {
6527  int error = NO_ERROR;
6528  TR_TRIGGER *trigger;
6529  int save;
6530 
6531  *comment = NULL;
6532  AU_DISABLE (save);
6533 
6534  trigger = tr_map_trigger (trigger_object, 1);
6535  if (trigger == NULL)
6536  {
6537  ASSERT_ERROR_AND_SET (error);
6538  }
6539  else
6540  {
6541  *comment = ws_copy_string (trigger->comment);
6542  }
6543 
6544  AU_ENABLE (save);
6545  return error;
6546 }
6547 
6548 /*
6549  * tr_is_trigger() - This function can be used to test if an object is a trigger object.
6550  * return: error code
6551  * trigger_object(in): trigger object
6552  * status(in): return status (non-zero if its a trigger object)
6553  */
6554 int
6555 tr_is_trigger (DB_OBJECT * trigger_object, int *status)
6556 {
6557  int error = NO_ERROR;
6558  DB_OBJECT *tclass, *oclass;
6559 
6560  *status = false;
6561 
6562  tclass = sm_find_class (TR_CLASS_NAME); /* need to cache this ! */
6563  oclass = sm_get_class (trigger_object);
6564 
6565  if (tclass == oclass)
6566  {
6567  *status = true;
6568  }
6569 
6570  /* need to properly detect errors on the object accesses */
6571  return error;
6572 }
6573 
6574 
6575 /* TRIGGER MIGRATION SUPPORT */
6576 
6577 /*
6578  * tr_time_as_string() - Returns the ASCII text for the given time constant.
6579  * return: const char
6580  * time(in): trigger time constant
6581  */
6582 const char *
6584 {
6585  const char *string;
6586  switch (time)
6587  {
6588  case TR_TIME_BEFORE:
6589  string = "BEFORE";
6590  break;
6591  case TR_TIME_AFTER:
6592  string = "AFTER";
6593  break;
6594  case TR_TIME_DEFERRED:
6595  string = "DEFERRED";
6596  break;
6597  default:
6598  string = "???";
6599  break;
6600  }
6601 
6602  return string;
6603 }
6604 
6605 /*
6606  * tr_event_as_string() - Returns the ASCII representation of an event constant
6607  * return: const char
6608  * event(in): event constant
6609  */
6610 const char *
6612 {
6613  const char *string;
6614 
6615  switch (event)
6616  {
6617  case TR_EVENT_UPDATE:
6618  string = "UPDATE";
6619  break;
6621  string = "STATEMENT UPDATE";
6622  break;
6623  case TR_EVENT_DELETE:
6624  string = "DELETE";
6625  break;
6627  string = "STATEMENT DELETE";
6628  break;
6629  case TR_EVENT_INSERT:
6630  string = "INSERT";
6631  break;
6633  string = "STATEMENT INSERT";
6634  break;
6635  case TR_EVENT_ALTER:
6636  string = "ALTER";
6637  break;
6638  case TR_EVENT_DROP:
6639  string = "DROP";
6640  break;
6641  case TR_EVENT_COMMIT:
6642  string = "COMMIT";
6643  break;
6644  case TR_EVENT_ROLLBACK:
6645  string = "ROLLBACK";
6646  break;
6647  case TR_EVENT_ABORT:
6648  string = "ABORT";
6649  break;
6650  case TR_EVENT_TIMEOUT:
6651  string = "TIMEOUT";
6652  break;
6653  case TR_EVENT_NULL:
6654  case TR_EVENT_ALL:
6655  default:
6656  string = "???";
6657  break;
6658  }
6659  return string;
6660 }
6661 
6662 /*
6663  * tr_status_as_string() - Returns the ASCII representation of a trigger status constant.
6664  * return: const char *
6665  * status(in): status code
6666  */
6667 const char *
6669 {
6670  const char *string;
6671 
6672  switch (status)
6673  {
6674  case TR_STATUS_INVALID:
6675  string = "INVALID";
6676  break;
6677  case TR_STATUS_ACTIVE:
6678  string = "ACTIVE";
6679  break;
6680  case TR_STATUS_INACTIVE:
6681  string = "INACTIVE";
6682  break;
6683  default:
6684  string = "???";
6685  break;
6686  }
6687 
6688  return string;
6689 }
6690 
6691 #if defined(ENABLE_UNUSED_FUNCTION)
6692 /*
6693  * tr_dump_all_triggers() - This is intended to support the unloaddb/loaddb utilities.
6694  * return: error code
6695  * fp(in): output file
6696  * quoted_id_flag(in):
6697  *
6698  * Note:
6699  * This is intended to support the unloaddb/loaddb utilities.
6700  * It dumps a csql script that can be used to regenerate all of the currently defined triggers.
6701  * It uses the login() method without passwords and as such assumes that we are running as the 'DBA' user.
6702  * NOTE: Do not dump triggers if they are defined on one of the system classes.
6703  * These are defined as part of "createdb" and must not be emitted in the unloaddb schema file.
6704  * This does however prevent users from defining their own triggers on the system classes but this isn't
6705  * much of a limitation since users can't alter the system classes in any other way.
6706  */
6707 int
6708 tr_dump_all_triggers (FILE * fp, bool quoted_id_flag)
6709 {
6710  int error = NO_ERROR;
6711  TR_TRIGGER *trigger;
6712  DB_SET *table;
6713  DB_VALUE value;
6714  DB_OBJECT *trigger_object;
6715  int max, i;
6716 
6717  if (Au_root != NULL && (error = obj_get (Au_root, "triggers", &value)) == NO_ERROR)
6718  {
6719  if (DB_IS_NULL (&value))
6720  {
6721  table = NULL;
6722  }
6723  else
6724  {
6725  table = db_get_set (&value);
6726  }
6727  if (table != NULL)
6728  {
6729  error = set_filter (table);
6730  max = set_size (table);
6731  for (i = 1; i < max && error == NO_ERROR; i += 2)
6732  {
6733  if ((error = set_get_element (table, i, &value)) == NO_ERROR)
6734  {
6735  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && !DB_IS_NULL (&value)
6736  && db_get_object (&value) != NULL)
6737  {
6738  trigger_object = db_get_object (&value);
6739  trigger = tr_map_trigger (trigger_object, 1);
6740  if (trigger == NULL)
6741  {
6742  assert (er_errid () != NO_ERROR);
6743  error = er_errid ();
6744  }
6745  else
6746  {
6747  /* don't dump system class triggers */
6748  if (trigger->class_mop == NULL || !sm_is_system_class (trigger->class_mop))
6749  {
6750 
6751  if (trigger->status != TR_STATUS_INVALID)
6752  {
6753  tr_dump_trigger (trigger_object, fp, quoted_id_flag);
6754  fprintf (fp, "call [change_trigger_owner]('%s'," " '%s') on class [db_root];\n\n",
6755  trigger->name, get_user_name (trigger->owner));
6756  }
6757  }
6758  }
6759  }
6760  }
6761  }
6762  set_free (table);
6763  }
6764  }
6765 
6766  return error;
6767 }
6768 #endif /* ENABLE_UNUSED_FUNCTION */
6769 
6770 /* TRIGGER ALTER OPERATIONS */
6771 
6772 /*
6773  * tr_rename_trigger() - Renames a trigger. The new name cannot already be in use.
6774  * return: error code
6775  * trigger_object(in): trigger object
6776  * name(in): new trigger name
6777  * call_from_api(in): call from api
6778  */
6779 int
6780 tr_rename_trigger (DB_OBJECT * trigger_object, const char *name, bool call_from_api)
6781 {
6782  int error = NO_ERROR;
6783  TR_TRIGGER *trigger;
6784  DB_VALUE value;
6785  char *newname, *oldname;
6786  char *tr_name = NULL;
6787  int save;
6788  bool has_savepoint = false;
6789 
6790  /* Do we need to disable authorization just for check_authorization ? */
6791  AU_DISABLE (save);
6792 
6793  trigger = tr_map_trigger (trigger_object, true);
6794  if (trigger == NULL)
6795  {
6796  ASSERT_ERROR_AND_SET (error);
6797  }
6798  else
6799  {
6800  tr_name = strdup (trigger->name);
6801  }
6802 
6803  if (trigger == NULL)
6804  {
6805  ;
6806  }
6807  else if (!check_authorization (trigger, true))
6808  {
6810  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
6811  }
6812  else
6813  {
6814  newname = tr_process_name (name);
6815  if (newname == NULL)
6816  {
6817  ASSERT_ERROR_AND_SET (error);
6818  }
6819  else
6820  {
6821  if (TM_TRAN_ISOLATION () >= TRAN_REP_READ)
6822  {
6823  /* protect against multiple flushes to server */
6825  if (error == NO_ERROR)
6826  {
6827  has_savepoint = true;
6828  }
6829  }
6830 
6831  if (error == NO_ERROR)
6832  {
6833  error = trigger_table_rename (trigger_object, newname);
6834  }
6835 
6836  /* might need to abort the transaction here */
6837  if (error == NO_ERROR)
6838  {
6839  oldname = trigger->name;
6840  trigger->name = newname;
6841  db_make_string (&value, newname);
6842  newname = NULL;
6843  error = db_put_internal (trigger_object, TR_ATT_NAME, &value);
6844  if (error == NO_ERROR)
6845  {
6846  error = locator_flush_instance (trigger_object);
6847  }
6848 
6849  if (error != NO_ERROR)
6850  {
6851  /*
6852  * hmm, couldn't set the new name, put the old one back,
6853  * we might need to abort the transaction here ?
6854  */
6855  ASSERT_ERROR ();
6856  newname = trigger->name;
6857  trigger->name = oldname;
6858  /* if we can't do this, the transaction better abort */
6859  (void) trigger_table_rename (trigger_object, oldname);
6860  oldname = NULL;
6861  }
6862  if (oldname != NULL)
6863  {
6864  free_and_init (oldname);
6865  }
6866  }
6867 
6868  if (newname != NULL)
6869  {
6870  free_and_init (newname);
6871  }
6872  }
6873  }
6874 
6875  AU_ENABLE (save);
6876 
6877  if (has_savepoint && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
6878  {
6880  }
6881 
6882  if (tr_name)
6883  {
6884  free_and_init (tr_name);
6885  }
6886 
6887  return error;
6888 }
6889 
6890 /*
6891  * tr_set_status() - This changes a trigger status.
6892  * return: error code
6893  * trigger_object(in): trigger object
6894  * status(in): new statue
6895  * call_from_api(in): call from api
6896  *
6897  * Note:
6898  * The possible values are TR_STATUS_ACTIVE and TR_STATUS_INACTIVE.
6899  * We reset the associated cache validation flag when the status changes.
6900  */
6901 int
6902 tr_set_status (DB_OBJECT * trigger_object, DB_TRIGGER_STATUS status, bool call_from_api)
6903 {
6904  int error = NO_ERROR;
6905  TR_TRIGGER *trigger;
6906  DB_TRIGGER_STATUS oldstatus;
6907  DB_VALUE value;
6908  int save;
6909 
6910  AU_DISABLE (save);
6911 
6912  trigger = tr_map_trigger (trigger_object, 1);
6913  if (trigger == NULL)
6914  {
6915  ASSERT_ERROR_AND_SET (error);
6916  }
6917  else if (!check_authorization (trigger, true))
6918  {
6920  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
6921  }
6922  else
6923  {
6924  oldstatus = trigger->status;
6925  trigger->status = status;
6926  db_make_int (&value, status);
6927  if (db_put_internal (trigger_object, TR_ATT_STATUS, &value))
6928  {
6929  ASSERT_ERROR_AND_SET (error);
6930 
6931  /*
6932  * hmm, couldn't set the new status, put the old one back,
6933  * we might need to abort the transaction here ?
6934  */
6935  trigger->status = oldstatus;
6936  }
6937  else
6938  {
6939  /*
6940  * The schema manager maintains a flag indicating whether active triggers are defined for the class.
6941  * When the status of a trigger changes, we need to tell the schema manager to recalculate this flag.
6942  */
6943  if (trigger->class_mop != NULL)
6944  {
6945  error = sm_invalidate_trigger_cache (trigger->class_mop);
6946  }
6947 
6948  /*
6949  * If this is a user trigger, the status will be checked by run_user_triggers
6950  * so the user cache list doesn't have to be recalculated.
6951  */
6952  }
6953  }
6954 
6955  AU_ENABLE (save);
6956 
6957  return error;
6958 }
6959 
6960 /*
6961  * tr_set_priority() - This changes a trigger priority.
6962  * The associated trigger caches are rebuilt to reflect the change in priority.
6963  * return: error code
6964  * trigger_object(in): trigger object
6965  * priority(in): new priority
6966  * call_from_api(in): call from api
6967  */
6968 int
6969 tr_set_priority (DB_OBJECT * trigger_object, double priority, bool call_from_api)
6970 {
6971  int error = NO_ERROR;
6972  TR_TRIGGER *trigger;
6973  double oldpri;
6974  DB_VALUE value;
6975  int save;
6976 
6977  AU_DISABLE (save);
6978 
6979  trigger = tr_map_trigger (trigger_object, 1);
6980  if (trigger == NULL)
6981  {
6982  ASSERT_ERROR_AND_SET (error);
6983  }
6984  else if (!check_authorization (trigger, true))
6985  {
6987  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
6988  }
6989  else
6990  {
6991  oldpri = trigger->priority;
6992  trigger->priority = priority;
6993  db_make_double (&value, priority);
6994  if (db_put_internal (trigger_object, TR_ATT_PRIORITY, &value))
6995  {
6996  ASSERT_ERROR_AND_SET (error);
6997 
6998  /*
6999  * hmm, couldn't set the new status, put the old one back,
7000  * we might need to abort the transaction here ?
7001  */
7002  trigger->priority = oldpri;
7003  }
7004  else
7005  {
7006  if (trigger->class_mop != NULL)
7007  {
7008  /*
7009  * its a class trigger, find all the caches that point to this trigger and cause them to be re-ordered
7010  */
7011  reorder_schema_caches (trigger);
7012  }
7013  else
7014  {
7015  /* this was a user trigger, rebuild the cache */
7017  }
7018  }
7019  }
7020 
7021  AU_ENABLE (save);
7022 
7023  return error;
7024 }
7025 
7026 /*
7027  * tr_set_comment() - This changes a trigger comment.
7028  * return: error code
7029  * trigger_object(in): trigger object
7030  * comment(in): new comment
7031  * call_from_api(in): call from api
7032  *
7033  * Note:
7034  * The possible values are TR_STATUS_ACTIVE and TR_STATUS_INACTIVE.
7035  * We reset the associated cache validation flag when the status changes.
7036  */
7037 int
7038 tr_set_comment (DB_OBJECT * trigger_object, const char *comment, bool call_from_api)
7039 {
7040  int error = NO_ERROR;
7041  TR_TRIGGER *trigger;
7042  DB_VALUE value;
7043  int save;
7044  char *oldcomment = NULL;
7045 
7046  AU_DISABLE (save);
7047 
7048  /* fetch and check the trigger */
7049  trigger = tr_map_trigger (trigger_object, 1);
7050  if (trigger == NULL)
7051  {
7052  ASSERT_ERROR_AND_SET (error);
7053  }
7054  else if (!check_authorization (trigger, true))
7055  {
7057  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
7058  }
7059 
7060  if (error == NO_ERROR)
7061  {
7062  oldcomment = (char *) trigger->comment;
7063  assert (comment != NULL);
7064  trigger->comment = strdup (comment);
7065  if (trigger->comment == NULL)
7066  {
7067  trigger->comment = oldcomment;
7069  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, trigger->name);
7070  }
7071  else
7072  {
7073  db_make_string_copy (&value, comment);
7074  if (db_put_internal (trigger_object, TR_ATT_COMMENT, &value))
7075  {
7076  error = (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED;
7077  trigger->comment = oldcomment;
7078  }
7079  else
7080  {
7081  if (oldcomment != NULL)
7082  {
7083  free_and_init (oldcomment);
7084  }
7085  }
7086  pr_clear_value (&value);
7087  }
7088  }
7089 
7090  AU_ENABLE (save);
7091 
7092  return error;
7093 }
7094 
7095 /* TRIGGER PARAMETERS */
7096 
7097 /*
7098  * tr_get_depth() - This returns the maximum call depth allowed for nested triggers.
7099  * return: depth
7100  *
7101  * Note:
7102  * A negative value indicates infinite depth.
7103  * This can be used to prevent infinite loops in recursive trigger definitions.
7104  */
7105 int
7107 {
7108  return tr_Maximum_depth;
7109 }
7110 
7111 /*
7112  * tr_set_depth()
7113  * return: error code
7114  * depth(in):
7115  */
7116 int
7117 tr_set_depth (int depth)
7118 {
7119  if (depth > TR_MAX_RECURSION_LEVEL || depth < 0)
7120  {
7122  return ER_TR_MAX_DEPTH_TOO_BIG;
7123  }
7124 
7125  tr_Maximum_depth = depth;
7126  return NO_ERROR;
7127 }
7128 
7129 /*
7130  * tr_get_trace() - This is used to access the trigger trace flag.
7131  * return: trace
7132  *
7133  * Note:
7134  * Setting the trace flag to a non-zero value will enable the display
7135  * of trace messages to the standard output device.
7136  */
7137 int
7139 {
7140  return tr_Trace;
7141 }
7142 
7143 /*
7144  * tr_set_trace()
7145  * return: error code
7146  * trace(in):
7147  */
7148 int
7149 tr_set_trace (bool trace)
7150 {
7151  tr_Trace = trace;
7152  return NO_ERROR;
7153 }
7154 
7155 
7156 /* TRIGGER MODULE CONTROL */
7157 
7158 /*
7159  * tr_init()
7160  * return: none
7161  */
7162 void
7163 tr_init (void)
7164 {
7165  tr_Current_depth = 0;
7167  tr_Invalid_transaction = false;
7168  tr_Deferred_activities = NULL;
7169  tr_Deferred_activities_tail = NULL;
7172  tr_User_triggers = NULL;
7173  tr_Trace = false;
7174  tr_Uncommitted_triggers = NULL;
7176  tr_Schema_caches = NULL;
7177 
7178  /* create the object map */
7179  tr_object_map = mht_create ("Trigger object map", TR_EST_MAP_SIZE, mht_ptrhash, mht_compare_ptrs_are_equal);
7180 }
7181 
7182 /* Helper routine for tr_final */
7183 /*
7184  * map_flush_helper() -
7185  * return: int
7186  * key(in):
7187  * data(in):
7188  * args(in):
7189  */
7190 static int
7191 map_flush_helper (const void *key, void *data, void *args)
7192 {
7193  if (data != NULL)
7194  {
7195  free_trigger ((TR_TRIGGER *) data);
7196  }
7197  return NO_ERROR;
7198 }
7199 
7200 
7201 /*
7202  * tr_final() - Trigger shutdown function.
7203  * return: none
7204  */
7205 void
7206 tr_final (void)
7207 {
7209  tr_free_trigger_list (tr_User_triggers);
7210  tr_free_trigger_list (tr_Uncommitted_triggers);
7211  tr_User_triggers = NULL;
7212  tr_Uncommitted_triggers = NULL;
7213 
7214  /* need to free all trigger structures in the table */
7215  if (tr_object_map != NULL)
7216  {
7217  mht_map (tr_object_map, map_flush_helper, NULL);
7218  mht_destroy (tr_object_map);
7219  tr_object_map = NULL;
7220  }
7221 
7222  /*
7223  * Don't need to explicitly free these now since
7224  * they are allocated in the workspace. May need to change this.
7225  */
7226  tr_Schema_caches = NULL;
7227 }
7228 
7229 /*
7230  * tr_dump() - Dump status of the trigger manager.
7231  * return: none
7232  * fpp(in): ouput file
7233  *
7234  * Note:
7235  * Mostly this is used to get a list of the currently deferred activities for debugging purposes.
7236  * Since this list is likely to be generally useful, we should make this available in the API interface as well.
7237  * Possibly a session command too.
7238  */
7239 void
7240 tr_dump (FILE * fpp)
7241 {
7243  TR_TRIGLIST *t;
7244 
7245  fprintf (fpp, "TRIGGER MANAGER STATISTICS\n");
7246 
7247  fprintf (fpp, "Trigger execution state : %s\n", TR_EXECUTION_ENABLED ? "ENABLED" : "DISABLED");
7248  if (tr_Deferred_activities == NULL)
7249  {
7250  fprintf (fpp, "No deferred triggers.\n");
7251  }
7252  else
7253  {
7254  fprintf (fpp, "Deferred trigger list:\n");
7255  for (c = tr_Deferred_activities; c != NULL; c = c->next)
7256  {
7257  for (t = c->head; t != NULL; t = t->next)
7258  {
7259  fprintf (fpp, " %s\n", t->trigger->name);
7260  }
7261  }
7262  }
7263 }
7264 
7265 
7266 /*
7267  * TRIGGER DATABASE INSTALLATION
7268  */
7269 
7270 /*
7271  * define_trigger_classes() - This defines the classes necessary for storing triggers.
7272  * return: error code
7273  *
7274  * Note:
7275  * Currently there is only a single trigger object class.
7276  * This should only be called during createdb.
7277  */
7278 static int
7280 {
7281  DB_CTMPL *tmp;
7282  DB_OBJECT *class_mop;
7283  DB_VALUE value;
7284 
7285  tmp = NULL;
7286 
7288  if (tmp == NULL)
7289  {
7290  goto tmp_error;
7291  }
7292 
7293  if (dbt_add_attribute (tmp, TR_ATT_OWNER, "db_user", NULL))
7294  {
7295  goto tmp_error;
7296  }
7297 
7298  if (dbt_add_attribute (tmp, TR_ATT_NAME, "string", NULL))
7299  {
7300  goto tmp_error;
7301  }
7302 
7303  db_make_int (&value, TR_STATUS_ACTIVE);
7304  if (dbt_add_attribute (tmp, TR_ATT_STATUS, "integer", &value))
7305  {
7306  goto tmp_error;
7307  }
7308 
7310  if (dbt_add_attribute (tmp, TR_ATT_PRIORITY, "double", &value))
7311  {
7312  goto tmp_error;
7313  }
7314 
7315  db_make_int (&value, TR_EVENT_NULL);
7316  if (dbt_add_attribute (tmp, TR_ATT_EVENT, "integer", &value))
7317  {
7318  goto tmp_error;
7319  }
7320 
7321  if (dbt_add_attribute (tmp, TR_ATT_CLASS, "object", NULL))
7322  {
7323  goto tmp_error;
7324  }
7325 
7326  if (dbt_add_attribute (tmp, TR_ATT_ATTRIBUTE, "string", NULL))
7327  {
7328  goto tmp_error;
7329  }
7330 
7331  db_make_int (&value, 0);
7332  if (dbt_add_attribute (tmp, TR_ATT_CLASS_ATTRIBUTE, "integer", &value))
7333  {
7334  goto tmp_error;
7335  }
7336 
7337  if (dbt_add_attribute (tmp, TR_ATT_CONDITION_TYPE, "integer", NULL))
7338  {
7339  goto tmp_error;
7340  }
7341 
7342  if (dbt_add_attribute (tmp, TR_ATT_CONDITION, "string", NULL))
7343  {
7344  goto tmp_error;
7345  }
7346 
7347  db_make_int (&value, TR_TIME_AFTER);
7348  if (dbt_add_attribute (tmp, TR_ATT_CONDITION_TIME, "integer", NULL))
7349  {
7350  goto tmp_error;
7351  }
7352 
7353  if (dbt_add_attribute (tmp, TR_ATT_ACTION_TYPE, "integer", NULL))
7354  {
7355  goto tmp_error;
7356  }
7357 
7358  if (dbt_add_attribute (tmp, TR_ATT_ACTION, "string", NULL))
7359  {
7360  goto tmp_error;
7361  }
7362 
7363  db_make_int (&value, TR_TIME_AFTER);
7364  if (dbt_add_attribute (tmp, TR_ATT_ACTION_TIME, "integer", NULL))
7365  {
7366  goto tmp_error;
7367  }
7368 
7369  if (dbt_add_attribute (tmp, TR_ATT_COMMENT, "varchar(1024)", NULL))
7370  {
7371  goto tmp_error;
7372  }
7373 
7374  class_mop = dbt_finish_class (tmp);
7375  if (class_mop == NULL)
7376  {
7377  goto tmp_error;
7378  }
7379 
7380  if (locator_create_heap_if_needed (class_mop, false) == NULL)
7381  {
7382  goto tmp_error;
7383  }
7384 
7385  return NO_ERROR;
7386 
7387 tmp_error:
7388  if (tmp != NULL)
7389  {
7390  dbt_abort_class (tmp);
7391  }
7392 
7393  ASSERT_ERROR ();
7394  return er_errid ();
7395 }
7396 
7397 /*
7398  * tr_install() - Trigger installation function.
7399  * return: error code
7400  *
7401  * Note:
7402  * A system class called TRIGGER is created, and initialized.
7403  * The function should be called exactly once in createdb.
7404  */
7405 int
7407 {
7408  return (define_trigger_classes ());
7409 }
7410 
7411 /*
7412  * tr_get_execution_state() - Returns the current trigger execution state.
7413  * return: bool
7414  */
7415 bool
7417 {
7418  return tr_Execution_enabled;
7419 }
7420 
7421 /*
7422  * tr_set_execution_state() - Returns the previous trigger firing enabled
7423  * state.
7424  * return: bool
7425  * new_state(in): bool
7426  * true : enables trigger firing state
7427  * false : disables trigger firing state
7428  */
7429 bool
7430 tr_set_execution_state (bool new_state)
7431 {
7432  bool old_state = tr_Execution_enabled;
7433 
7434  tr_Execution_enabled = new_state;
7435 
7436  return old_state;
7437 }
7438 
7439 const char *
7441 {
7442  return TR_CLASS_NAME;
7443 }
7444 
7445 #if defined(ENABLE_UNUSED_FUNCTION)
7446 
7447 /*
7448  * tr_downcase_all_trigger_info() -/
7449  * return: int
7450  */
7451 int
7452 tr_downcase_all_trigger_info (void)
7453 {
7454  DB_OBJLIST *list, *mop;
7455  MOP class_mop, obj;
7456  DB_VALUE value;
7457  char *attribute;
7458 
7459  class_mop = sm_find_class (TR_CLASS_NAME);
7460  if (class_mop == NULL)
7461  {
7462  return ER_FAILED;
7463  }
7464 
7465  list = sm_fetch_all_objects (class_mop, DB_FETCH_QUERY_WRITE);
7466  if (list == NULL)
7467  {
7468  return ER_FAILED;
7469  }
7470 
7471  for (mop = list; mop != NULL; mop = mop->next)
7472  {
7473  obj = mop->op;
7474  if (obj_get (obj, "target_attribute", &value) != NO_ERROR)
7475  break;
7476 
7477  if (!DB_IS_NULL (&value))
7478  {
7479  attribute = db_get_string (&value);
7480  sm_downcase_name (attribute, attribute, SM_MAX_IDENTIFIER_LENGTH);
7481  if (obj_set (obj, "target_attribute", &value) != NO_ERROR)
7482  break;
7483  ws_dirty (obj);
7484  }
7485  }
7486  ml_ext_free (list);
7487  return ((mop == NULL) ? NO_ERROR : ER_FAILED);
7488 }
7489 #endif /* ENABLE_UNUSED_FUNCTION */
unsigned decached
Definition: work_space.h:152
DB_OBJECT * db_find_class(const char *name)
Definition: db_info.c:133
DB_C_FLOAT db_get_float(const DB_VALUE *value)
#define ER_LK_UNILATERALLY_ABORTED
Definition: error_code.h:130
double priority
DB_TRIGGER_TIME time
static int eval_action(TR_TRIGGER *trigger, DB_OBJECT *current, DB_OBJECT *temp, bool *reject)
int tr_set_depth(int depth)
PT_NAME_INFO name
Definition: parse_tree.h:3318
void ws_clear_hints(MOP mop, bool leave_pinned)
Definition: work_space.c:3257
TR_TRIGGER * trigger
int tran_system_savepoint(const char *savept_name)
int tr_delete_triggers_for_class(TR_SCHEMA_CACHE **cache, DB_OBJECT *class_object)
#define WS_IS_DELETED(mop)
Definition: work_space.h:284
char * current_refname
int tr_drop_cache_trigger(TR_SCHEMA_CACHE *cache, DB_OBJECT *trigger_object)
PT_NODE * pt_get_errors(PARSER_CONTEXT *parser)
#define NO_ERROR
Definition: error_code.h:46
unsigned int mht_ptrhash(const void *key, const unsigned int ht_size)
Definition: memory_hash.c:547
TR_DEFERRED_CONTEXT * tr_Deferred_activities_tail
const char * TR_ATT_CONDITION_TIME
#define AU_DISABLE(save)
Definition: authenticate.h:106
int tr_delete_schema_cache(TR_SCHEMA_CACHE *cache, DB_OBJECT *class_object)
int set_drop_seq_element(DB_COLLECTION *set, int index)
Definition: set_object.c:2902
DB_COLLECTION * db_get_set(const DB_VALUE *value)
int tr_find_event_triggers(DB_TRIGGER_EVENT event, DB_OBJECT *class_mop, const char *attribute, bool active, DB_OBJLIST **list)
int tr_is_trigger(DB_OBJECT *trigger_object, int *status)
static int check_semantics(TR_TRIGGER *trigger)
int sm_is_system_class(MOP op)
#define ER_TR_INVALID_PRIORITY
Definition: error_code.h:590
static int tr_execute_activities(TR_STATE *state, DB_TRIGGER_TIME tr_time, DB_OBJECT *current, DB_OBJECT *temp)
#define ER_TR_BAD_TARGET_ATTR
Definition: error_code.h:597
int tr_merge_schema_cache(TR_SCHEMA_CACHE *destination, TR_SCHEMA_CACHE *source)
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
#define ASSERT_ERROR()
static PT_NODE * tr_check_correlation(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *walk_on)
int tr_Maximum_depth
const char * db_get_class_name(DB_OBJECT *class_)
Definition: db_info.c:608
static int tr_User_triggers_valid
static void free_state(TR_STATE *state)
#define ER_TR_NO_VCLASSES
Definition: error_code.h:595
#define ER_MVCC_SERIALIZABLE_CONFLICT
Definition: error_code.h:1484
#define ER_TR_REJECT_NOT_POSSIBLE
Definition: error_code.h:610
int tr_trigger_condition(DB_OBJECT *trigger_object, char **condition)
char * MOBJ
Definition: work_space.h:174
bool tr_get_execution_state(void)
#define ER_TR_TRIGGER_SELECT_FAILURE
Definition: error_code.h:600
static TR_ACTIVITY * make_activity(void)
int tr_add_cache_trigger(TR_SCHEMA_CACHE *cache, DB_OBJECT *trigger_object)
MOP Au_root
Definition: authenticate.c:300
void set_free(DB_COLLECTION *set)
Definition: set_object.c:2560
static int run_user_triggers(DB_TRIGGER_EVENT event, DB_TRIGGER_TIME time)
struct tr_activity * condition
static int validate_trigger(TR_TRIGGER *trigger)
#define PT_ERROR(parser, node, msg)
Definition: parse_tree.h:54
int db_get_int(const DB_VALUE *value)
void ws_dirty(MOP op)
Definition: work_space.c:1622
DB_TIMESTAMP timestamp
Definition: dbtype_def.h:766
MOBJ locator_create_heap_if_needed(MOP class_mop, bool reuse_oid)
Definition: locator_cl.c:5690
int db_is_vclass(DB_OBJECT *op)
Definition: db_virt.c:681
DB_C_DOUBLE db_get_double(const DB_VALUE *value)
#define ER_FAILED
Definition: error_code.h:47
const char * TR_ATT_ACTION
#define UNIQUE_SAVEPOINT_DROP_TRIGGER
int pt_exec_trigger_stmt(PARSER_CONTEXT *parser, PT_NODE *trigger_stmt, DB_OBJECT *object1, DB_OBJECT *object2, DB_VALUE *result)
Definition: compile.c:1373
DB_OBJECT * object
int tr_trigger_action_type(DB_OBJECT *trigger_object, DB_TRIGGER_ACTION *type)
int tr_trigger_attribute(DB_OBJECT *trigger_object, char **attribute)
#define ER_TR_INVALID_CONDITION_TYPE
Definition: error_code.h:608
int mht_rem(MHT_TABLE *ht, const void *key, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1952
#define TR_MAX_RECURSION_LEVEL
char tr_Invalid_transaction_trigger[SM_MAX_IDENTIFIER_LENGTH+2]
#define ER_QPROC_INVALID_XASLNODE
Definition: error_code.h:532
int tr_has_user_trigger(bool *has_user_trigger)
void pt_reset_error(PARSER_CONTEXT *parser)
void tr_abort(TR_STATE *state)
int sm_invalidate_trigger_cache(DB_OBJECT *classop)
const char * tr_time_as_string(DB_TRIGGER_TIME time)
const void * mht_put(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1778
static int map_flush_helper(const void *key, void *data, void *args)
#define ASSERT_ERROR_AND_SET(error_code)
static TR_TRIGLIST * tr_User_triggers
const char * TR_ATT_ACTION_TYPE
int tr_empty_schema_cache(TR_SCHEMA_CACHE *cache)
DB_OBJLIST * ml_ext_copy(DB_OBJLIST *list)
Definition: work_space.c:4832
int db_make_object(DB_VALUE *value, DB_C_OBJECT *obj)
#define SM_MAX_IDENTIFIER_LENGTH
DB_COLLECTION * set_create_sequence(int size)
Definition: set_object.c:2432
PT_NODE * pt_get_next_error(PT_NODE *errors, int *stmt_no, int *line_no, int *col_no, const char **msg)
PARSER_CONTEXT * parser_create_parser(void)
Definition: parse_tree.c:1169
static int compare_recursion_levels(int rl_1, int rl_2)
int tr_rename_trigger(DB_OBJECT *trigger_object, const char *name, bool call_from_api)
int tr_get_depth(void)
static void tr_finish(TR_STATE *state)
bool au_is_dba_group_member(MOP user)
DB_TRIGGER_EVENT event
DB_OBJECT * dbt_finish_class(DB_CTMPL *def)
Definition: db_temp.c:226
#define IS_CLASS_EVENT(event)
const char * TR_ATT_CONDITION_TYPE
int tr_trigger_name(DB_OBJECT *trigger_object, char **name)
int tr_trigger_priority(DB_OBJECT *trigger_object, double *priority)
TR_DEFERRED_CONTEXT * tr_Deferred_activities
DB_DATETIMETZ * db_get_datetimetz(const DB_VALUE *value)
void sm_downcase_name(const char *name, char *buf, int maxlen)
PT_SCOPE_INFO scope
Definition: parse_tree.h:3333
static void tr_clear_trigger(TR_TRIGGER *trigger)
#define ER_TR_ACTION_EVAL
Definition: error_code.h:617
static const int TR_RETURN_FALSE
int db_make_sequence(DB_VALUE *value, DB_C_SET *set)
#define ER_TR_CONDITION_EVAL
Definition: error_code.h:616
#define TR_LOWEST_PRIORITY
#define ER_TR_TRIGGER_NOT_FOUND
Definition: error_code.h:592
DB_OBJECT * dbt_finish_object(DB_OTMPL *def)
Definition: db_obj.c:560
TR_TRIGLIST * triggers[1]
static void flush_deferred_activities(void)
static int tr_drop_trigger_internal(TR_TRIGGER *trigger, int rollback, bool need_savepoint)
int tr_prepare_statement(TR_STATE **state_p, DB_TRIGGER_EVENT event, DB_OBJECT *class_mop, int attcount, const char **attnames)
#define ER_TR_MAX_DEPTH_TOO_BIG
Definition: error_code.h:1334
int er_errid(void)
static int compile_trigger_activity(TR_TRIGGER *trigger, TR_ACTIVITY *activity, int with_evaluate)
#define ER_TR_TRIGGER_ALTER_FAILURE
Definition: error_code.h:603
void dbt_abort_object(DB_OTMPL *def)
Definition: db_obj.c:616
static TR_TRIGLIST * tr_Uncommitted_triggers
int set_size(DB_COLLECTION *set)
Definition: set_object.c:3036
int tr_trigger_action(DB_OBJECT *trigger_object, char **action)
#define AU_SET_USER
Definition: authenticate.h:141
int tr_get_trace(void)
static int its_deleted(DB_OBJECT *object)
TR_TRIGLIST * triggers
int tr_drop_trigger(DB_OBJECT *obj, bool call_from_api)
void db_ws_free(void *ptr)
Definition: quick_fit.c:194
int tr_before(TR_STATE *state)
bool ws_is_same_object(MOP mop1, MOP mop2)
Definition: work_space.c:5065
struct tr_triglist * prev
#define AU_ALTER
Definition: authenticate.h:73
const char * TR_ATT_CONDITION
struct tr_schema_cache * next
int tr_trigger_comment(DB_OBJECT *trigger_object, char **comment)
static int trigger_table_rename(DB_OBJECT *trigger_object, const char *newname)
#define ER_TR_CONDITION_COMPILE
Definition: error_code.h:614
int tr_install(void)
static void remove_deferred_activity(TR_DEFERRED_CONTEXT *context, TR_TRIGLIST *element)
char * temp_refname
void parser_free_parser(PARSER_CONTEXT *parser)
Definition: parse_tree.c:1240
static TR_STATE * start_state(TR_STATE **current, const char *name)
int sm_drop_trigger(DB_OBJECT *classop, const char *attribute, int class_attribute, DB_OBJECT *trigger)
static int trigger_table_drop(const char *name)
DB_TIMESTAMPTZ * db_get_timestamptz(const DB_VALUE *value)
int dbt_put_internal(DB_OTMPL *def, const char *name, DB_VALUE *value)
Definition: db_obj.c:670
#define ER_TR_TRANSACTION_INVALIDATED
Definition: error_code.h:618
static void free_activity(TR_ACTIVITY *act)
int tr_set_status(DB_OBJECT *trigger_object, DB_TRIGGER_STATUS status, bool call_from_api)
const char * TR_ATT_CLASS_ATTRIBUTE
static const char * NEW_REFERENCE_NAME
#define ER_TR_MISSING_TARGET_CLASS
Definition: error_code.h:591
int db_make_string(DB_VALUE *value, DB_CONST_C_CHAR str)
DB_MONETARY * db_get_monetary(const DB_VALUE *value)
DB_OBJECT * tr_find_trigger(const char *name)
static bool tr_Execution_enabled
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
int sm_find_subclass_in_hierarchy(MOP hierarchy, MOP class_mop, bool *found)
MOP Au_dba_user
Definition: authenticate.c:334
DB_OBJECT * owner
DB_ATTRIBUTE * db_get_attribute(DB_OBJECT *obj, const char *name)
Definition: db_info.c:791
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
const char * TR_ATT_NAME
Definition: db_set.h:35
#define TR_MAX_PRINT_STRING
struct tr_activity * action
static void remove_trigger_list(TR_TRIGLIST **list, TR_TRIGGER *trigger)
static bool check_authorization(TR_TRIGGER *trigger, bool alter_flag)
static TR_TRIGGER * tr_make_trigger(void)
const char * TR_ATT_ACTION_OLD
static int eval_condition(TR_TRIGGER *trigger, DB_OBJECT *current, DB_OBJECT *temp, bool *status)
const char * tr_get_class_name(void)
int tran_abort_upto_system_savepoint(const char *savepoint_name)
#define assert(x)
const char * TR_ATT_EVENT
int set_filter(DB_COLLECTION *set)
Definition: set_object.c:3744
int tr_find_all_triggers(DB_OBJLIST **list)
const char * comment
static const char * EVAL_PREFIX
struct tr_schema_cache TR_SCHEMA_CACHE
int prm_get_integer_value(PARAM_ID prm_id)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
#define ER_TR_BAD_TARGET_CLASS
Definition: error_code.h:596
int tr_trigger_condition_time(DB_OBJECT *trigger_object, DB_TRIGGER_TIME *tr_time)
DB_OBJLIST * objects
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
DB_TRIGGER_STATUS status
DB_TRIGGER_ACTION type
static TR_STATE * make_state(void)
int tr_validate_schema_cache(TR_SCHEMA_CACHE *cache, MOP class_mop)
const char * original
Definition: parse_tree.h:2544
static int tr_User_triggers_modified
DB_DATETIME datetime
Definition: dbtype_def.h:783
int tr_trigger_action_time(DB_OBJECT *trigger_object, DB_TRIGGER_TIME *tr_time)
static const int TR_RETURN_TRUE
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
static void get_reference_names(TR_TRIGGER *trigger, TR_ACTIVITY *activity, const char **curname, const char **tempname)
static void reinsert_trigger_list(TR_TRIGLIST **list, TR_TRIGGER *trigger)
static int unregister_user_trigger(TR_TRIGGER *trigger, int rollback)
static const char * EVAL_SUFFIX
OID tr_Stack[TR_MAX_RECURSION_LEVEL+1]
#define min(a, b)
bool tr_Invalid_transaction
const char * sm_get_ch_name(MOP op)
void tr_dump(FILE *fpp)
DB_OBJECT * db_get_object(const DB_VALUE *value)
VID_OID oid_info
Definition: work_space.h:120
TR_CACHE_TYPE
int au_check_authorization(MOP op, DB_AUTH auth)
#define ER_EMERGENCY_ERROR
Definition: error_code.h:632
void * mht_get(MHT_TABLE *ht, const void *key)
Definition: memory_hash.c:1419
SP_PARSER_CTX * parser
#define ER_TR_INVALID_ACTION_TIME
Definition: error_code.h:604
#define NULL
Definition: freelistheap.h:34
OID oid
Definition: work_space.h:65
#define UNIQUE_SAVEPOINT_RENAME_TRIGGER
const char * er_msg(void)
int tr_Current_depth
const char * TR_ATT_COMMENT
int db_drop(DB_OBJECT *obj)
Definition: db_obj.c:190
static TR_RECURSION_DECISION tr_check_recursivity(OID oid, OID stack[], int stack_size, bool is_statement)
int sm_check_name(const char *name)
const char * TR_ATT_PROPERTIES
int dbt_add_attribute(DB_CTMPL *def, const char *name, const char *domain, DB_VALUE *default_value)
Definition: db_temp.c:272
int sm_add_trigger(DB_OBJECT *classop, const char *attribute, int class_attribute, DB_OBJECT *trigger)
#define err(fd,...)
Definition: porting.h:431
void tr_final(void)
int au_fetch_instance_force(MOP op, MOBJ *obj_ptr, AU_FETCHMODE fetchmode, LC_FETCH_VERSION_TYPE fetch_version_type)
int ml_remove(DB_OBJLIST **list, MOP mop)
Definition: work_space.c:4613
#define ER_TR_TRIGGER_DELETE_FAILURE
Definition: error_code.h:601
DB_CTMPL * dbt_create_class(const char *name)
Definition: db_temp.c:76
#define TM_TRAN_READ_FETCH_VERSION()
MHT_TABLE * mht_create(const char *name, int est_size, unsigned int(*hash_func)(const void *key, unsigned int ht_size), int(*cmp_func)(const void *key1, const void *key2))
Definition: memory_hash.c:894
#define ER_TR_INTERNAL_ERROR
Definition: error_code.h:607
int tr_set_trace(bool trace)
#define COMPARE_TRIGGER_NAMES
static DB_OBJECT * trigger_to_object(TR_TRIGGER *trigger)
int ml_ext_add(DB_OBJLIST **list, MOP mop, int *added_ptr)
Definition: work_space.c:4877
int tr_prepare_class(TR_STATE **state_p, TR_SCHEMA_CACHE *cache, MOP class_mop, DB_TRIGGER_EVENT event)
#define WS_CHN(obj)
Definition: work_space.h:309
#define ER_TR_ACTION_COMPILE
Definition: error_code.h:615
int db_put_internal(DB_OBJECT *obj, const char *name, DB_VALUE *value)
Definition: db_obj.c:347
int set_get_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2575
void ml_free(DB_OBJLIST *list)
Definition: work_space.c:4654
static int find_event_triggers(DB_TRIGGER_EVENT event, DB_OBJECT *class_mop, const char *attribute, bool active_filter, DB_OBJLIST **list)
TR_RECURSION_DECISION
struct db_objlist * next
Definition: dbtype_def.h:442
int tr_after(TR_STATE *state)
int pr_clear_value(DB_VALUE *value)
DB_BIGINT db_get_bigint(const DB_VALUE *value)
static const char * time_as_string(DB_TRIGGER_TIME tr_time)
#define max(a, b)
static int execute_activity(TR_TRIGGER *trigger, DB_TRIGGER_TIME tr_time, DB_OBJECT *current, DB_OBJECT *temp, bool *rejected)
int tr_set_comment(DB_OBJECT *trigger_object, const char *comment, bool call_from_api)
int tr_unmap_trigger(TR_TRIGGER *trigger)
int ws_mop_compare(MOP mop1, MOP mop2)
Definition: work_space.c:3144
unsigned short array_length
int locator_flush_instance(MOP mop)
Definition: locator_cl.c:5236
int tr_set_priority(DB_OBJECT *trigger_object, double priority, bool call_from_api)
struct db_object * op
Definition: dbtype_def.h:443
int mht_compare_ptrs_are_equal(const void *key1, const void *key2)
Definition: memory_hash.c:779
DB_TRIGGER_TIME
Definition: dbtype_def.h:388
MOP Au_user
Definition: authenticate.c:343
const char * TR_CLASS_NAME
int set_put_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2719
static void error(const char *msg)
Definition: gencat.c:331
PT_NODE * pt_compile_trigger_stmt(PARSER_CONTEXT *parser, const char *trigger_stmt, DB_OBJECT *class_op, const char *name1, const char *name2)
Definition: compile.c:1018
int db_make_float(DB_VALUE *value, const DB_C_FLOAT num)
int ml_add(DB_OBJLIST **list, MOP mop, int *added_ptr)
Definition: work_space.c:4493
int tr_update_user_cache(void)
bool tr_Trace
DB_OBJLIST * sm_fetch_all_objects(DB_OBJECT *op, DB_FETCH_MODE purpose)
const char * TR_ATT_PRIORITY
void tr_free_trigger_list(TR_TRIGLIST *list)
DB_OTMPL * dbt_create_object_internal(DB_OBJECT *classobj)
#define AU_SELECT
Definition: authenticate.h:69
static int get_user_trigger_objects(DB_TRIGGER_EVENT event, bool active_filter, DB_OBJLIST **trigger_list)
DB_OBJLIST * ml_copy(DB_OBJLIST *list)
Definition: work_space.c:4671
#define ARG_FILE_LINE
Definition: error_manager.h:44
static TR_SCHEMA_CACHE * tr_Schema_caches
void ws_decache(MOP mop)
Definition: work_space.c:2701
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
int tr_get_cache_objects(TR_SCHEMA_CACHE *cache, DB_OBJLIST **list)
const char * tr_event_as_string(DB_TRIGGER_EVENT event)
int locator_all_flush(void)
Definition: locator_cl.c:5457
int obj_set(MOP op, const char *name, DB_VALUE *value)
#define AU_ENABLE(save)
Definition: authenticate.h:113
static int get_schema_trigger_objects(DB_OBJECT *class_mop, const char *attribute, DB_TRIGGER_EVENT event, bool active_flag, DB_OBJLIST **objlist)
PT_NODE * stmt
Definition: parse_tree.h:2679
#define ER_TR_EXCEEDS_MAX_REC_LEVEL
Definition: error_code.h:605
static void free_trigger(TR_TRIGGER *trigger)
static TR_DEFERRED_CONTEXT * add_deferred_activity_context(void)
void tr_init(void)
void tr_check_abort_triggers(void)
int tr_dump_trigger(print_output &output_ctx, DB_OBJECT *trigger_object)
static char * tr_process_name(const char *name_string)
#define ER_TR_REJECT_AFTER_EVENT
Definition: error_code.h:609
#define free_and_init(ptr)
Definition: memory_alloc.h:147
static void reorder_schema_caches(TR_TRIGGER *trigger)
#define strlen(s1)
Definition: intl_support.c:43
static int trigger_table_add(const char *name, DB_OBJECT *trigger)
DB_DATE * db_get_date(const DB_VALUE *value)
int oid_compare(const void *a, const void *b)
Definition: oid.c:243
static const int TR_RETURN_ERROR
static char * get_user_name(DB_OBJECT *user)
int obj_inst_lock(MOP op, int for_write)
DB_TRIGGER_EVENT
Definition: dbtype_def.h:356
int db_make_string_copy(DB_VALUE *value, DB_CONST_C_CHAR str)
unsigned int date
Definition: dbtype_def.h:776
const char * TR_ATT_CLASS
#define ER_HEAP_UNKNOWN_OBJECT
Definition: error_code.h:102
int tr_trigger_event(DB_OBJECT *trigger_object, DB_TRIGGER_EVENT *event)
int db_get(DB_OBJECT *object, const char *attpath, DB_VALUE *value)
Definition: db_obj.c:233
bool tr_set_execution_state(bool new_state)
void ml_ext_free(DB_OBJLIST *list)
Definition: work_space.c:4806
static void remove_deferred_context(TR_DEFERRED_CONTEXT *c)
struct tr_deferred_context * prev
bool prm_get_bool_value(PARAM_ID prm_id)
const char * tr_status_as_string(DB_TRIGGER_STATUS status)
static int merge_trigger_list(TR_TRIGLIST **list, TR_TRIGLIST *more, int destructive)
DB_TIMESTAMP * db_get_timestamp(const DB_VALUE *value)
DB_C_SHORT db_get_short(const DB_VALUE *value)
struct tr_triglist * next
void * db_ws_alloc(size_t size)
Definition: quick_fit.c:73
void er_clear(void)
int tr_active_schema_cache(MOP class_mop, TR_SCHEMA_CACHE *cache, DB_TRIGGER_EVENT event_type, bool *has_event_type_triggers)
#define ER_TR_REJECTED
Definition: error_code.h:606
int tr_trigger_status(DB_OBJECT *trigger_object, DB_TRIGGER_STATUS *status)
TR_SCHEMA_CACHE * tr_make_schema_cache(TR_CACHE_TYPE type, DB_OBJLIST *objects)
int tr_before_object(TR_STATE *state, DB_OBJECT *current, DB_OBJECT *temp)
struct tr_deferred_context * next
DB_OBJECT * class_mop
TR_TRIGGER * tr_map_trigger(DB_OBJECT *object, int fetch)
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
int i
Definition: dynamic_load.c:954
TR_SCHEMA_CACHE * tr_copy_schema_cache(TR_SCHEMA_CACHE *cache, MOP filter_class)
static int register_user_trigger(DB_OBJECT *object)
int mht_map(const MHT_TABLE *ht, int(*map_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:2199
#define UNIQUE_SAVEPOINT_CREATE_TRIGGER
static const char * OLD_REFERENCE_NAME
#define DB_IS_NULL(value)
Definition: dbtype.h:63
static int object_to_trigger(DB_OBJECT *object, TR_TRIGGER *trigger)
MOP sm_get_class(MOP obj)
static int signal_evaluation_error(TR_TRIGGER *trigger, int error)
static bool check_target(DB_TRIGGER_EVENT event, DB_OBJECT *class_mop, const char *attribute)
static const char * OBJ_REFERENCE_NAME
char * attribute
int obj_get(MOP op, const char *name, DB_VALUE *value)
int db_make_double(DB_VALUE *value, const DB_C_DOUBLE num)
char * strdup(const char *str)
Definition: porting.c:901
DB_TRIGGER_STATUS
Definition: dbtype_def.h:344
void dbt_abort_class(DB_CTMPL *def)
Definition: db_temp.c:249
DB_DATETIME * db_get_datetime(const DB_VALUE *value)
const char * TR_ATT_OWNER
int db_value_clear(DB_VALUE *value)
Definition: db_macro.c:1588
int set_insert_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2781
int db_make_int(DB_VALUE *value, const int num)
const char * TR_ATT_ACTION_TIME
#define pt_has_error(parser)
Definition: parser.h:507
MOP sm_find_class(const char *name)
static int trigger_table_find(const char *name, DB_OBJECT **trigger_p)
static int add_deferred_activities(TR_TRIGLIST *triggers, MOP current)
DB_OBJECT * tr_create_trigger(const char *name, DB_TRIGGER_STATUS status, double priority, DB_TRIGGER_EVENT event, DB_OBJECT *class_mop, const char *attribute, DB_TRIGGER_TIME cond_time, const char *cond_source, DB_TRIGGER_TIME action_time, DB_TRIGGER_ACTION action_type, const char *action_source, const char *comment)
const char * resolved
Definition: parse_tree.h:2545
int tr_trigger_class(DB_OBJECT *trigger_object, DB_OBJECT **class_mop_p)
int tr_check_commit_triggers(DB_TRIGGER_TIME time)
#define ER_TR_TRIGGER_EXISTS
Definition: error_code.h:594
#define ER_TR_MISSING_ACTION_STRING
Definition: error_code.h:612
void tr_free_schema_cache(TR_SCHEMA_CACHE *cache)
char * ws_copy_string(const char *str)
Definition: work_space.c:3457
DB_TIME * db_get_time(const DB_VALUE *value)
#define TR_EXECUTION_ENABLED
int tr_after_object(TR_STATE *state, DB_OBJECT *current, DB_OBJECT *temp)
DB_TRIGGER_ACTION
Definition: dbtype_def.h:397
int tr_check_authorization(DB_OBJECT *trigger_object, int alter_flag)
static int find_all_triggers(bool active_filter, bool alter_filter, DB_OBJLIST **list)
#define ER_TR_INVALID_EVENT
Definition: error_code.h:902
static MHT_TABLE * tr_object_map
void tr_invalidate_user_cache(void)
#define ER_TR_CORRELATION_ERROR
Definition: error_code.h:935
#define MAX_ERROR_STRING
double amount
Definition: dbtype_def.h:831
int sm_get_trigger_cache(DB_OBJECT *classop, const char *attribute, int class_attribute, void **cache)
int tr_drop_deferred_activities(DB_OBJECT *trigger_object, DB_OBJECT *target)
static int insert_trigger_list(TR_TRIGLIST **list, TR_TRIGGER *trigger)
PT_NODE * parser_walk_tree(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE_WALK_FUNCTION pre_function, void *pre_argument, PT_NODE_WALK_FUNCTION post_function, void *post_argument)
const char * TR_ATT_STATUS
const char * TR_ATT_ATTRIBUTE
static bool value_as_boolean(DB_VALUE *value)
#define ER_TR_ACTIVITY_NOT_OWNED
Definition: error_code.h:613
static void remove_trigger_list_element(TR_TRIGLIST **list, TR_TRIGLIST *element)
int au_fetch_class_force(MOP op, SM_CLASS **class_, AU_FETCHMODE fetchmode)
static const int TR_EST_MAP_SIZE
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
#define ER_IS_ABORTED_DUE_TO_DEADLOCK(err)
unsigned int time
Definition: dbtype_def.h:777
int set_drop_element(DB_COLLECTION *set, DB_VALUE *value, bool match_nulls)
Definition: set_object.c:2842
int tr_execute_deferred_activities(DB_OBJECT *trigger_object, DB_OBJECT *target)
DB_OBJECT * target
#define TM_TRAN_ISOLATION()
void tr_check_rollback_triggers(DB_TRIGGER_TIME time)
static int define_trigger_classes(void)