CUBRID Engine  latest
compile.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  * compile.c - compile parse tree into executable form
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <assert.h>
28 
29 #include "authenticate.h"
30 #include "dbi.h"
31 #include "parser.h"
32 #include "semantic_check.h"
33 #include "locator_cl.h"
34 #include "memory_alloc.h"
35 #include "schema_manager.h"
36 #include "parser_message.h"
37 #include "view_transform.h"
38 #include "intl_support.h"
39 #include "server_interface.h"
40 #include "network_interface_cl.h"
41 #include "execute_statement.h"
42 #include "transaction_cl.h"
43 #include "dbtype.h"
44 
47 {
48  UINTPTR spec_id1;
49  UINTPTR spec_id2;
52  const char *name1;
53  const char *name2;
55  int trig_corr_path; /* path expr rooted by trigger corr name */
57 };
58 
59 /* structure used for parser_walk_tree in pt_class_pre_fetch */
62 {
66  char **classes;
67  int *only_all;
70 };
71 
73 {
76 };
77 
79 static PT_NODE *pt_count_entities (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
81 static PT_NODE *pt_find_lck_classes (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
83 static int pt_in_lck_array (PT_CLASS_LOCKS * lcks, const char *str, LC_PREFETCH_FLAGS flags);
84 
85 static void remove_appended_trigger_info (char *msg, int with_evaluate);
86 
87 static PT_NODE *pt_set_trigger_obj_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
88 static PT_NODE *pt_set_trigger_obj_post (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
89 static PT_NODE *pt_set_class_chn (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
90 
91 /*
92  * pt_spec_to_oid_attr () - Generate an oid attribute from a resolved spec.
93  * Can be called any time after name resolution.
94  * return: a PT_NAME node, or a NULL
95  * parser(in): the parser context used to derive stmt
96  * spec(in/out): an entity spec. requires spec has been resolved
97  * how(in):
98  */
99 
100 PT_NODE *
102 {
103  PT_NODE *node = NULL, *oid = NULL;
104  PT_NODE *flat;
105  PT_NODE *range;
106 
107  if (spec->info.spec.range_var == NULL)
108  return NULL;
109 
110  flat = spec->info.spec.flat_entity_list;
111  range = spec->info.spec.range_var;
112 
113  if (PT_SPEC_IS_DERIVED (spec) && spec->info.spec.flat_entity_list && spec->info.spec.as_attr_list)
114  {
115  /* this spec should have come from a vclass that was rewritten as a derived table; pull ROWOID/CLASSOID from
116  * as_attr_list NOTE: see mq_rewrite_derived_table_for_update () */
117  switch (how)
118  {
119  case OID_NAME:
120  return parser_copy_tree (parser, spec->info.spec.as_attr_list);
121 
122  case CLASSOID_NAME:
124  node = parser_copy_tree (parser, spec->info.spec.as_attr_list);
125  break;
126 
127  default:
128  /* should not be here */
129  return NULL;
130  }
131  }
132 
133  if (how == OID_NAME || how == CLASSOID_NAME || how == HIDDEN_CLASSOID_NAME || !flat
134  || (!flat->info.name.virt_object || mq_is_updatable (flat->info.name.virt_object)))
135  {
136  /* just generate an oid name, if that is what is asked for or the class is not a proxy and there is no view or
137  * the view is updatable */
138  if (node != NULL)
139  {
140  oid = node;
141  }
142  else
143  {
144  oid = pt_name (parser, "");
145  if (oid)
146  {
147  oid->info.name.resolved = range->info.name.original;
148  oid->info.name.meta_class = PT_OID_ATTR;
149  oid->info.name.spec_id = spec->info.spec.id;
150  oid->type_enum = PT_TYPE_OBJECT;
151  oid->data_type = parser_new_node (parser, PT_DATA_TYPE);
152  }
153  else
154  {
155  return NULL;
156  }
157  if (oid->data_type)
158  {
159  oid->data_type->type_enum = PT_TYPE_OBJECT;
160  oid->data_type->info.data_type.entity = parser_copy_tree_list (parser, flat);
161  }
162  else
163  {
164  return NULL;
165  }
166 
167  if (flat)
168  {
169  oid->data_type->info.data_type.virt_object = flat->info.name.virt_object;
170  oid->data_type->info.data_type.virt_type_enum = flat->info.name.virt_type_enum;
171  }
172  }
173  if (how == CLASSOID_NAME || how == HIDDEN_CLASSOID_NAME)
174  {
175  PT_NODE *func, *tmp;
176 
177  /* make into a class_of function with the generated OID as the argument */
178  func = parser_new_node (parser, PT_FUNCTION);
179  if (func)
180  {
182  func->info.function.arg_list = oid;
183  func->type_enum = PT_TYPE_OBJECT;
184  func->data_type = parser_new_node (parser, PT_DATA_TYPE);
185  }
186  else
187  {
188  return NULL;
189  }
190  if (func->data_type)
191  {
193  func->data_type->info.data_type.entity = parser_copy_tree_list (parser, flat);
194  for (tmp = func->data_type->info.data_type.entity; tmp != NULL; tmp = tmp->next)
195  {
197  }
198  }
199  else
200  {
201  return NULL;
202  }
203 
204 
205  if (flat)
206  {
209  }
210 
211  if (how == HIDDEN_CLASSOID_NAME)
212  {
213  func->info.function.hidden_column = 1;
214  }
215 
216  node = func; /* return the function */
217  }
218  else
219  {
220  node = oid; /* return the oid */
221  }
222  }
223  else
224  {
225  node = mq_oid (parser, spec);
226  }
227 
228  return node;
229 }
230 
231 
232 /*
233  * pt_add_oid_to_select_list () - augment a statement's select_list
234  * to select the oid
235  * return: none
236  * parser(in): the parser context used to derive statement
237  * statement(in/out): a SELECT/UNION/DIFFERENCE/INTERSECTION statement
238  * how(in):
239  */
240 
241 static PT_NODE *
243 {
244  PT_NODE *oid, *from;
245 
246  if (!statement)
247  {
248  return NULL;
249  }
250 
251  if (PT_IS_QUERY_NODE_TYPE (statement->node_type))
252  {
253  PT_NODE *p, *ord;
254 
255  /*
256  * It would be nice to make this adjustment more automatic by
257  * actually counting the number of "invisible" columns and keeping a
258  * running adjustment bias, but right now there doesn't seem to be a
259  * way of distinguishing invisible columns from ordinary ones, short
260  * of just knowing which style of adjustment is being made (single
261  * oid or multiple oids). If a new style is added, this code will
262  * need to be extended.
263  */
264  p = statement->info.query.order_by;
265  while (p)
266  {
267  ord = p->info.sort_spec.expr;
268  assert (ord->node_type == PT_VALUE);
269 
270  /* adjust value */
271  p->info.sort_spec.pos_descr.pos_no += 1;
274 
275  /* not needed any more */
277 
278  p = p->next;
279 
280  }
281  }
282 
283  if (statement->node_type == PT_SELECT)
284  {
285  /* value query doesn't have oid attr */
286  if (!PT_IS_VALUE_QUERY (statement))
287  {
288  statement->info.query.oids_included = DB_ROW_OIDS;
289  from = statement->info.query.q.select.from;
290  if (from && from->node_type == PT_SPEC)
291  {
292  oid = pt_spec_to_oid_attr (parser, from, how);
293  if (oid)
294  {
295  /* prepend oid to the statement's select_list */
296  oid->next = statement->info.query.q.select.list;
297  statement->info.query.q.select.list = oid;
298  }
299  }
300  }
301  }
302  else if (statement->node_type == PT_UNION || statement->node_type == PT_INTERSECTION
303  || statement->node_type == PT_DIFFERENCE)
304  {
305 
306  statement->info.query.oids_included = DB_ROW_OIDS;
307  statement->info.query.q.union_.arg1 =
308  pt_add_oid_to_select_list (parser, statement->info.query.q.union_.arg1, how);
309  statement->info.query.q.union_.arg2 =
310  pt_add_oid_to_select_list (parser, statement->info.query.q.union_.arg2, how);
311 
312  if (statement->info.query.q.union_.select_list != NULL)
313  {
314  /* after adding oid, we need to get select_list again */
315  parser_free_tree (parser, statement->info.query.q.union_.select_list);
316  statement->info.query.q.union_.select_list = NULL;
317 
318  (void) pt_get_select_list (parser, statement);
319  }
320  }
321 
322  return statement;
323 }
324 
325 /*
326  * pt_add_row_oid () - augment a statement's select_list to select the row oid
327  * return: none
328  * parser(in): the parser context used to derive statement
329  * statement(in/out): a SELECT/UNION/DIFFERENCE/INTERSECTION statement
330  */
331 
332 PT_NODE *
334 {
335  return pt_add_oid_to_select_list (parser, statement, VIEW_OID);
336 }
337 
338 /*
339  * pt_add_row_oid_name () - augment a statement's select_list to
340  * select the row oid
341  * return: none
342  * parser(in): the parser context used to derive statement
343  * statement(in/out): a SELECT/UNION/DIFFERENCE/INTERSECTION statement
344  */
345 
346 PT_NODE *
348 {
349  return pt_add_oid_to_select_list (parser, statement, OID_NAME);
350 }
351 
352 /*
353  * pt_add_row_classoid_name () - augment a statement's select_list
354  * to select the row oid
355  * return: none
356  * parser(in): the parser context used to derive statement
357  * statement(in/out): a SELECT/UNION/DIFFERENCE/INTERSECTION statement
358  */
359 
360 PT_NODE *
361 pt_add_row_classoid_name (PARSER_CONTEXT * parser, PT_NODE * statement, int server_op)
362 {
363  if (server_op)
364  {
365  return pt_add_oid_to_select_list (parser, statement, CLASSOID_NAME);
366  }
367  else
368  {
369  return pt_add_oid_to_select_list (parser, statement, HIDDEN_CLASSOID_NAME);
370  }
371 }
372 
373 /*
374  * pt_compile () - Semantic check and convert parse tree into executable form
375  * return:
376  * parser(in):
377  * statement(in/out):
378  */
379 PT_NODE *
380 pt_compile (PARSER_CONTEXT * parser, PT_NODE * volatile statement)
381 {
382  PT_NODE *next;
383 
384  PT_SET_JMP_ENV (parser);
385 
386  if (statement)
387  {
388  next = statement->next;
389  statement->next = NULL;
390 
391  statement = pt_semantic_check (parser, statement);
392 
393  /* restore link */
394  if (statement)
395  {
396  statement->next = next;
397  }
398  }
399 
400  PT_CLEAR_JMP_ENV (parser);
401 
402  return statement;
403 }
404 
405 
406 /*
407  * pt_class_pre_fetch () - minimize potential deadlocks by prefetching
408  * the classes the statement will need in the correct lock mode
409  * return:
410  * parser(in):
411  * statement(in):
412  *
413  * Note :
414  * This routine will not avoid deadlock altogether because classes which
415  * are implicitly accessed via path expressions are not know at this time.
416  * We are assured however that these implicit classes will be read only
417  * classes and will not need lock escalation. These implicit classes
418  * will be locked during semantic analysis.
419  *
420  * This routine will only prefetch for the following statement types:
421  * UPDATE, DELETE, INSERT, SELECT, UNION, DIFFERENCE, INTERSECTION.
422  *
423  * There are two types of errors:
424  * 1) lock timeout. In this case, we set an error and return.
425  * 2) unknown class. In this case, the user has a semantic error.
426  * We need to continue with semantic analysis so that the proper
427  * error msg will be returned. Thus WE DO NOT set an error for this case.
428  */
429 
430 PT_NODE *
432 {
433  PT_CLASS_LOCKS lcks;
434  PT_NODE *node = NULL;
435  LOCK lock_rr_tran = NULL_LOCK;
436  LC_FIND_CLASSNAME find_result;
437 
438  lcks.classes = NULL;
439  lcks.only_all = NULL;
440  lcks.locks = NULL;
441  lcks.flags = NULL;
442 
443  /* we don't pre fetch for non query statements */
444  if (statement == NULL)
445  {
446  return NULL;
447  }
448 
449  switch (statement->node_type)
450  {
451  case PT_DELETE:
452  case PT_INSERT:
453  case PT_UPDATE:
454  case PT_SELECT:
455  case PT_UNION:
456  case PT_DIFFERENCE:
457  case PT_INTERSECTION:
458  case PT_MERGE:
460  {
461  lock_rr_tran = S_LOCK;
462  }
463  break;
464  default:
466  {
468  {
469  lock_rr_tran = S_LOCK;
470  }
471  if (statement->node_type == PT_ALTER && statement->info.alter.code == PT_ADD_ATTR_MTHD)
472  {
473  for (node = statement->info.alter.alter_clause.attr_mthd.attr_def_list; node; node = node->next)
474  {
475  if (node->info.attr_def.constrain_not_null)
476  {
477  lock_rr_tran = X_LOCK;
478  break;
479  }
480  }
481  }
482  if (tran_lock_rep_read (lock_rr_tran) != NO_ERROR)
483  {
484  return NULL;
485  }
486  }
487 
488  if (statement->node_type == PT_CREATE_ENTITY && statement->info.create_entity.entity_type == PT_CLASS)
489  {
490  (void) parser_walk_tree (parser, statement, NULL, NULL, pt_resolve_cte_specs, NULL);
491  }
492 
493  return statement;
494  }
495 
496  /* specs referring a CTE will have an entity name, just like a normal class;
497  * in order to not try and prefetch (and possibly fail) such classes, we must first resolve such specs */
498  (void) parser_walk_tree (parser, statement, NULL, NULL, pt_resolve_cte_specs, NULL);
499 
500  lcks.num_classes = 0;
501 
502  /* pt_count_entities() will give us too large a count if a class is mentioned more than once, but this will not hurt
503  * us. */
504  (void) parser_walk_tree (parser, statement, pt_count_entities, &lcks.num_classes, NULL, NULL);
505 
506  if (lcks.num_classes == 0)
507  {
508  return statement; /* caught in semantic check */
509  }
510 
511  /* allocate the arrays */
512  lcks.allocated_count = lcks.num_classes;
513  lcks.classes = (char **) malloc ((lcks.num_classes + 1) * sizeof (char *));
514  if (lcks.classes == NULL)
515  {
517  lcks.num_classes * sizeof (char *));
518  goto cleanup;
519  }
520 
521  lcks.only_all = (int *) malloc (lcks.num_classes * sizeof (int));
522  if (lcks.only_all == NULL)
523  {
525  lcks.num_classes * sizeof (int));
526  goto cleanup;
527  }
528 
529  lcks.locks = (LOCK *) malloc (lcks.num_classes * sizeof (LOCK));
530  if (lcks.locks == NULL)
531  {
533  lcks.num_classes * sizeof (DB_FETCH_MODE));
534  goto cleanup;
535  }
536  memset (lcks.classes, 0, (lcks.num_classes + 1) * sizeof (char *));
537 
538  lcks.flags = (LC_PREFETCH_FLAGS *) malloc (lcks.num_classes * sizeof (LC_PREFETCH_FLAGS));
539  if (lcks.flags == NULL)
540  {
542  lcks.num_classes * sizeof (DB_FETCH_MODE));
543  goto cleanup;
544  }
545  memset (lcks.flags, 0, lcks.num_classes * sizeof (LC_PREFETCH_FLAGS));
546 
547  /* reset so parser_walk_tree can step through arrays */
548  lcks.num_classes = 0;
549 
550  (void) parser_walk_tree (parser, statement, pt_find_lck_classes, &lcks, NULL, NULL);
551 
552  if (!pt_has_error (parser)
553  && (find_result =
554  locator_lockhint_classes (lcks.num_classes, (const char **) lcks.classes, lcks.locks, lcks.only_all,
555  lcks.flags, true, lock_rr_tran)) != LC_CLASSNAME_EXIST)
556  {
557  if (find_result == LC_CLASSNAME_ERROR
559  {
560  /*
561  * Transaction has been aborted, the dirty objects and cached
562  * locks has been cleared in current client during the above
563  * locator_lockhint_classes () process. Therefore, must return from
564  * this function immediately, otherwise the released 'statement'
565  * (or other resources) will cause the unexpected problems.
566  */
567  goto cleanup;
568  }
569 
570  PT_ERRORc (parser, statement, db_error_string (3));
571  }
572 
573  /* free already assigned parser->lcks_classes if exist */
574  parser_free_lcks_classes (parser);
575 
576  /* parser->lcks_classes will be freed at parser_free_parser() */
577  parser->lcks_classes = lcks.classes;
578  parser->num_lcks_classes = lcks.num_classes;
579  lcks.classes = NULL;
580 
581  (void) parser_walk_tree (parser, statement, pt_set_class_chn, NULL, NULL, NULL);
582 
583 cleanup:
584  if (lcks.classes)
585  {
586  free_and_init (lcks.classes);
587  }
588 
589  if (lcks.only_all)
590  {
591  free_and_init (lcks.only_all);
592  }
593 
594  if (lcks.locks)
595  {
596  free_and_init (lcks.locks);
597  }
598  if (lcks.flags)
599  {
600  free_and_init (lcks.flags);
601  }
602  return statement;
603 }
604 
605 /*
606  * pt_set_class_chn() -
607  * return:
608  * parser(in):
609  * node(in):
610  * arg(in):
611  * continue_walk(out):
612  */
613 static PT_NODE *
614 pt_set_class_chn (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
615 {
616  PT_NODE *class_;
617  MOP clsmop = NULL;
618  int is_class = 0;
619 
620  if (node->node_type == PT_SPEC)
621  {
622  for (class_ = node->info.spec.flat_entity_list; class_; class_ = class_->next)
623  {
624  clsmop = class_->info.name.db_object;
625  if (clsmop == NULL)
626  {
627  continue;
628  }
629  is_class = db_is_class (clsmop);
630  if (is_class < 0)
631  {
632  PT_ERRORc (parser, class_, er_msg ());
633  continue;
634  }
635  if (is_class == 0)
636  {
637  continue;
638  }
639 
640  if (locator_flush_class (clsmop) != NO_ERROR)
641  {
642  PT_ERRORc (parser, class_, er_msg ());
643  }
644 
646  }
647  }
648 
649  return node;
650 }
651 
652 /*
653  * pt_count_entities () - If the node is an entity spec, bump counter
654  * return:
655  * parser(in):
656  * node(in): the node to check, leave node unchanged
657  * arg(out): count of entities
658  * continue_walk(in):
659  */
660 static PT_NODE *
661 pt_count_entities (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
662 {
663  int *cnt = (int *) arg;
664 
665  if (node->node_type == PT_SPEC)
666  {
667  (*cnt)++;
668  if (node->info.spec.partition != NULL)
669  {
670  (*cnt)++;
671  }
672  }
673 
674  return node;
675 }
676 
677 /*
678  * pt_add_lock_class () - add class locks in the prefetch structure
679  * return : error code or NO_ERROR
680  * parser (in) : parser context
681  * lcks (in/out) : pointer to PT_CLASS_LOCKS structure
682  * spec (in) : spec to add in locks list.
683  * flags(in) : the scope for which this class is added (either for
684  * locking or for count optimization)
685  */
686 int
688 {
689  int len = 0;
690 
691  if (lcks->num_classes >= lcks->allocated_count)
692  {
693  /* Need to allocate more space in the locks array. Do not free locks array if memory allocation fails, it will be
694  * freed by the caller of this function */
695  size_t new_size = lcks->allocated_count + 1;
696 
697  /* expand classes */
698  char **const realloc_ptr_classes = (char **) realloc (lcks->classes, new_size * sizeof (char *));
699  if (realloc_ptr_classes == NULL)
700  {
702  new_size * sizeof (char *));
703  return ER_FAILED;
704  }
705  lcks->classes = realloc_ptr_classes;
706 
707  /* expand only_all */
708  int *const realloc_ptr_only_all = (int *) realloc (lcks->only_all, new_size * sizeof (int));
709  if (realloc_ptr_only_all == NULL)
710  {
711  PT_ERRORmf (parser, spec, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_OUT_OF_MEMORY, new_size * sizeof (int));
712  return ER_FAILED;
713  }
714  lcks->only_all = realloc_ptr_only_all;
715 
716  /* expand locks */
717  LOCK *const realloc_ptr_locks = (LOCK *) realloc (lcks->locks, new_size * sizeof (LOCK));
718  if (realloc_ptr_locks == NULL)
719  {
720  PT_ERRORmf (parser, spec, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_OUT_OF_MEMORY, new_size * sizeof (LOCK));
721  return ER_FAILED;
722  }
723  lcks->locks = realloc_ptr_locks;
724 
725  /* flags */
726  LC_PREFETCH_FLAGS *const realloc_ptr_flags
727  = (LC_PREFETCH_FLAGS *) realloc (lcks->flags, new_size * sizeof (LC_PREFETCH_FLAGS));
728  if (realloc_ptr_flags == NULL)
729  {
731  new_size * sizeof (LC_PREFETCH_FLAGS));
732  return ER_FAILED;
733  }
734  lcks->flags = realloc_ptr_flags;
735 
736  lcks->allocated_count++;
737  }
738 
739  /* need to lowercase the class name so that the lock manager can find it. */
740  len = (int) strlen (spec->info.spec.entity_name->info.name.original);
741  /* parser->lcks_classes[n] will be freed at parser_free_parser() */
742  lcks->classes[lcks->num_classes] = (char *) calloc (1, len + 1);
743  if (lcks->classes[lcks->num_classes] == NULL)
744  {
747  }
748 
749  sm_downcase_name (spec->info.spec.entity_name->info.name.original, lcks->classes[lcks->num_classes], len + 1);
750 
751  if (spec->info.spec.only_all == PT_ONLY)
752  {
753  lcks->only_all[lcks->num_classes] = 0;
754  }
755  else
756  {
757  lcks->only_all[lcks->num_classes] = 1;
758  }
759 
760  if (flags & LC_PREF_FLAG_LOCK)
761  {
763  }
764  else
765  {
766  lcks->locks[lcks->num_classes] = NA_LOCK;
767  }
768  lcks->flags[lcks->num_classes] = flags;
769 
770  lcks->num_classes++;
771 
772  return NO_ERROR;
773 }
774 
775 /*
776  * pt_find_lck_classes () - identifies classes and adds an unique entry in the
777  * prefetch structure with the SCH-S lock mode
778  * return:
779  * parser(in):
780  * node(in): the node to check, returns node unchanged
781  * arg(in/out): pointer to PT_CLASS_LOCKS structure
782  * continue_walk(in):
783  */
784 static PT_NODE *
785 pt_find_lck_classes (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
786 {
787  PT_CLASS_LOCKS *lcks = (PT_CLASS_LOCKS *) arg;
788 
789  lcks->lock_type = DB_FETCH_READ;
790 
791  /* Temporary disable count optimization. To enable it just restore the condition and also remove deactivation in
792  * qexec_evaluate_aggregates_optimize */
793  if (false /* node->node_type == PT_SELECT */ )
794  {
795  /* count optimization */
796  PT_NODE *list = node->info.query.q.select.list;
797  PT_NODE *from = node->info.query.q.select.from;
798 
799  /* Check if query is of form 'SELECT count(*) from t' */
800  if (list != NULL && list->next == NULL && list->node_type == PT_FUNCTION
801  && list->info.function.function_type == PT_COUNT_STAR && from != NULL && from->next == NULL
802  && from->info.spec.entity_name != NULL && from->info.spec.entity_name->node_type == PT_NAME
803  && node->info.query.q.select.where == NULL)
804  {
805  /* only add to the array, if not there already in this lock mode. */
807  {
808  if (pt_add_lock_class (parser, lcks, from, LC_PREF_FLAG_COUNT_OPTIM) != NO_ERROR)
809  {
810  *continue_walk = PT_STOP_WALK;
811  return node;
812  }
813  }
814  }
815  }
816 
817  /* if its not an entity, there's nothing left to do */
818  if (node->node_type != PT_SPEC)
819  {
820  /* if its not an entity, there's nothing left to do */
821  return node;
822  }
823 
824  /* check if this is a parenthesized entity list */
825  if (!node->info.spec.entity_name || (node->info.spec.entity_name->node_type != PT_NAME))
826  {
827  return node;
828  }
829 
830  if (node->info.spec.partition != NULL)
831  {
832  /* add specified lock on specified partition */
833  node = pt_find_lck_class_from_partition (parser, node, lcks);
834  if (node == NULL)
835  {
836  *continue_walk = PT_STOP_WALK;
837  return NULL;
838  }
839  }
840  /* only add to the array, if not there already in this lock mode. */
842  {
843  if (pt_add_lock_class (parser, lcks, node, LC_PREF_FLAG_LOCK) != NO_ERROR)
844  {
845  *continue_walk = PT_STOP_WALK;
846  return node;
847  }
848  }
849 
850  return node;
851 }
852 
853 /*
854  * pt_find_lck_class_from_partition - add pre-fetch locks for specified
855  * partition
856  * return: spec
857  * parser (in) : parser context
858  * node (in) : partition spec
859  * locks (in) : locks array
860  */
861 static PT_NODE *
863 {
864  int error = NO_ERROR;
865  const char *entity_name = NULL;
866  const char *partition_name = NULL;
867 
868  if (node == NULL || node->info.spec.partition == NULL)
869  {
870  return node;
871  }
872 
873  entity_name = node->info.spec.entity_name->info.name.original;
874  partition_name = pt_partition_name (parser, entity_name, node->info.spec.partition->info.name.original);
875  if (partition_name == NULL)
876  {
877  if (!pt_has_error (parser))
878  {
879  PT_INTERNAL_ERROR (parser, "allocate memory");
880  return NULL;
881  }
882  }
883 
884  if (!pt_in_lck_array (locks, partition_name, LC_PREF_FLAG_LOCK))
885  {
886  /* Set lock on specified partition. Only add to the array if not there already in this lock mode. */
887  node->info.spec.entity_name->info.name.original = partition_name;
888  error = pt_add_lock_class (parser, locks, node, LC_PREF_FLAG_LOCK);
889 
890  /* restore spec name */
891  node->info.spec.entity_name->info.name.original = entity_name;
892  if (error != NO_ERROR)
893  {
894  return NULL;
895  }
896  }
897 
898  return node;
899 }
900 
901 /*
902  * pt_in_lck_array () -
903  * return: true if string found in array with given lockmode, false otherwise
904  * lcks(in):
905  * str(in):
906  */
907 static int
908 pt_in_lck_array (PT_CLASS_LOCKS * lcks, const char *str, LC_PREFETCH_FLAGS flags)
909 {
910  int i, no_lock_idx = -1;
911  LOCK chk_lock;
912 
914  for (i = 0; i < lcks->num_classes; i++)
915  {
916  if (intl_identifier_casecmp (str, lcks->classes[i]) == 0)
917  {
918  if (flags & LC_PREF_FLAG_LOCK)
919  {
920  if (lcks->flags[i] & LC_PREF_FLAG_LOCK)
921  {
922  if (lcks->locks[i] == chk_lock)
923  {
924  return true;
925  }
926  }
927  else
928  {
929  no_lock_idx = i;
930  }
931  }
932  else if (flags & LC_PREF_FLAG_COUNT_OPTIM)
933  {
934  lcks->flags[i] = (LC_PREFETCH_FLAGS) (lcks->flags[i] | LC_PREF_FLAG_COUNT_OPTIM);
935  return true;
936  }
937  }
938  }
939  if (no_lock_idx >= 0)
940  {
941  lcks->locks[no_lock_idx] = chk_lock;
942  lcks->flags[no_lock_idx] = (LC_PREFETCH_FLAGS) (lcks->flags[no_lock_idx] | LC_PREF_FLAG_LOCK);
943  return true;
944  }
945 
946  return false; /* not found */
947 }
948 
949 /*
950  * remove_appended_trigger_info () - remove appended trigger info
951  * msg(in/out):
952  * with_evaluate(in):
953  */
954 static void
955 remove_appended_trigger_info (char *msg, int with_evaluate)
956 {
957  size_t i;
958  const char *scope_str = "SCOPE___ ";
959  const char *from_on_str = " FROM ON ";
960  const char *eval_prefix = "EVALUATE ( ";
961  const char *eval_suffix = " ) ";
962  const char single_quote_char = '\'';
963  const char semicolon = ';';
964  char *p = NULL;
965 
966  if (msg == NULL)
967  {
968  return;
969  }
970 
971  if (with_evaluate)
972  {
973  p = strstr (msg, eval_prefix);
974  if (p != NULL)
975  {
976  p = (char *) memmove (p, p + strlen (eval_prefix), strlen (p) - strlen (eval_prefix) + 1);
977  }
978 
979  p = strstr (msg, eval_suffix);
980  if (p != NULL)
981  {
982  p = (char *) memmove (p, p + strlen (eval_suffix), strlen (p) - strlen (eval_suffix) + 1);
983  }
984  }
985 
986  p = strstr (msg, scope_str);
987  if (p != NULL)
988  {
989  p = (char *) memmove (p, p + strlen (scope_str), strlen (p) - strlen (scope_str) + 1);
990  }
991 
992  p = strstr (msg, from_on_str);
993  if (p != NULL)
994  {
995  for (i = 0; p[i] != single_quote_char && i < strlen (p); i++)
996  ;
997 
998  if (i > 0 && p[i - 1] == semicolon)
999  {
1000  p = (char *) memmove (p, p + i, strlen (p) - i + 1);
1001  }
1002  }
1003 }
1004 
1005 /*
1006  * pt_compile_trigger_stmt () - Compiles the trigger_stmt so that it can be
1007  * executed by pt_exec_trigger_stmt
1008  * return:
1009  * parser(in): the parser context
1010  * trigger_stmt(in): trigger_stmt to compile
1011  * class_op(in): class name to resolve name1 and name2 to
1012  * name1(in): name to resolve
1013  * name2(in): name to resolve
1014  *
1015  */
1016 
1017 PT_NODE *
1018 pt_compile_trigger_stmt (PARSER_CONTEXT * parser, const char *trigger_stmt, DB_OBJECT * class_op, const char *name1,
1019  const char *name2)
1020 {
1021  char *stmt_str = NULL;
1022  const char *class_name;
1023  PT_NODE **statement_p, *statement;
1024  int is_update_object;
1025  PT_NODE *err_node;
1026  int with_evaluate;
1027 
1028  assert (parser != NULL);
1029 
1030  if (!trigger_stmt)
1031  return NULL;
1032 
1033  /* is this an update object statement? if so it gets more complex */
1034  is_update_object = (intl_mbs_ncasecmp (trigger_stmt, "update object", strlen ("update object")) == 0);
1035 
1036  if (is_update_object)
1037  {
1038  if (class_op == NULL)
1039  {
1040  return NULL; /* deleted object */
1041  }
1042 
1043  /* The name that could be an argument to UPDATE OBJECT will always be the first name supplied here. Don't need to
1044  * initialize a label as we'll convert the PT_PARAMETER node into a PT_TRIGGER_OID later. */
1045  if (name1 != NULL)
1046  {
1047  name1 = name2;
1048  name2 = NULL;
1049  }
1050  }
1051 
1052  /* wrap a scope around the statement */
1053  stmt_str = pt_append_string (parser, stmt_str, "SCOPE___ ");
1054  stmt_str = pt_append_string (parser, stmt_str, trigger_stmt);
1055 
1056  class_name = NULL;
1057  if (class_op && name1 != NULL)
1058  {
1059  class_name = db_get_class_name (class_op);
1060  if (!class_name)
1061  {
1062  return (PT_NODE *) 0;
1063  }
1064 
1065  stmt_str = pt_append_string (parser, stmt_str, " FROM ON ");
1066  if (name1)
1067  {
1068  stmt_str = pt_append_string (parser, stmt_str, " [");
1069  stmt_str = pt_append_string (parser, stmt_str, class_name);
1070  stmt_str = pt_append_string (parser, stmt_str, "] ");
1071  stmt_str = pt_append_string (parser, stmt_str, name1);
1072  }
1073 
1074  if (name2)
1075  {
1076  if (!name1)
1077  {
1078  return (PT_NODE *) 0;
1079  }
1080  stmt_str = pt_append_string (parser, stmt_str, ", [");
1081  stmt_str = pt_append_string (parser, stmt_str, class_name);
1082  stmt_str = pt_append_string (parser, stmt_str, "] ");
1083  stmt_str = pt_append_string (parser, stmt_str, name2);
1084  }
1085  }
1086  stmt_str = pt_append_string (parser, stmt_str, ";");
1087 
1088  statement_p = parser_parse_string_use_sys_charset (parser, stmt_str);
1089  if (statement_p == NULL || *statement_p == NULL)
1090  return NULL;
1091  statement = *statement_p;
1092 
1093  /* If this is an update object statement, setup a spec to allow binding to the :obj parameter. This code was copied
1094  * from some other pt_ function, should consider making this a subroutine if it is generally useful. */
1095  if (is_update_object)
1096  {
1097  PT_NODE *upd, *entity, *entity_name;
1098 
1099  upd = statement->info.scope.stmt->info.trigger_action.expression;
1100  entity = parser_new_node (parser, PT_SPEC);
1101  entity->info.spec.id = (UINTPTR) entity;
1102  entity->line_number = upd->line_number;
1103  entity->column_number = upd->column_number;
1104  entity->info.spec.entity_name = parser_new_node (parser, PT_NAME);
1105  entity_name = entity->info.spec.entity_name;
1106  entity_name->info.name.spec_id = entity->info.spec.id;
1107  entity_name->info.name.meta_class = PT_CLASS;
1108  entity_name->info.name.original = (const char *) db_get_class_name (class_op);
1109 
1110  entity->info.spec.only_all = PT_ONLY;
1111  entity->info.spec.range_var = parser_copy_tree (parser, entity_name);
1112  if (entity->info.spec.range_var == NULL)
1113  {
1114  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
1115  return NULL;
1116  }
1117 
1118  entity->info.spec.range_var->info.name.resolved = NULL;
1119  upd->info.update.spec = entity;
1120  }
1121 
1122  statement = pt_compile (parser, statement);
1123 
1124  /* Remove those info we append, which users can't understand them */
1125  if (pt_has_error (parser))
1126  {
1127  err_node = pt_get_errors (parser);
1128  with_evaluate = strstr (trigger_stmt, "EVALUATE ( ") != NULL ? true : false;
1129  while (err_node)
1130  {
1131  remove_appended_trigger_info (err_node->info.error_msg.error_message, with_evaluate);
1132  err_node = err_node->next;
1133  }
1134  }
1135 
1136  /* We need to do view translation here on the expression to be executed. */
1137  if (statement)
1138  {
1140  mq_translate (parser, statement->info.scope.stmt->info.trigger_action.expression);
1141  /*
1142  * Trigger statement node must use the datetime information of the
1143  * node corresponding the action to be made.
1144  */
1145  if (statement->info.scope.stmt && statement->info.scope.stmt->info.trigger_action.expression)
1146  {
1148  }
1149  }
1150 
1151  /* split the delete statement */
1152  if (statement != NULL && statement->info.scope.stmt->info.trigger_action.expression != NULL
1154  {
1156  {
1157  return NULL;
1158  }
1159  }
1160 
1161  return statement;
1162 }
1163 
1164 
1165 /*
1166  * pt_set_trigger_obj_pre () - sets pt_trigger_exec_info's object1 and object2
1167  * return:
1168  * parser(in): the parser context
1169  * node(in): trigger_stmt statement node
1170  * arg(in): a struct pt_trigger_exec_info
1171  * walk_on(in/out): flag that tells when to stop traversal
1172  *
1173  * Note :
1174  * Handling UPDATE OBJECT statements is a bit different from regular
1175  * update statements. The "obj" argument for the update will actually
1176  * start in the parse tree with metaclass PT_PARAMETER and the spec_id
1177  * will be zero the first time we walk over the tree. This gets changed
1178  * to a PT_TRIGGER_OID so at exec time we don't have to deal with setting
1179  * a value for this label.
1180  *
1181  * In the usual case, we just look for PT_NAME nodes with spec_id's that
1182  * match the spec_id's given to the correlation names in the outer scope.
1183  */
1184 static PT_NODE *
1185 pt_set_trigger_obj_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
1186 {
1187  TRIGGER_EXEC_INFO *exec_info = (TRIGGER_EXEC_INFO *) arg;
1188 
1189 
1190  if (exec_info->is_update_object)
1191  {
1192  /* Its an "update object" statement, the object target will initially be a PT_PARAMETER meta_class node. When we
1193  * find one of these, convert it to be a normal PT_TRIGGER_OID node so we avoid ambiguities in name resolution
1194  * and don't have to actually set a :obj label for run time evaluation. Note that since the meta_class of the
1195  * node changes after the first time through here, the following clause has to be smart about recognzing this in
1196  * the future with a spec_id of zero. */
1197  switch (node->node_type)
1198  {
1199  case PT_SELECT:
1200  node->info.query.xasl = (void *) 0;
1201  break;
1202 
1203  case PT_UPDATE:
1204  /* this is the root of the update statement, the "object" field must be set to a non-NULL value in order for
1205  * do_update() to believe that this is an update object statement. Given that, I'm not sure if it is
1206  * necessary to be setting the parameter value in the object_parameter field as well but it doesn't seem to
1207  * hurt. */
1208  node->info.update.object = exec_info->object1;
1209  break;
1210 
1211  case PT_NAME:
1212  if (node->info.name.meta_class == PT_PARAMETER)
1213  {
1214  /* it could be our :obj or :new parameter, ignore spec_id, it could * be zero or could be resolved
1215  * depending on where we are. this shouldn't matter, the symbolic names tell us what this is. */
1216  if ((exec_info->name1 != NULL && strcmp (node->info.name.original, exec_info->name1) == 0)
1217  || (exec_info->name2 != NULL && strcmp (node->info.name.original, exec_info->name2) == 0))
1218  {
1219  /* its a parameter reference to one of our magic names */
1220  node->info.name.db_object = exec_info->object1;
1222  if (exec_info->path_expr_level)
1223  {
1224  exec_info->trig_corr_path = true;
1225  }
1226  }
1227  }
1228  else
1229  {
1230  /* its some other non-paremter name node */
1231  if (exec_info->spec_id1 && node->info.name.spec_id == exec_info->spec_id1)
1232  {
1233  node->info.name.db_object = exec_info->object1;
1235  if (exec_info->path_expr_level)
1236  {
1237  exec_info->trig_corr_path = true;
1238  }
1239  }
1240  else if (exec_info->spec_id2 && node->info.name.spec_id == exec_info->spec_id2)
1241  {
1242  node->info.name.db_object = exec_info->object2;
1244  if (exec_info->path_expr_level)
1245  {
1246  exec_info->trig_corr_path = true;
1247  }
1248  }
1249  else if (node->info.name.spec_id == 0 && node->info.name.meta_class == PT_TRIGGER_OID)
1250  {
1251  /* this was our former PT_PARAMETER node that we hacked into a PT_TRIGGER_OID above. */
1252  node->info.name.db_object = exec_info->object1;
1253  if (exec_info->path_expr_level)
1254  {
1255  exec_info->trig_corr_path = true;
1256  }
1257  }
1258  }
1259  break;
1260 
1261  case PT_DOT_:
1262  exec_info->path_expr_level++;
1263  break;
1264 
1265  default:
1266  break;
1267  }
1268  }
1269  else
1270  {
1271  /* its a "normal" update/insert/delete statement surrounded by a SCOPE___ block with one or more correlation
1272  * names. */
1273  switch (node->node_type)
1274  {
1275  case PT_SELECT:
1276  node->info.query.xasl = (void *) 0;
1277  break;
1278 
1279  case PT_NAME:
1280  if (exec_info->spec_id1 && node->info.name.spec_id == exec_info->spec_id1)
1281  {
1282  node->info.name.db_object = exec_info->object1;
1284  if (exec_info->path_expr_level)
1285  {
1286  exec_info->trig_corr_path = true;
1287  }
1288  }
1289  else if (exec_info->spec_id2 && node->info.name.spec_id == exec_info->spec_id2)
1290  {
1291  node->info.name.db_object = exec_info->object2;
1293  if (exec_info->path_expr_level)
1294  {
1295  exec_info->trig_corr_path = true;
1296  }
1297  }
1298  break;
1299 
1300  case PT_DOT_:
1301  exec_info->path_expr_level++;
1302  break;
1303 
1304  default:
1305  break;
1306  }
1307  }
1308 
1309  return node;
1310 }
1311 
1312 /*
1313  * pt_set_trigger_obj_post () -
1314  * return:
1315  * parser(in):
1316  * node(in):
1317  * arg(in):
1318  * walk_on(in):
1319  */
1320 static PT_NODE *
1321 pt_set_trigger_obj_post (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
1322 {
1323  PT_NODE *temp, *next;
1324  TRIGGER_EXEC_INFO *exec_info = (TRIGGER_EXEC_INFO *) arg;
1325 
1326  if (node->node_type != PT_DOT_)
1327  {
1328  return node;
1329  }
1330 
1331  exec_info->path_expr_level--;
1332  if (!exec_info->path_expr_level && exec_info->trig_corr_path)
1333  {
1334  /* This is a path expression rooted in a trigger correlation variable We need to replace this path expression by
1335  * evaluating it */
1336  exec_info->trig_corr_path = false;
1337 
1338  /* save the next pointer or it will be lost */
1339  next = node->next;
1340  node->next = NULL;
1341  temp = pt_eval_value_path (parser, node);
1342  parser_free_tree (parser, node);
1343  node = temp;
1344 
1345  /* pt_eval_value_path can return NULL, so be careful. */
1346  if (node)
1347  {
1348  node->next = next;
1349  }
1350  }
1351 
1352  return node;
1353 }
1354 
1355 
1356 /*
1357  * pt_exec_trigger_stmt () - Executes the trigger_stmt after setting object1
1358  * and object2.
1359  * return: NO_ERROR on success, non-zero for ERROR
1360  * parser(in): the parser context
1361  * trigger_stmt(in): trigger_stmt to exec
1362  * object1(in): object to associate with compiled name1
1363  * object2(in): object to associate with compiled name2
1364  * result(out): result of the trigger_stmt
1365  *
1366  * Note :
1367  * Special handling for the "update object" statement has made this rather
1368  * complex. It would be worth considering changing the way. we parse update
1369  * object statements so that the target can be an correlation name
1370  * as well as a parameter.
1371  */
1372 int
1374  DB_VALUE * result)
1375 {
1376  int error = NO_ERROR;
1377  PT_NODE *node;
1378  PT_NODE *tmp_trigger = NULL;
1379  TRIGGER_EXEC_INFO exec_info;
1380  DB_VALUE **src;
1381  int unhide1, unhide2;
1382  int server_info_bits;
1383 
1384  assert (parser != NULL && trigger_stmt != NULL && trigger_stmt->node_type == PT_SCOPE);
1385 
1386  server_info_bits = 0; /* init */
1387 
1388  /* set sys_date, sys_time, sys_timestamp, sys_datetime values for trigger statement. */
1389  if (trigger_stmt->flag.si_datetime)
1390  {
1391  server_info_bits |= SI_SYS_DATETIME;
1392  }
1393 
1394  if (trigger_stmt->flag.si_tran_id)
1395  {
1396  server_info_bits |= SI_LOCAL_TRANSACTION_ID;
1397  }
1398 
1399  /* request to the server */
1400  if (server_info_bits)
1401  {
1402  error = qp_get_server_info (parser, server_info_bits);
1403  if (error != NO_ERROR)
1404  {
1405  return error;
1406  }
1407  }
1408 
1409  /* initialize our parser_walk_tree state */
1410  (void) memset (&exec_info, 0, sizeof (exec_info));
1411  exec_info.object1 = object1;
1412  exec_info.object2 = object2;
1413 
1414  if (trigger_stmt->info.scope.stmt != NULL && trigger_stmt->info.scope.stmt->node_type == PT_TRIGGER_ACTION)
1415  {
1416  node = trigger_stmt->info.scope.stmt->info.trigger_action.expression;
1417  if (node != NULL && node->node_type == PT_UPDATE && node->info.update.object_parameter != NULL)
1418  {
1419  PT_NODE *temp;
1420 
1421  exec_info.is_update_object = true;
1422 
1423  /* make sure the spec we created up in pt_compile_trigger_stmt gets updated to have the actual class of this
1424  * instance, not sure that's really necessary. */
1425  temp = node->info.update.spec->info.spec.flat_entity_list;
1426  temp->info.name.db_object = db_get_class (object1);
1427 
1428  /* first object will be the parameter */
1429  temp = node->info.update.object_parameter;
1430  exec_info.spec_id1 = 0; /* nothing yet */
1431  exec_info.name1 = temp->info.name.original;
1432 
1433  /* second object will be in the scope */
1434  node = trigger_stmt->info.scope.from;
1435  if (node != NULL && node->info.spec.entity_name != NULL)
1436  {
1437  exec_info.spec_id2 = node->info.spec.entity_name->info.name.spec_id;
1438  exec_info.name2 = node->info.spec.range_var->info.name.original;
1439  }
1440  }
1441  else
1442  {
1443  node = trigger_stmt->info.scope.from;
1444  /* both names will be in the scope */
1445  /* first name, "obj" or "new" */
1446  if (node != NULL && node->info.spec.entity_name != NULL)
1447  {
1448  exec_info.spec_id1 = node->info.spec.entity_name->info.name.spec_id;
1449  exec_info.name1 = node->info.spec.range_var->info.name.original;
1450  }
1451 
1452  /* second name, "obj" or "old" */
1453  if (node != NULL && (node = node->next) != NULL && node->info.spec.entity_name != NULL)
1454  {
1455  exec_info.spec_id2 = node->info.spec.entity_name->info.name.spec_id;
1456  exec_info.name2 = node->info.spec.range_var->info.name.original;
1457  }
1458  }
1459  }
1460 
1461  /* We need to copy the trigger statement because pt_set_trigger_obj_post() may change the statement by evaluating
1462  * path expressions rooted by trigger correlation variable names. */
1463  tmp_trigger = parser_copy_tree (parser, trigger_stmt);
1464  if (tmp_trigger == NULL)
1465  {
1466  assert (er_errid () != NO_ERROR);
1467  return er_errid ();
1468  }
1469  /* Due to tree copy, the spec ids are broken. Reset spec ids */
1470  tmp_trigger = mq_reset_ids_in_statement (parser, tmp_trigger);
1471  if (tmp_trigger == NULL)
1472  {
1473  assert (er_errid () != NO_ERROR);
1474  return er_errid ();
1475  }
1476 
1477  (void) parser_walk_tree (parser, tmp_trigger->info.scope.stmt, pt_set_trigger_obj_pre, (void *) &exec_info,
1478  pt_set_trigger_obj_post, (void *) &exec_info);
1479 
1480  unhide1 = ws_hide_new_old_trigger_obj (object1);
1481  unhide2 = ws_hide_new_old_trigger_obj (object2);
1482 
1483  error = do_scope (parser, tmp_trigger);
1484  if (unhide1)
1485  {
1487  }
1488  if (unhide2)
1489  {
1491  }
1492 
1493  /* Rather than cloning, simply transfer the contents of the DB_VALUE in the "etc" field to the user supplied
1494  * container. Be sure to free the "etc" value when we're done, otherwise it becomes dangling the next time we
1495  * evaluate this trigger expresssion. */
1496  src = NULL;
1497  if (tmp_trigger->info.scope.stmt->node_type == PT_TRIGGER_ACTION)
1498  {
1499  src = (DB_VALUE **) (&tmp_trigger->info.scope.stmt->info.trigger_action.expression->etc);
1500  }
1501  else if (tmp_trigger->info.scope.stmt->node_type == PT_EVALUATE)
1502  {
1503  src = (DB_VALUE **) (&tmp_trigger->info.scope.stmt->etc);
1504  }
1505 
1506  if (src == NULL || *src == NULL)
1507  {
1508  db_make_null (result);
1509  }
1510  else
1511  {
1512  /* transfer the contents without cloning since we're going to free the source container */
1513  *result = **src;
1514 
1515  /* free this so it doesn't become garbage the next time */
1516  db_make_null (*src);
1517  db_value_free (*src);
1518  }
1519 
1520  /* reset the parser values */
1521  if (trigger_stmt->flag.si_datetime)
1522  {
1523  db_make_null (&parser->sys_datetime);
1524  db_make_null (&parser->sys_epochtime);
1525  }
1526  if (trigger_stmt->flag.si_tran_id)
1527  {
1529  }
1530 
1531  parser_free_tree (parser, tmp_trigger);
1532 
1533  return error;
1534 }
1535 
1536 /*
1537  * pt_name_occurs_in_from_list() - counts the number of times a name
1538  * appears as an exposed name in a list of entity_spec's
1539  * return:
1540  * parser(in):
1541  * name(in):
1542  * from_list(in):
1543  */
1544 int
1545 pt_name_occurs_in_from_list (PARSER_CONTEXT * parser, const char *name, PT_NODE * from_list)
1546 {
1547  PT_NODE *spec;
1548  int i = 0;
1549 
1550  if (!name || !from_list)
1551  {
1552  return i;
1553  }
1554 
1555  for (spec = from_list; spec != NULL; spec = spec->next)
1556  {
1557  if (spec->info.spec.range_var && spec->info.spec.range_var->info.name.original
1558  && (intl_identifier_casecmp (name, spec->info.spec.range_var->info.name.original) == 0))
1559  {
1560  i++;
1561  }
1562  }
1563 
1564  return i;
1565 }
PT_NODE * pt_name(PARSER_CONTEXT *parser_ptr, const char *name)
PT_NODE * order_by
Definition: parse_tree.h:2769
#define ER_LK_UNILATERALLY_ABORTED
Definition: error_code.h:130
PT_NODE * pt_compile(PARSER_CONTEXT *parser, PT_NODE *volatile statement)
Definition: compile.c:380
PT_NODE * next
Definition: parse_tree.h:3447
PT_NAME_INFO name
Definition: parse_tree.h:3318
void parser_free_lcks_classes(PARSER_CONTEXT *parser)
Definition: parse_tree.c:1310
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: parse_tree.h:2829
PT_NODE * arg_list
Definition: parse_tree.h:2258
PT_NODE * pt_get_errors(PARSER_CONTEXT *parser)
#define NO_ERROR
Definition: error_code.h:46
PT_UNION_INFO union_
Definition: parse_tree.h:2782
PT_UPDATE_INFO update
Definition: parse_tree.h:3353
int do_scope(PARSER_CONTEXT *parser, PT_NODE *statement)
UINTPTR id
Definition: parse_tree.h:2144
PT_NODE ** parser_parse_string_use_sys_charset(PARSER_CONTEXT *parser, const char *buffer)
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
DB_OBJECT * object
Definition: parse_tree.h:2864
const char * db_get_class_name(DB_OBJECT *class_)
Definition: db_info.c:608
UINTPTR spec_id2
Definition: compile.c:49
static int pt_add_lock_class(PARSER_CONTEXT *parser, PT_CLASS_LOCKS *lcks, PT_NODE *spec, LC_PREFETCH_FLAGS flags)
Definition: compile.c:687
PT_NODE * pt_class_pre_fetch(PARSER_CONTEXT *parser, PT_NODE *statement)
Definition: compile.c:431
PT_NODE * from
Definition: parse_tree.h:2678
LOCK * locks
Definition: compile.c:68
PT_NODE * mq_translate(PARSER_CONTEXT *parser, PT_NODE *volatile node)
#define ER_FAILED
Definition: error_code.h:47
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
PT_SPEC_INFO spec
Definition: parse_tree.h:3346
PT_NODE * pt_get_select_list(PARSER_CONTEXT *parser, PT_NODE *query)
Definition: query_result.c:404
PT_NODE * arg2
Definition: parse_tree.h:2664
int tran_lock_rep_read(LOCK lock_rr_tran)
DB_FETCH_MODE lock_type
Definition: compile.c:65
PT_NODE * spec
Definition: parse_tree.h:2859
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2552
int path_expr_level
Definition: compile.c:54
int locator_get_cache_coherency_number(MOP mop)
Definition: locator_cl.c:2171
PT_NODE * partition
Definition: parse_tree.h:2142
union pt_query_info::@124 q
void sm_downcase_name(const char *name, char *buf, int maxlen)
PT_SCOPE_INFO scope
Definition: parse_tree.h:3333
enum lc_prefetch_flags LC_PREFETCH_FLAGS
Definition: locator.h:339
int er_errid(void)
#define PT_SET_JMP_ENV(parser)
Definition: parse_tree.h:89
int pt_split_delete_stmt(PARSER_CONTEXT *parser, PT_NODE *delete_stmt)
PT_NODE * pt_add_row_oid_name(PARSER_CONTEXT *parser, PT_NODE *statement)
Definition: compile.c:347
DB_OBJECT * virt_object
Definition: parse_tree.h:2548
bool is_update_object
Definition: compile.c:56
PT_NODE * data_type
Definition: parse_tree.h:3453
PT_NODE * pt_eval_value_path(PARSER_CONTEXT *parser, PT_NODE *path)
static PT_NODE * pt_add_oid_to_select_list(PARSER_CONTEXT *parser, PT_NODE *statement, VIEW_HANDLING how)
Definition: compile.c:242
static PT_NODE * pt_count_entities(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: compile.c:661
LOCK locator_fetch_mode_to_lock(DB_FETCH_MODE purpose, LC_OBJTYPE type, LC_FETCH_VERSION_TYPE fetch_version_type)
Definition: locator_cl.c:2068
int qp_get_server_info(PARSER_CONTEXT *parser, int server_info_bits)
static DB_OBJECT * is_class(OID *obj_oid, OID *class_oid)
Definition: compactdb.c:637
FUNC_TYPE function_type
Definition: parse_tree.h:2259
PT_TYPE_ENUM type_enum
Definition: parse_tree.h:3457
LOCK
char oids_included
Definition: parse_tree.h:2750
DB_DATA data
Definition: dbtype_def.h:1083
PT_NODE * pt_semantic_check(PARSER_CONTEXT *parser, PT_NODE *node)
union pt_alter_info::@111 alter_clause
PT_NODE * arg1
Definition: parse_tree.h:2663
PT_ALTER_INFO alter
Definition: parse_tree.h:3268
PT_FUNCTION_INFO function
Definition: parse_tree.h:3301
short constrain_not_null
Definition: parse_tree.h:1866
DB_OBJECT * db_object
Definition: parse_tree.h:2546
#define MSGCAT_RUNTIME_OUT_OF_MEMORY
#define TM_TRAN_REP_READ_LOCK()
#define assert(x)
struct pt_alter_info::@111::@113 attr_mthd
#define PT_IS_QUERY_NODE_TYPE(x)
Definition: parse_tree.h:115
PT_TYPE_ENUM virt_type_enum
Definition: parse_tree.h:2042
DB_VALUE db_value
Definition: parse_tree.h:3059
PT_NODE * entity
Definition: parse_tree.h:2038
#define MSGCAT_SET_PARSER_RUNTIME
static PT_NODE * pt_find_lck_class_from_partition(PARSER_CONTEXT *parser, PT_NODE *node, PT_CLASS_LOCKS *locks)
Definition: compile.c:862
PT_DATA_VALUE data_value
Definition: parse_tree.h:3058
DB_OBJECT * object2
Definition: compile.c:51
PT_NODE * flat_entity_list
Definition: parse_tree.h:2140
const char * name2
Definition: compile.c:53
const char * original
Definition: parse_tree.h:2544
int intl_identifier_casecmp(const char *str1, const char *str2)
int db_value_free(DB_VALUE *value)
Definition: db_macro.c:1610
DB_VALUE local_transaction_id
Definition: parse_tree.h:3583
int pt_name_occurs_in_from_list(PARSER_CONTEXT *parser, const char *name, PT_NODE *from_list)
Definition: compile.c:1545
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
int locator_flush_class(MOP class_mop)
Definition: locator_cl.c:5068
const char * db_error_string(int level)
Definition: db_admin.c:2116
PT_NODE * parser_copy_tree(PARSER_CONTEXT *parser, const PT_NODE *tree)
#define PT_IS_VALUE_QUERY(n)
Definition: parse_tree.h:476
DB_VALUE sys_epochtime
Definition: parse_tree.h:3581
PT_NODE * from
Definition: parse_tree.h:2686
UINTPTR spec_id
Definition: parse_tree.h:2543
PT_DATA_TYPE_INFO data_type
Definition: parse_tree.h:3284
static void cleanup(int signo)
Definition: broker.c:717
PT_NODE * pt_spec_to_oid_attr(PARSER_CONTEXT *parser, PT_NODE *spec, VIEW_HANDLING how)
Definition: compile.c:101
SP_PARSER_CTX * parser
bool mq_is_updatable(DB_OBJECT *class_object)
PT_ATTR_DEF_INFO attr_def
Definition: parse_tree.h:3272
int * only_all
Definition: compile.c:67
#define NULL
Definition: freelistheap.h:34
PT_ALTER_CODE code
Definition: parse_tree.h:1751
PT_NODE * as_attr_list
Definition: parse_tree.h:2136
char ** classes
Definition: compile.c:66
PT_NODE * pt_add_row_classoid_name(PARSER_CONTEXT *parser, PT_NODE *statement, int server_op)
Definition: compile.c:361
pt_order_by_adjustment
Definition: compile.c:72
static PT_NODE * pt_set_trigger_obj_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: compile.c:1185
const char * er_msg(void)
int db_is_class(MOP obj)
Definition: db_info.c:310
DB_OBJECT * db_get_class(MOP obj)
Definition: db_info.c:589
DB_OBJECT * object1
Definition: compile.c:50
#define PT_SPEC_IS_DERIVED(spec_)
Definition: parse_tree.h:690
LC_FIND_CLASSNAME
char * pt_append_string(const PARSER_CONTEXT *parser, const char *old_string, const char *new_tail)
Definition: parse_tree.c:980
PT_CREATE_ENTITY_INFO create_entity
Definition: parse_tree.h:3279
#define PT_ERRORc(parser, node, msg)
Definition: parse_tree.h:55
PT_ZZ_ERROR_MSG_INFO error_msg
Definition: parse_tree.h:3267
PT_NODE * select_list
Definition: parse_tree.h:2665
PT_NODE * pt_add_row_oid(PARSER_CONTEXT *parser, PT_NODE *statement)
Definition: compile.c:333
PT_NODE * where
Definition: parse_tree.h:2687
PT_QUERY_INFO query
Definition: parse_tree.h:3325
const char * text
Definition: parse_tree.h:3056
unsigned si_datetime
Definition: parse_tree.h:3464
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
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
PT_SORT_SPEC_INFO sort_spec
Definition: parse_tree.h:3343
UINTPTR spec_id1
Definition: compile.c:48
const char * pt_partition_name(PARSER_CONTEXT *parser, const char *class_name, const char *partition)
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
PT_NODE * stmt
Definition: parse_tree.h:2679
LC_FIND_CLASSNAME locator_lockhint_classes(int num_classes, const char **many_classnames, LOCK *many_locks, int *need_subclasses, LC_PREFETCH_FLAGS *flags, int quit_on_errors, LOCK lock_rr_tran)
Definition: locator_cl.c:6260
PT_NODE * pt_resolve_cte_specs(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
DB_VALUE sys_datetime
Definition: parse_tree.h:3580
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
Definition: intl_support.c:43
unsigned si_tran_id
Definition: parse_tree.h:3465
int intl_mbs_ncasecmp(const char *mbs1, const char *mbs2, size_t n)
Definition: intl_support.c:441
PT_MISC_TYPE entity_type
Definition: parse_tree.h:1899
DB_OBJECT * virt_object
Definition: parse_tree.h:2040
static PT_NODE * pt_find_lck_classes(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: compile.c:785
PT_MISC_TYPE only_all
Definition: parse_tree.h:2145
PT_TYPE_ENUM virt_type_enum
Definition: parse_tree.h:2551
const char * name1
Definition: compile.c:52
PT_NODE * mq_oid(PARSER_CONTEXT *parser, PT_NODE *spec)
#define ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED
Definition: error_code.h:171
void * etc
Definition: parse_tree.h:3450
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
int db_make_null(DB_VALUE *value)
PT_NODE * list
Definition: parse_tree.h:2685
void ws_unhide_new_old_trigger_obj(MOP op)
Definition: work_space.c:3800
int ws_hide_new_old_trigger_obj(MOP op)
Definition: work_space.c:3765
LC_PREFETCH_FLAGS * flags
Definition: compile.c:69
static PT_NODE * pt_set_trigger_obj_post(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: compile.c:1321
DB_FETCH_MODE
Definition: dbtype_def.h:215
int trig_corr_path
Definition: compile.c:55
#define PT_INTERNAL_ERROR(parser, what)
Definition: parse_tree.h:112
#define pt_has_error(parser)
Definition: parser.h:507
const char * resolved
Definition: parse_tree.h:2545
static void remove_appended_trigger_info(char *msg, int with_evaluate)
Definition: compile.c:955
#define PT_CLEAR_JMP_ENV(parser)
Definition: parse_tree.h:107
enum view_handling VIEW_HANDLING
PT_NODE * mq_reset_ids_in_statement(PARSER_CONTEXT *parser, PT_NODE *statement)
int num_classes
Definition: compile.c:63
PT_TRIGGER_ACTION_INFO trigger_action
Definition: parse_tree.h:3349
int column_number
Definition: parse_tree.h:3442
struct parser_node::@132 flag
PT_NODE * entity_name
Definition: parse_tree.h:2130
PT_NODE * object_parameter
Definition: parse_tree.h:2865
PT_SELECT_INFO select
Definition: parse_tree.h:2781
char ** lcks_classes
Definition: parse_tree.h:3573
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)
int allocated_count
Definition: compile.c:64
PT_NODE * parser_copy_tree_list(PARSER_CONTEXT *parser, PT_NODE *tree)
const char ** p
Definition: dynamic_load.c:945
static int pt_in_lck_array(PT_CLASS_LOCKS *lcks, const char *str, LC_PREFETCH_FLAGS flags)
Definition: compile.c:908
#define PT_ERRORmf(parser, node, setNo, msgNo, arg1)
Definition: parse_tree.h:64
#define TM_TRAN_ISOLATION()
static PT_NODE * pt_set_class_chn(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: compile.c:614
PT_NODE * range_var
Definition: parse_tree.h:2135