CUBRID Engine  latest
trigger_description.cpp
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_description.cpp
21  */
22 
23 #include "trigger_description.hpp"
24 
25 #include "authenticate.h"
26 #include "dbi.h"
27 #include "dbtype_function.h"
28 #include "object_accessor.h"
29 #include "object_print.h"
30 #include "object_printer.hpp"
31 #include "object_print_util.hpp"
32 #include "printer.hpp"
33 #include "set_object.h"
34 #include "schema_manager.h"
35 #include "trigger_manager.h"
36 #include "work_space.h"
37 
38 /* safe string free */
39 #define STRFREE_W(string) \
40  if (string != NULL) db_string_free((char *) (string))
41 
42 static int is_required_trigger (TR_TRIGGER *trigger, DB_OBJLIST *classes);
43 static char *get_user_name (DB_OBJECT *user);
44 
46  : name (0)
47  , event (0)
48  , class_name (0)
49  , attribute (0)
50  , full_event (0)
51  , status (0)
52  , priority (0)
53  , condition_time (0)
54  , condition (0)
55  , action_time (0)
56  , action (0)
57  , comment (0)
58 {
59 }
60 
62 {
63  struct db_object *trobj = tr_find_trigger (name);
64 
65  if (trobj == NULL)
66  {
67  return ER_FAILED;
68  }
69 
70  return init (trobj);
71 }
72 
74 {
75  assert (trobj != NULL);
76 
77  char *condition = NULL, *action = NULL, *classname;
78  TR_TRIGGER *trigger;
79 
80  trigger = tr_map_trigger (trobj, 1);
81  if (trigger == NULL)
82  {
83  return ER_FAILED;
84  }
85 
86  /* even though we have the trigger, use these to get the expressions translated into a simple string */
87  if (db_trigger_condition (trobj, &condition) != NO_ERROR)
88  {
89  ws_free_string (condition);
90  return ER_FAILED;
91  }
92  if (db_trigger_action (trobj, &action) != NO_ERROR)
93  {
94  ws_free_string (action);
95  return ER_FAILED;
96  }
97 
98  /* copy these */
99  this->name = object_print::copy_string (trigger->name);
100  this->attribute = object_print::copy_string (trigger->attribute);
101  this->comment = object_print::copy_string (trigger->comment);
102 
103  /* these are already copies */
104  this->condition = condition;
105  this->action = action;
106 
107  /* these are constant strings that don't need to ever change */
108  this->event = tr_event_as_string (trigger->event);
111 
112  /* only show status if its inactive */
113  if (trigger->status != TR_STATUS_ACTIVE)
114  {
115  this->status = tr_status_as_string (trigger->status);
116  }
117 
118  /* if its 0, leave it out */
119  if (trigger->priority != 0.0)
120  {
121  char temp_buffer[64];
122 
123  sprintf (temp_buffer, "%f", trigger->priority);
124  this->priority = object_print::copy_string (temp_buffer);
125  }
126 
127  if (trigger->class_mop != NULL)
128  {
129  classname = (char *) sm_get_ch_name (trigger->class_mop);
130  if (classname != NULL)
131  {
132  this->class_name = object_print::copy_string ((char *) classname);
133  }
134  else
135  {
136  this->class_name = object_print::copy_string ("*** deleted class ***");
137  }
138 
139  /* format the full event specification so csql can display it without being dependent on syntax */
140 
141  char buffer[ (SM_MAX_IDENTIFIER_LENGTH * 2) + 32];
142 
143  if (this->attribute != NULL)
144  {
145  sprintf (buffer, "%s ON %s(%s)", this->event, this->class_name, this->attribute);
146  }
147  else
148  {
149  sprintf (buffer, "%s ON %s", this->event, this->class_name);
150  }
151 
152  this->full_event = object_print::copy_string (buffer);
153  }
154  else
155  {
156  /* just make a copy of this so csql can simply use it without thinking */
157  this->full_event = object_print::copy_string ((char *) this->event);
158  }
159 
160  return NO_ERROR;
161 }
162 
164 {
165  /* these were allocated by this module and can be freed with free_and_init() */
166  free (name);
167  free (attribute);
168  free (class_name);
169  free (full_event);
170  free (priority);
171  if (comment)
172  {
173  free ((void *) comment);
174  }
175 
176  /* these were returned by the trigger manager and must be freed with db_string_free() */
178  STRFREE_W (action);
179 }
180 
181 /*
182  * help_print_trigger () - Debug function, primarily for help_print_info,
183  * can be useful in the debugger as well.
184  * Display the description of a trigger to stdout.
185  * return: none
186  * name(in): trigger name
187  * file(in):
188  */
190 {
191  if (name != NULL)
192  {
193  fprintf (file, "Trigger : %s\n", name);
194 
195  if (status != NULL)
196  {
197  fprintf (file, "Status : %s\n", status);
198  }
199 
200  if (priority != NULL)
201  {
202  fprintf (file, "Priority : %s\n", priority);
203  }
204 
205  fprintf (file, "Event : %s %s\n", condition_time, full_event);
206 
207  if (condition != NULL)
208  {
209  fprintf (file, "Condition : %s\n", condition);
210  }
211 
213  {
214  fprintf (file, "Action : %s %s\n", action_time, action);
215  }
216  else
217  {
218  fprintf (file, "Action : %s\n", action);
219  }
220 
221  if (comment != NULL)
222  {
223  fprintf (file, "Comment '%s'\n", comment);
224  }
225  }
226 }
227 
228 /*
229  * tr_dump_trigger() - This function is used to dump a trigger definition in ASCII format so that it can be read and
230  * re-defined from the csql interpreter.
231  * It is intended to support the unloaddb/loadbdb migration utilities.
232  * return: error code
233  * output_ctx(in/out): output context
234  * trigger_object(in): trigger object
235  * quoted_id_flag(in):
236  */
237 int
238 tr_dump_trigger (print_output &output_ctx, DB_OBJECT *trigger_object)
239 {
240  int error = NO_ERROR;
241  TR_TRIGGER *trigger;
242  DB_TRIGGER_TIME time;
243  int save;
244  const char *name;
245 
246  AU_DISABLE (save);
247 
248  trigger = tr_map_trigger (trigger_object, 1);
249 
250  if (trigger == NULL)
251  {
252  ASSERT_ERROR_AND_SET (error);
253  }
254  else if (trigger->status != TR_STATUS_INVALID)
255  {
256  /* automatically filter out invalid triggers */
257 
258  output_ctx ("CREATE TRIGGER ");
259  output_ctx ("[%s]\n", trigger->name);
260  output_ctx (" STATUS %s\n", tr_status_as_string (trigger->status));
261  output_ctx (" PRIORITY %f\n", trigger->priority);
262 
263  time = TR_TIME_BEFORE;
264  if (trigger->condition != NULL)
265  {
266  time = trigger->condition->time;
267  }
268  else if (trigger->action != NULL)
269  {
270  time = trigger->action->time;
271  }
272 
273  /* BEFORE UPDATE etc. */
274  output_ctx (" %s %s", tr_time_as_string (time), tr_event_as_string (trigger->event));
275 
276  if (trigger->class_mop != NULL)
277  {
278  name = db_get_class_name (trigger->class_mop);
279  output_ctx (" ON ");
280  output_ctx ("[%s]", name);
281 
282  if (trigger->attribute != NULL)
283  {
284  output_ctx ("([%s])", trigger->attribute);
285  }
286  }
287  output_ctx ("\n");
288 
289  if (trigger->condition != NULL)
290  {
291  output_ctx ("IF %s\n", trigger->condition->source);
292  }
293 
294  if (trigger->action != NULL)
295  {
296  output_ctx (" EXECUTE ");
297  if (trigger->action->time != time)
298  {
299  output_ctx ("%s ", tr_time_as_string (trigger->action->time));
300  }
301  switch (trigger->action->type)
302  {
303  case TR_ACT_EXPRESSION:
304  output_ctx ("%s", trigger->action->source);
305  break;
306  case TR_ACT_REJECT:
307  output_ctx ("REJECT");
308  break;
309  case TR_ACT_INVALIDATE:
310  output_ctx ("INVALIDATE TRANSACTION");
311  break;
312  case TR_ACT_PRINT:
313  output_ctx ("PRINT '%s'", trigger->action->source);
314  break;
315  default:
316  output_ctx ("???");
317  break;
318  }
319  }
320 
321  if (trigger->comment != NULL && trigger->comment[0] != '\0')
322  {
323  output_ctx (" ");
324  help_print_describe_comment (output_ctx, trigger->comment);
325  }
326 
327  output_ctx (";\n");
328  }
329 
330  AU_ENABLE (save);
331  return error;
332 }
333 
334 
335 /*
336  * tr_dump_selective_triggers() -
337  * return: error code
338  * output_ctx(in/out):
339  * quoted_id_flag(in):
340  * classes(in):
341  */
342 int
344 {
345  int error = NO_ERROR;
346  TR_TRIGGER *trigger;
347  DB_SET *table;
348  DB_VALUE value;
349  DB_OBJECT *trigger_object;
350  int max, i;
351 
352  if (Au_root == NULL)
353  {
354  return NO_ERROR;
355  }
356 
357  error = obj_get (Au_root, "triggers", &value);
358  if (error != NO_ERROR)
359  {
360  return error;
361  }
362 
363  if (DB_IS_NULL (&value))
364  {
365  table = NULL;
366  }
367  else
368  {
369  table = db_get_set (&value);
370  }
371 
372  if (table == NULL)
373  {
374  return NO_ERROR;
375  }
376 
377  error = set_filter (table);
378  max = set_size (table);
379  for (i = 1; i < max && error == NO_ERROR; i += 2)
380  {
381  error = set_get_element (table, i, &value);
382  if (error == NO_ERROR)
383  {
384  if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && !DB_IS_NULL (&value) && db_get_object (&value) != NULL)
385  {
386  trigger_object = db_get_object (&value);
387  trigger = tr_map_trigger (trigger_object, 1);
388  if (trigger == NULL)
389  {
390  ASSERT_ERROR_AND_SET (error);
391  }
392  else
393  {
394  int is_system_class = 0;
395 
396  if (trigger->class_mop != NULL && !is_required_trigger (trigger, classes))
397  {
398  continue;
399  }
400 
401  /* don't dump system class triggers */
402  if (trigger->class_mop != NULL)
403  {
404  is_system_class = sm_is_system_class (trigger->class_mop);
405  }
406  if (is_system_class == 0)
407  {
408  if (trigger->status != TR_STATUS_INVALID)
409  {
410  tr_dump_trigger (output_ctx, trigger_object);
411  output_ctx ("call [change_trigger_owner]('%s'," " '%s') on class [db_root];\n\n",
412  trigger->name, get_user_name (trigger->owner));
413  }
414  }
415  else if (is_system_class < 0)
416  {
417  error = is_system_class;
418  }
419  }
420  }
421  }
422  }
423  set_free (table);
424 
425  return error;
426 }
427 
428 /*
429  * is_required_trigger() -
430  * return: int
431  * trigger(in):
432  * classes(in):
433  */
434 static int
436 {
437  DB_OBJLIST *cl;
438 
439  for (cl = classes; cl != NULL; cl = cl->next)
440  {
441  if (trigger->class_mop == cl->op)
442  {
443  return 1;
444  }
445  }
446 
447  return 0;
448 }
449 
450 /*
451  * get_user_name() - Shorthand function for getting the user name out of a user object.
452  * The name is stored in a static array so we don't have to worry about freeing it.
453  * return: user name
454  * user(in): user object
455  */
456 static char *
458 {
459 #define MAX_USER_NAME 32 /* actually its 8 */
460 
461  static char namebuf[MAX_USER_NAME];
462 
463  DB_VALUE value;
464  const char *tmp;
465 
466  if (db_get (user, "name", &value))
467  {
468  /* error */
469  strcpy (namebuf, "???");
470  return namebuf;
471  }
472 
473  if (DB_VALUE_TYPE (&value) != DB_TYPE_STRING || DB_IS_NULL (&value) || db_get_string (&value) == NULL)
474  {
475  strcpy (namebuf, "???");
476  }
477  else
478  {
479  tmp = db_get_string (&value);
480  if (tmp)
481  {
482  strncpy (namebuf, tmp, sizeof (namebuf) - 1);
483  }
484  namebuf[MAX_USER_NAME - 1] = '\0';
485  }
486  db_value_clear (&value);
487 
488  return namebuf;
489 
490 #undef MAX_USER_NAME
491 }
double priority
DB_TRIGGER_TIME time
#define NO_ERROR
Definition: error_code.h:46
#define AU_DISABLE(save)
Definition: authenticate.h:106
char * copy_string(const char *source)
DB_COLLECTION * db_get_set(const DB_VALUE *value)
int tr_dump_selective_triggers(print_output &output_ctx, DB_OBJLIST *classes)
int sm_is_system_class(MOP op)
const char * db_get_class_name(DB_OBJECT *class_)
Definition: db_info.c:608
int init(const char *name)
MOP Au_root
Definition: authenticate.c:300
void set_free(DB_COLLECTION *set)
Definition: set_object.c:2560
struct tr_activity * condition
#define ER_FAILED
Definition: error_code.h:47
const char * tr_time_as_string(DB_TRIGGER_TIME time)
#define ASSERT_ERROR_AND_SET(error_code)
#define SM_MAX_IDENTIFIER_LENGTH
DB_TRIGGER_EVENT event
static const char * describe_trigger_condition_time(const tr_trigger &trigger)
#define STRFREE_W(string)
int set_size(DB_COLLECTION *set)
Definition: set_object.c:3036
static int is_required_trigger(TR_TRIGGER *trigger, DB_OBJLIST *classes)
void ws_free_string(const char *str)
Definition: work_space.c:3480
DB_OBJECT * tr_find_trigger(const char *name)
DB_OBJECT * owner
Definition: db_set.h:35
struct tr_activity * action
#define assert(x)
int set_filter(DB_COLLECTION *set)
Definition: set_object.c:3744
const char * comment
DB_TRIGGER_STATUS status
DB_TRIGGER_ACTION type
#define MAX_USER_NAME
const char * sm_get_ch_name(MOP op)
DB_OBJECT * db_get_object(const DB_VALUE *value)
#define NULL
Definition: freelistheap.h:34
int set_get_element(DB_COLLECTION *set, int index, DB_VALUE *value)
Definition: set_object.c:2575
struct db_objlist * next
Definition: dbtype_def.h:442
#define max(a, b)
struct db_object * op
Definition: dbtype_def.h:443
DB_TRIGGER_TIME
Definition: dbtype_def.h:388
static void error(const char *msg)
Definition: gencat.c:331
const char * tr_event_as_string(DB_TRIGGER_EVENT event)
#define AU_ENABLE(save)
Definition: authenticate.h:113
int tr_dump_trigger(print_output &output_ctx, DB_OBJECT *trigger_object)
static char * get_user_name(DB_OBJECT *user)
void help_print_describe_comment(print_output &output_ctx, const char *comment)
Definition: object_print.c:716
int db_get(DB_OBJECT *object, const char *attpath, DB_VALUE *value)
Definition: db_obj.c:233
const char * tr_status_as_string(DB_TRIGGER_STATUS status)
DB_OBJECT * class_mop
TR_TRIGGER * tr_map_trigger(DB_OBJECT *object, int fetch)
int db_trigger_condition(DB_OBJECT *trobj, char **condition)
Definition: db_obj.c:1663
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
int i
Definition: dynamic_load.c:954
static const char * describe_trigger_action_time(const tr_trigger &trigger)
#define DB_IS_NULL(value)
Definition: dbtype.h:63
int db_trigger_action(DB_OBJECT *trobj, char **action)
Definition: db_obj.c:1742
char * attribute
int obj_get(MOP op, const char *name, DB_VALUE *value)
int db_value_clear(DB_VALUE *value)
Definition: db_macro.c:1588
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)