CUBRID Engine  latest
view_transform.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  * view_transform.c - Functions for the translation of virtual queries
21  */
22 
23 #ident "$Id$"
24 
25 #include <assert.h>
26 
27 #include "authenticate.h"
28 #include "view_transform.h"
29 #include "parser.h"
30 #include "parser_message.h"
31 #include "schema_manager.h"
32 #include "semantic_check.h"
33 #include "optimizer.h"
34 #include "execute_schema.h"
35 
36 #include "dbi.h"
37 #include "object_accessor.h"
38 #include "object_primitive.h"
39 #include "locator_cl.h"
40 #include "virtual_object.h"
41 #include "dbtype.h"
42 
43 #define MAX_STACK_OBJECTS 500
44 
45 #define PT_PUSHABLE_TERM(p) \
46  ((p)->out.pushable && (p)->out.correlated_found == false)
47 
48 #define MAX_CYCLE 300
49 
50 #define MQ_IS_OUTER_JOIN_SPEC(s) \
51  ( \
52  ((s)->info.spec.join_type == PT_JOIN_LEFT_OUTER \
53  || (s)->info.spec.join_type == PT_JOIN_RIGHT_OUTER) || \
54  ((s)->next && \
55  ((s)->next->info.spec.join_type == PT_JOIN_LEFT_OUTER \
56  || (s)->next->info.spec.join_type == PT_JOIN_RIGHT_OUTER)) \
57  )
58 
59 typedef enum
61 
62 typedef struct find_id_info
63 {
64  struct
65  { /* input section */
70  } in;
72  struct
73  { /* output section */
74  bool found;
77  bool pushable;
78  } out;
79 } FIND_ID_INFO;
80 
81 typedef struct mq_bump_core_info
82 {
84  int increment;
85 }
87 
88 typedef struct
89 {
90  UINTPTR old_id; /* spec id to replace in method name nodes */
91  UINTPTR new_id; /* spec it to replace it with */
93 
94 typedef struct check_pushable_info
95 {
100 
103  bool xxxnum_found; /* rownum, inst_num(), orderby_num(), groupby_num() */
106 
107 static unsigned int top_cycle = 0;
109 
110 
111 
114 {
117  UINTPTR spec_id;
118  PT_NODE *new_specs; /* for adding shared attr specs */
119 };
120 
121 typedef struct exists_info EXISTS_INFO;
123 {
126 };
127 
128 
131 {
132  UINTPTR id;
134 };
135 
138 {
140  UINTPTR spec_id;
141  PT_NODE *newspec; /* for new sharedd attr specs */
142 };
143 
146 {
150 };
151 
153 struct extra_specs_frame
154 {
155  struct extra_specs_frame *next;
157 };
158 
161 {
165 };
166 
169 {
171  UINTPTR id;
172 };
173 
174 
175 static PT_NODE *mq_bump_corr_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
176 static PT_NODE *mq_bump_corr_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
178 static DB_AUTH mq_compute_authorization (DB_OBJECT * class_object);
179 static DB_AUTH mq_compute_query_authorization (PT_NODE * statement);
180 static void mq_set_union_query (PARSER_CONTEXT * parser, PT_NODE * statement, PT_MISC_TYPE is_union);
181 static PT_NODE *mq_flatten_union (PARSER_CONTEXT * parser, PT_NODE * statement);
182 static PT_NODE *mq_rewrite_agg_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
183 static PT_NODE *mq_rewrite_agg_names_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
184 static bool mq_conditionally_add_objects (PARSER_CONTEXT * parser, PT_NODE * flat, DB_OBJECT *** classes, int *index,
185  int *max);
186 static PT_UPDATABILITY mq_updatable_local (PARSER_CONTEXT * parser, PT_NODE * statement, DB_OBJECT *** classes, int *i,
187  int *max);
188 static PT_NODE *mq_substitute_select_in_statement (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * query_spec,
189  PT_NODE * class_);
190 static PT_NODE *mq_substitute_spec_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg,
191  int *continue_walk);
193  PT_NODE * class_, PT_NODE * order_by, int what_for);
195  PT_NODE * query_spec_list, PT_NODE * class_,
196  PT_NODE * order_by, int what_for);
197 static int mq_translatable_class (PARSER_CONTEXT * parser, PT_NODE * class_);
199 static int mq_check_authorization_path_entities (PARSER_CONTEXT * parser, PT_NODE * class_spec, int what_for);
200 static int mq_check_subqueries_for_prepare (PARSER_CONTEXT * parser, PT_NODE * node, PT_NODE * subquery);
201 static PT_NODE *mq_translate_tree (PARSER_CONTEXT * parser, PT_NODE * tree, PT_NODE * spec_list, PT_NODE * order_by,
202  int what_for);
203 static PT_NODE *mq_class_meth_corr_subq_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg,
204  int *continue_walk);
206 static PT_NODE *pt_check_pushable (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
207 static bool pt_pushable_query_in_pos (PARSER_CONTEXT * parser, PT_NODE * query, int pos);
208 static PT_NODE *pt_find_only_name_id (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
209 static bool pt_sargable_term (PARSER_CONTEXT * parser, PT_NODE * term, FIND_ID_INFO * infop);
210 static bool mq_is_pushable_subquery (PARSER_CONTEXT * parser, PT_NODE * query, bool is_only_spec);
212 static void pt_copypush_terms (PARSER_CONTEXT * parser, PT_NODE * spec, PT_NODE * query, PT_NODE * term_list,
215  PT_NODE * new_query, FIND_ID_INFO * infop);
216 static int mq_copypush_sargable_terms (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec);
218  PT_NODE * query_spec);
219 static PT_NODE *mq_translate_select (PARSER_CONTEXT * parser, PT_NODE * select_statement);
220 static void mq_check_update (PARSER_CONTEXT * parser, PT_NODE * update_statement);
221 static void mq_check_delete (PARSER_CONTEXT * parser, PT_NODE * delete_stmt);
222 static PT_NODE *mq_translate_update (PARSER_CONTEXT * parser, PT_NODE * update_statement);
223 static PT_NODE *mq_resolve_insert_statement (PARSER_CONTEXT * parser, PT_NODE * insert_statement);
224 static PT_NODE *mq_translate_insert (PARSER_CONTEXT * parser, PT_NODE * insert_statement);
225 static PT_NODE *mq_translate_delete (PARSER_CONTEXT * parser, PT_NODE * delete_statement);
226 static void mq_check_merge (PARSER_CONTEXT * parser, PT_NODE * merge_statement);
227 static PT_NODE *mq_translate_merge (PARSER_CONTEXT * parser, PT_NODE * merge_statement);
228 static void mq_push_paths_select (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec);
229 static PT_NODE *mq_check_rewrite_select (PARSER_CONTEXT * parser, PT_NODE * select_statement);
230 static PT_NODE *mq_push_paths (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk);
231 static PT_NODE *mq_translate_local (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk);
232 static int mq_check_using_index (PARSER_CONTEXT * parser, PT_NODE * using_index);
233 #if defined(ENABLE_UNUSED_FUNCTION)
234 static PT_NODE *mq_collapse_dot (PARSER_CONTEXT * parser, PT_NODE * tree);
235 #endif /* ENABLE_UNUSED_FUNCTION */
236 static PT_NODE *mq_set_types (PARSER_CONTEXT * parser, PT_NODE * query_spec, PT_NODE * attributes,
237  DB_OBJECT * vclass_object, int cascaded_check);
238 static PT_NODE *mq_translate_subqueries (PARSER_CONTEXT * parser, DB_OBJECT * class_object, PT_NODE * attributes,
239  DB_AUTH * authorization);
240 static void mq_invert_assign (PARSER_CONTEXT * parser, PT_NODE * attr, PT_NODE * &expr, PT_NODE * inverted);
241 static void mq_invert_subqueries (PARSER_CONTEXT * parser, PT_NODE * select_statements, PT_NODE * attributes);
242 static void mq_set_non_updatable_oid (PARSER_CONTEXT * parser, PT_NODE * stmt, PT_NODE * virt_entity);
243 static bool mq_check_cycle (DB_OBJECT * class_object);
244 
245 static PT_NODE *mq_mark_location (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
247  int *continue_walk);
249 static PT_NODE *mq_rewrite_upd_del_top_level_specs (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg,
250  int *continue_walk);
252 
253 
255 
256 static PT_NODE *mq_coerce_resolved (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
257 static PT_NODE *mq_set_all_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
258 static PT_NODE *mq_reset_all_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
259 static PT_NODE *mq_clear_all_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
260 static PT_NODE *mq_clear_other_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
261 static PT_NODE *mq_reset_spec_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
262 static PT_NODE *mq_reset_spec_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg,
263  int *continue_walk);
264 static PT_NODE *mq_get_references_node (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
265 static PT_NODE *mq_referenced_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
266 static PT_NODE *mq_referenced_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
267 static int mq_is_referenced (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec);
269 static PT_NODE *mq_reset_select_spec_node (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
270 static PT_NODE *mq_reset_select_specs (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
271 static PT_NODE *mq_new_spec (PARSER_CONTEXT * parser, const char *class_name);
272 static PT_NODE *mq_replace_name_with_path (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
274 static PT_NODE *mq_substitute_path_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
275 static PT_NODE *mq_path_name_lambda (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * lambda_name,
276  PT_NODE * lambda_expr, UINTPTR spec_id);
278  int *continue_walk);
280  int *continue_walk);
281 static PT_NODE *mq_translate_paths (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * root_spec);
282 static void mq_invert_insert_select (PARSER_CONTEXT * parser, PT_NODE * attr, PT_NODE * subquery);
283 static void mq_invert_insert_subquery (PARSER_CONTEXT * parser, PT_NODE ** attr, PT_NODE * subquery);
284 static PT_NODE *mq_push_arg2 (PARSER_CONTEXT * parser, PT_NODE * query, PT_NODE * dot_arg2);
285 static PT_NODE *mq_lambda_node_pre (PARSER_CONTEXT * parser, PT_NODE * tree, void *void_arg, int *continue_walk);
286 static PT_NODE *mq_lambda_node (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
287 static PT_NODE *mq_set_virt_object (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
288 static PT_NODE *mq_fix_derived (PARSER_CONTEXT * parser, PT_NODE * select_statement, PT_NODE * spec);
290 static void mq_push_dot_in_query (PARSER_CONTEXT * parser, PT_NODE * query, int i, PT_NODE * name);
291 static PT_NODE *mq_clean_dot (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
293  DB_AUTH what_for, PARSER_CONTEXT ** qry_cache);
295  PT_FETCH_AS fetch_as, DB_AUTH what_for);
297  PT_NODE * attr, PT_NODE * real_class, PT_FETCH_AS fetch_as,
298  DB_AUTH what_for, UINTPTR * spec_id);
299 static PT_NODE *mq_set_names_dbobject (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
300 static bool mq_is_updatable_local (DB_OBJECT * class_object, PT_FETCH_AS fetch_as);
301 static PT_NODE *mq_fetch_one_real_class_get_cache (DB_OBJECT * vclass_object, PARSER_CONTEXT ** query_cache);
303 static PT_NODE *mq_path_spec_lambda (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * root_spec,
304  PT_NODE ** prev_ptr, PT_NODE * old_spec, PT_NODE * new_spec);
305 static PT_NODE *mq_generate_unique (PARSER_CONTEXT * parser, PT_NODE * name_list);
306 
308 
309 extern PT_NODE *mq_lambda (PARSER_CONTEXT * parser, PT_NODE * tree_with_names, PT_NODE * name_node,
310  PT_NODE * corresponding_tree);
311 
312 extern PT_NODE *mq_class_lambda (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * class_,
313  PT_NODE * corresponding_spec, PT_NODE * class_where_part, PT_NODE * class_check_part,
314  PT_NODE * class_group_by_part, PT_NODE * class_having_part);
315 
316 static PT_NODE *mq_fix_derived_in_union (PARSER_CONTEXT * parser, PT_NODE * statement, UINTPTR spec_id);
317 
319 
321  DB_AUTH what_for);
322 
323 static PT_NODE *mq_rename_resolved (PARSER_CONTEXT * parser, PT_NODE * spec, PT_NODE * statement, const char *newname);
324 
326 
328  bool get_spec_referenced_attr);
329 
330 static PT_NODE *mq_push_path (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec, PT_NODE * path);
331 
332 static PT_NODE *mq_derived_path (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * path);
333 #if defined(ENABLE_UNUSED_FUNCTION)
334 static int mq_mget_exprs (DB_OBJECT ** objects, int rows, char **exprs, int cols, int qOnErr, DB_VALUE * values,
335  int *results, char *emsg);
336 #endif /* ENABLE_UNUSED_FUNCTION */
337 
338 static void mq_insert_symbol (PARSER_CONTEXT * parser, PT_NODE ** listhead, PT_NODE * attr);
339 
340 static const char *get_authorization_name (DB_AUTH auth);
341 
342 static PT_NODE *mq_add_dummy_from_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
343 static PT_NODE *mq_update_order_by (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * query_spec,
344  PT_NODE * class_);
345 
346 static bool mq_is_order_dependent_node (PT_NODE * node);
347 
348 static bool mq_mark_order_dependent_nodes (PT_NODE * node);
349 
351  int *unique);
352 
353 static PT_NODE *mq_rewrite_order_dependent_query (PARSER_CONTEXT * parser, PT_NODE * select, int *unique);
354 
355 static PT_NODE *mq_bump_order_dep_corr_lvl_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
356 
358  int *continue_walk);
359 
361 
363  int *continue_walk);
364 
366 
367 static PT_NODE *pt_check_for_update_subquery (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
368 
369 static int pt_check_for_update_clause (PARSER_CONTEXT * parser, PT_NODE * query, bool root);
370 
372 
374 
376  int *continue_walk);
377 
378 static void mq_copy_view_error_msgs (PARSER_CONTEXT * parser, PARSER_CONTEXT * query_cache);
379 
380 /*
381  * mq_is_outer_join_spec () - determine if a spec is outer joined in a spec list
382  * returns: boolean
383  * parser(in): parser context
384  * spec(in): table spec to check
385  */
386 bool
388 {
389  if (spec == NULL)
390  {
391  /* should not be here */
392  PT_INTERNAL_ERROR (parser, "function called with wrong arguments");
393  return false;
394  }
395 
396  assert (spec->node_type == PT_SPEC);
397 
398  if (spec->info.spec.join_type == PT_JOIN_LEFT_OUTER)
399  {
400  /* directly on the right side of a left outer join */
401  return true;
402  }
403 
404  spec = spec->next;
405  while (spec)
406  {
407  switch (spec->info.spec.join_type)
408  {
409  case PT_JOIN_NONE:
410  case PT_JOIN_CROSS:
411  /* joins from this point forward do not matter */
412  return false;
413 
414  case PT_JOIN_RIGHT_OUTER:
415  /* right outer joined */
416  return true;
417 
418 #if 1 /* TODO - */
419  case PT_JOIN_NATURAL: /* not used */
420  case PT_JOIN_INNER:
421  case PT_JOIN_LEFT_OUTER:
422  case PT_JOIN_FULL_OUTER: /* not used */
423  case PT_JOIN_UNION: /* not used */
424  break;
425 #endif
426  }
427 
428  spec = spec->next;
429  }
430 
431  /* if we reached this point, it's not outer joined */
432  return false;
433 }
434 
435 
436 /*
437  * mq_bump_corr_pre() - Bump the correlation level of all matching
438  * correlated queries
439  * return:
440  * parser(in):
441  * node(in):
442  * void_arg(in):
443  * continue_walk(in):
444  */
445 static PT_NODE *
446 mq_bump_corr_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
447 {
448  MQ_BUMP_CORR_INFO *info = (MQ_BUMP_CORR_INFO *) void_arg;
449 
450  *continue_walk = PT_CONTINUE_WALK;
451 
452  if (!PT_IS_QUERY_NODE_TYPE (node->node_type))
453  return node;
454 
455  /* Can not increment threshold for list portion of walk. Since those queries are not sub-queries of this query.
456  * Consequently, we recurse separately for the list leading from a query. */
457  if (node->next)
458  {
459  node->next = mq_bump_correlation_level (parser, node->next, info->increment, info->match_level);
460  }
461 
462  *continue_walk = PT_LEAF_WALK;
463 
464  if (node->info.query.correlation_level != 0)
465  {
466  if (node->info.query.correlation_level >= info->match_level)
467  {
468  node->info.query.correlation_level += info->increment;
469  }
470  }
471  else
472  {
473  /* if the correlation level is 0, there cannot be correlated subqueries crossing this level */
474  *continue_walk = PT_STOP_WALK;
475  }
476 
477  /* increment threshold as we dive into selects and unions */
478  info->match_level++;
479 
480  return node;
481 
482 } /* mq_bump_corr_pre */
483 
484 
485 /*
486  * mq_bump_corr_post() - Unwind the info stack
487  * return:
488  * parser(in):
489  * node(in):
490  * void_arg(in):
491  * continue_walk(in):
492  */
493 static PT_NODE *
494 mq_bump_corr_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
495 {
496  MQ_BUMP_CORR_INFO *info = (MQ_BUMP_CORR_INFO *) void_arg;
497 
498  if (!PT_IS_QUERY_NODE_TYPE (node->node_type))
499  return node;
500 
501  info->match_level--;
502 
503  return node;
504 
505 } /* mq_bump_corr_post */
506 
507 
508 /*
509  * mq_bump_correlation_level() - Bump the correlation level of all matching
510  * correlated queries
511  * return:
512  * parser(in):
513  * node(in):
514  * increment(in):
515  * match(in):
516  */
517 PT_NODE *
518 mq_bump_correlation_level (PARSER_CONTEXT * parser, PT_NODE * node, int increment, int match)
519 {
520  MQ_BUMP_CORR_INFO info;
521  info.match_level = match;
522  info.increment = increment;
523 
524  return parser_walk_tree (parser, node, mq_bump_corr_pre, &info, mq_bump_corr_post, &info);
525 }
526 
527 /*
528  * mq_union_bump_correlation() - Union left and right sides,
529  * bumping correlation numbers
530  * return:
531  * parser(in):
532  * left(in):
533  * right(in):
534  */
535 static PT_NODE *
537 {
538  if (left->info.query.correlation_level)
539  left = mq_bump_correlation_level (parser, left, 1, left->info.query.correlation_level);
540 
541  if (right->info.query.correlation_level)
542  right = mq_bump_correlation_level (parser, right, 1, right->info.query.correlation_level);
543 
544  return pt_union (parser, left, right);
545 }
546 
547 /*
548  * mq_compute_authorization() -
549  * return: authorization in terms of the what_for mask
550  * class_object(in):
551  */
552 static DB_AUTH
554 {
555  DB_AUTH auth = (DB_AUTH) 0;
556 
557  if (db_check_authorization (class_object, DB_AUTH_SELECT) == NO_ERROR)
558  {
559  auth = (DB_AUTH) (auth + DB_AUTH_SELECT);
560  }
561  if (db_check_authorization (class_object, DB_AUTH_INSERT) == NO_ERROR)
562  {
563  auth = (DB_AUTH) (auth + DB_AUTH_INSERT);
564  }
565  if (db_check_authorization (class_object, DB_AUTH_UPDATE) == NO_ERROR)
566  {
567  auth = (DB_AUTH) (auth + DB_AUTH_UPDATE);
568  }
569  if (db_check_authorization (class_object, DB_AUTH_DELETE) == NO_ERROR)
570  {
571  auth = (DB_AUTH) (auth + DB_AUTH_DELETE);
572  }
573 
574  return auth;
575 }
576 
577 /*
578  * mq_compute_query_authorization() -
579  * return: authorization intersection of a query
580  * statement(in):
581  */
582 static DB_AUTH
584 {
585  PT_NODE *spec;
586  PT_NODE *flat;
587  DB_AUTH auth = (DB_AUTH) 0;
588 
589  switch (statement->node_type)
590  {
591  case PT_SELECT:
592  spec = statement->info.query.q.select.from;
593 
594  if (spec == NULL)
595  {
596  auth = DB_AUTH_SELECT;
597  }
598  else
599  {
600  auth = DB_AUTH_ALL;
601  /* select authorization is computed at semantic check */
602  /* its moot to compute other authorization on entire join, since its non-updateable */
603  for (flat = spec->info.spec.flat_entity_list; flat != NULL; flat = flat->next)
604  {
605  auth = (DB_AUTH) (auth & mq_compute_authorization (flat->info.name.db_object));
606  }
607  }
608  break;
609 
610  case PT_UNION:
612  auth = (DB_AUTH) (auth & mq_compute_query_authorization (statement->info.query.q.union_.arg2));
613  break;
614 
615  case PT_DIFFERENCE:
616  case PT_INTERSECTION:
617  /* select authorization is computed at semantic check */
618  /* again moot to compute other authorization, since this is not updatable. */
619  auth = DB_AUTH_SELECT;
620  break;
621 
622  default: /* should not get here, that is an error! */
623 #if defined(CUBRID_DEBUG)
624  fprintf (stdout, "Illegal parse node type %d, in %s, at line %d. \n", statement->node_type, __FILE__, __LINE__);
625 #endif /* CUBRID_DEBUG */
626  break;
627  }
628 
629  return auth;
630 }
631 
632 
633 /*
634  * mq_set_union_query() - Mark top level selects as PT_IS__UNION_QUERY
635  * return: B_AUTH authorization
636  * parser(in):
637  * statement(in):
638  * is_union(in):
639  */
640 static void
642 {
643  if (statement)
644  switch (statement->node_type)
645  {
646  case PT_SELECT:
647  statement->info.query.is_subquery = is_union;
648  break;
649 
650  case PT_UNION:
651  case PT_DIFFERENCE:
652  case PT_INTERSECTION:
653  statement->info.query.is_subquery = is_union;
654  mq_set_union_query (parser, statement->info.query.q.union_.arg1, is_union);
655  mq_set_union_query (parser, statement->info.query.q.union_.arg2, is_union);
656  break;
657 
658  default:
659  /* should not get here, that is an error! */
660  /* its almost certainly recoverable, so ignore it */
661  assert (0);
662  break;
663  }
664 }
665 
666 
667 /*
668  * mq_flatten_union() -
669  * return: returns an error if it fails.
670  * parser(in):
671  * statement(in):the parse tree of a union statement.
672  *
673  * Note :
674  * "legal" candidates for leafs are delete, update, and insert statements.
675  * "illegal" candidates are intersection and difference, which
676  * reslt in error return (NULL).
677  */
678 static PT_NODE *
680 {
681  PT_NODE *lhs = statement;
682  PT_NODE *rhs = NULL;
683 
684  if (!statement)
685  return NULL; /* bullet proofing */
686 
687  if (statement->node_type == PT_UNION && statement->info.query.all_distinct == PT_ALL)
688  {
689 
690  lhs = statement->info.query.q.union_.arg1;
691  rhs = statement->info.query.q.union_.arg2;
692  if (!lhs || !rhs)
693  return NULL; /* bullet proofing */
694 
695  if (lhs->node_type == PT_UNION)
696  lhs = mq_flatten_union (parser, lhs);
697  if (rhs->node_type == PT_UNION)
698  rhs = mq_flatten_union (parser, rhs);
699 
700  /* propagate error detected in recursion, if any */
701  if (!lhs || !rhs)
702  return NULL;
703 
704  /* append right hand side list to end of left hand side list */
705  parser_append_node (rhs, lhs);
706  }
707 
708  return lhs;
709 }
710 
711 /*
712  * mq_rewrite_agg_names() - re-sets PT_NAME node ids for conversion of
713  * aggregate selects. It also coerces path expressions into names, and
714  * pushes subqueries and SET() functions down into the derived table.
715  * It places each name on the referenced attrs list.
716  * return:
717  * parser(in):
718  * node(in):
719  * void_arg(in/out):
720  * continue_walk(in/out):
721  */
722 static PT_NODE *
723 mq_rewrite_agg_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
724 {
725  PT_AGG_REWRITE_INFO *info = (PT_AGG_REWRITE_INFO *) void_arg;
726  PT_AGG_NAME_INFO name_info;
727  PT_NODE *old_from = info->from;
728  PT_NODE *new_from = info->new_from;
729  PT_NODE *derived_select = info->derived_select;
730  PT_NODE *node_next;
733  PT_NODE *temp;
734  PT_NODE *arg2;
735  PT_NODE *temparg2;
736  int i = 0;
737  int line_no, col_no, is_hidden_column;
738  bool agg_found;
739 
740  *continue_walk = PT_CONTINUE_WALK;
741 
742  switch (node->node_type)
743  {
744  case PT_DOT_:
745  if ((arg2 = node->info.dot.arg2) && pt_find_entity (parser, old_from, node->info.dot.arg2->info.name.spec_id))
746  {
747  /* we should put this in the referenced name list, ie the select list of the derived select statement (if not
748  * already there) then change this node to a generated name. */
749  node_next = node->next;
750  type = node->type_enum;
751  data_type = parser_copy_tree_list (parser, node->data_type);
752 
753  node->next = NULL;
754  temp = derived_select->info.query.q.select.list;
755  i = 0;
756  while (temp)
757  {
758  if (temp->node_type == PT_DOT_ && (temparg2 = temp->info.dot.arg2)
759  && pt_name_equal (parser, temparg2, arg2))
760  {
761  break;
762  }
763  temp = temp->next;
764  i++;
765  }
766  line_no = node->line_number;
767  col_no = node->column_number;
768  is_hidden_column = node->flag.is_hidden_column;
769  if (!temp)
770  {
771  /* This was not found. add it */
772  derived_select->info.query.q.select.list =
773  parser_append_node (node, derived_select->info.query.q.select.list);
774  }
775  else
776  {
777  parser_free_tree (parser, node);
778  }
779  node = pt_name (parser, mq_generate_name (parser, "a", &i));
780  node->info.name.meta_class = PT_NORMAL;
781  node->info.name.spec_id = new_from->info.spec.id;
782  node->next = node_next;
783  node->type_enum = type;
784  node->data_type = data_type;
785  node->line_number = line_no;
786  node->column_number = col_no;
787  node->flag.is_hidden_column = is_hidden_column;
788 
789  mq_insert_symbol (parser, &new_from->info.spec.as_attr_list, node);
790  }
791  break;
792 
793  case PT_NAME:
794  /* is the name an attribute name ? */
795  if ((node->info.name.meta_class == PT_NORMAL || node->info.name.meta_class == PT_OID_ATTR
796  || node->info.name.meta_class == PT_VID_ATTR || node->info.name.meta_class == PT_SHARED
798  || node->info.name.meta_class == PT_METHOD) && pt_find_entity (parser, old_from, node->info.name.spec_id))
799  {
800 
801  if (node->info.name.meta_class == PT_METHOD)
802  {
803  /* for method_name, only reset spec_id */
804  node->info.name.spec_id = new_from->info.spec.id;
805 
806  goto push_complete;
807  }
808 
809  /* we should put this in the referenced name list, ie the select list of the derived select statement (if not
810  * already there) then change this node to a generated name. */
811  node_next = node->next;
812  type = node->type_enum;
813  data_type = parser_copy_tree_list (parser, node->data_type);
814 
815  node->next = NULL;
816  temp = derived_select->info.query.q.select.list;
817  i = 0;
818  while (temp)
819  {
820  if (temp->node_type == PT_NAME && pt_name_equal (parser, temp, node))
821  break;
822  temp = temp->next;
823  i++;
824  }
825  line_no = node->line_number;
826  col_no = node->column_number;
827  is_hidden_column = node->flag.is_hidden_column;
828  if (!temp)
829  {
830  derived_select->info.query.q.select.list =
831  parser_append_node (node, derived_select->info.query.q.select.list);
832  }
833  else
834  {
835  parser_free_tree (parser, node);
836  }
837 
838  node = pt_name (parser, mq_generate_name (parser, "a", &i));
839  node->info.name.meta_class = PT_NORMAL;
840  node->info.name.spec_id = new_from->info.spec.id;
841  node->next = node_next;
842  node->type_enum = type;
843  node->data_type = data_type;
844  node->line_number = line_no;
845  node->column_number = col_no;
846  node->flag.is_hidden_column = is_hidden_column;
847 
848  mq_insert_symbol (parser, &new_from->info.spec.as_attr_list, node);
849 
850  push_complete:
851 
852  /* once we push it, we don't need to dive in */
853  *continue_walk = PT_LIST_WALK;
854  }
855  break;
856 
857  case PT_FUNCTION:
858  /* We need to push the set functions down with their subqueries. init. info->from is already set at
859  * mq_rewrite_aggregate_as_derived */
860  agg_found = false;
861 
862  /* init name finding structure */
863  name_info.max_level = -1;
864  name_info.name_count = 0;
865  name_info.select_stack = info->select_stack;
866 
867  if (pt_is_set_type (node))
868  {
869  if (!pt_is_query (node->info.function.arg_list))
870  {
871  (void) parser_walk_tree (parser, node, pt_find_aggregate_names, &name_info, pt_continue_walk, NULL);
872 
873  agg_found = (name_info.max_level == 0 || name_info.name_count == 0);
874  }
875  }
876  else if (pt_is_aggregate_function (parser, node))
877  {
879  {
880  /* found count(*), groupby_num() */
881  agg_found = (info->depth == 0);
882  }
883  else
884  {
885  /* check for aggregation function for example: SELECT (SELECT max(x.i) FROM y ...) ... FROM x */
886  (void) parser_walk_tree (parser, node->info.function.arg_list, pt_find_aggregate_names, &name_info,
888  agg_found = (name_info.max_level == 0 || name_info.name_count == 0);
889  }
890  }
891 
892  /* rewrite if necessary */
893  if (agg_found)
894  {
895  node_next = node->next;
896  type = node->type_enum;
897  data_type = parser_copy_tree_list (parser, node->data_type);
898 
899  node->next = NULL;
900  for (i = 0, temp = derived_select->info.query.q.select.list; temp; temp = temp->next, i++)
901  ; /* empty */
902 
903  derived_select->info.query.q.select.list =
904  parser_append_node (node, derived_select->info.query.q.select.list);
905  line_no = node->line_number;
906  col_no = node->column_number;
907  is_hidden_column = node->flag.is_hidden_column;
908  node = pt_name (parser, mq_generate_name (parser, "a", &i));
909  node->info.name.meta_class = PT_NORMAL;
910  node->info.name.spec_id = new_from->info.spec.id;
911  node->next = node_next;
912  node->type_enum = type;
913  node->data_type = data_type;
914  node->line_number = line_no;
915  node->column_number = col_no;
916  node->flag.is_hidden_column = is_hidden_column;
917 
918  mq_insert_symbol (parser, &new_from->info.spec.as_attr_list, node);
919 
920  /* once we push it, we don't need to dive in */
921  *continue_walk = PT_LIST_WALK;
922  }
923  break;
924  case PT_UNION:
925  case PT_DIFFERENCE:
926  case PT_INTERSECTION:
927  case PT_SELECT:
928  /* Can not increment level for list portion of walk. Since those queries are not sub-queries of this query.
929  * Consequently, we recurse separately for the list leading from a query. Can't just call
930  * pt_to_uncorr_subquery_list() directly since it needs to do a leaf walk and we want to do a full walk on the
931  * next list. */
932  if (node->next)
933  {
934  node->next =
936  }
937 
938  if (node->info.query.correlation_level == 0)
939  {
940  /* no need to dive into the uncorrelated subquery */
941  *continue_walk = PT_STOP_WALK;
942  }
943  else
944  {
945  *continue_walk = PT_LEAF_WALK;
946  }
947 
948  /* push SELECT on stack */
949  if (node->node_type == PT_SELECT)
950  {
951  info->select_stack = pt_pointer_stack_push (parser, info->select_stack, node);
952  }
953 
954  info->depth++; /* increase query depth as we dive into subqueries */
955  break;
956 
957  case PT_DATA_TYPE:
958  *continue_walk = PT_STOP_WALK;
959  break;
960 
961  default:
962  break;
963  }
964 
965  return node;
966 }
967 
968 /*
969  * mq_rewrite_agg_names_post() -
970  * return:
971  * parser(in):
972  * node(in):
973  * void_arg(in/out):
974  * continue_walk(in):
975  */
976 static PT_NODE *
977 mq_rewrite_agg_names_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
978 {
979  PT_AGG_REWRITE_INFO *info = (PT_AGG_REWRITE_INFO *) void_arg;
980 
981  *continue_walk = PT_CONTINUE_WALK;
982 
983  switch (node->node_type)
984  {
985  case PT_SELECT:
986  info->select_stack = pt_pointer_stack_pop (parser, info->select_stack, NULL);
987  /* FALLTHRU */
988 
989  case PT_UNION:
990  case PT_DIFFERENCE:
991  case PT_INTERSECTION:
992  info->depth--; /* decrease query depth */
993  break;
994 
995  default:
996  break;
997  }
998 
999  return node;
1000 }
1001 
1002 /*
1003  * mq_conditionally_add_objects() - places the object pointers on an array
1004  * return: false on detection of duplicates in the classes
1005  * parser(in):
1006  * flat(in):
1007  * classes(in/out):
1008  * index(in/out):
1009  * max(in/out):
1010  */
1011 static bool
1013 {
1014  int i;
1015  DB_OBJECT *class_object;
1016  DB_OBJECT **temp;
1017 
1018  while (flat)
1019  {
1020  class_object = flat->info.name.db_object;
1021 
1022  for (i = 0; i < *index; i++)
1023  {
1024  if ((*classes)[i] == class_object)
1025  return false;
1026  }
1027  if (*index >= *max)
1028  {
1029  temp = (DB_OBJECT **) parser_alloc (parser, (*max + MAX_STACK_OBJECTS) * sizeof (DB_OBJECT *));
1030 
1031  if (temp == NULL)
1032  {
1033  PT_INTERNAL_ERROR (parser, "parser_alloc");
1034  return false;
1035  }
1036 
1037  memcpy (temp, *classes, *max * sizeof (DB_OBJECT *));
1038  /* don't keep dangling pointers */
1039  memset (*classes, 0, *max * sizeof (DB_OBJECT *));
1040  *classes = temp;
1041  *max = *max + MAX_STACK_OBJECTS;
1042  }
1043  (*classes)[(*index)] = class_object;
1044  (*index)++;
1045  flat = flat->next;
1046  }
1047 
1048  return true;
1049 }
1050 
1051 /*
1052  * mq_updatable_local() - takes a subquery expansion of a class_, and
1053  * tests it for updatability
1054  * return: true on updatable
1055  * parser(in):
1056  * statement(in):
1057  * classes(in/out):
1058  * num_classes(in/out):
1059  * max(in/out):
1060  */
1061 static PT_UPDATABILITY
1062 mq_updatable_local (PARSER_CONTEXT * parser, PT_NODE * statement, DB_OBJECT *** classes, int *num_classes, int *max)
1063 {
1064  PT_UPDATABILITY global = PT_UPDATABLE;
1065 
1066  while ((statement != NULL) && (PT_NOT_UPDATABLE != global))
1067  {
1068  PT_UPDATABILITY local = PT_UPDATABLE;
1069 
1070  if (statement && statement->info.query.all_distinct == PT_DISTINCT)
1071  {
1072  /* distinct */
1073  local = (PT_UPDATABILITY) (local & PT_NOT_UPDATABLE);
1074  }
1075 
1076  switch (statement->node_type)
1077  {
1078  case PT_SELECT:
1079  if (statement->info.query.q.select.group_by /* aggregate */
1080  || statement->info.query.q.select.having /* aggregate */
1081  || statement->info.query.q.select.connect_by /* HQ */
1082  || statement->info.query.q.select.from == NULL /* no spec */
1083  || PT_SELECT_INFO_IS_FLAGED (statement, PT_SELECT_INFO_READ_ONLY)) /* system generated read-only */
1084  {
1085  local = (PT_UPDATABILITY) (local & PT_NOT_UPDATABLE);
1086  }
1087 
1088  if (local != PT_NOT_UPDATABLE)
1089  {
1090  PT_NODE *spec = statement->info.query.q.select.from;
1091 
1092  while (spec != NULL)
1093  {
1094  if (spec->info.spec.derived_table != NULL)
1095  {
1096  if (spec->info.spec.flag & PT_SPEC_FLAG_FROM_VCLASS)
1097  {
1098  /* derived table from former view */
1099  local = (PT_UPDATABILITY) (local &
1100  mq_updatable_local (parser, spec->info.spec.derived_table, classes,
1101  num_classes, max));
1102  }
1103  else
1104  {
1105  /* derived tables are not updatable */
1106  local = PT_NOT_UPDATABLE;
1107  break;
1108  }
1109  }
1110  spec = spec->next;
1111  }
1112  }
1113 
1114  if (local != PT_NOT_UPDATABLE
1115  && (pt_has_aggregate (parser, statement) || pt_has_analytic (parser, statement)))
1116  {
1117  /* aggregate and analytic queries are not updatable */
1118  local = (PT_UPDATABILITY) (local & PT_NOT_UPDATABLE);
1119  }
1120 
1121  if (local != PT_NOT_UPDATABLE)
1122  {
1123  PT_NODE *from;
1124  int i = 0;
1125 
1126  for (from = statement->info.query.q.select.from; from != NULL; from = from->next)
1127  {
1128  (void) mq_conditionally_add_objects (parser, from->info.spec.flat_entity_list, classes, num_classes,
1129  max);
1130  }
1131 
1132  for (i = 0; i < *num_classes; ++i)
1133  {
1134  if (sm_is_reuse_oid_class ((*classes)[i]) || sm_is_system_class ((*classes)[i]) > 0)
1135  {
1136  local = (PT_UPDATABILITY) (local & PT_NOT_UPDATABLE);
1137  break;
1138  }
1139  }
1140  }
1141 
1142  if (local != PT_NOT_UPDATABLE && statement->info.query.q.select.from->next)
1143  {
1144  /* last check is for partially updatable queries */
1145  local = (PT_UPDATABILITY) (local & PT_PARTIALLY_UPDATABLE);
1146  }
1147  break;
1148 
1149  case PT_UNION:
1150  if (local != PT_NOT_UPDATABLE)
1151  {
1152  local =
1153  (PT_UPDATABILITY) (local &
1154  mq_updatable_local (parser, statement->info.query.q.union_.arg1, classes,
1155  num_classes, max));
1156  local =
1157  (PT_UPDATABILITY) (local &
1158  mq_updatable_local (parser, statement->info.query.q.union_.arg2, classes,
1159  num_classes, max));
1160  }
1161  break;
1162 
1163  default:
1164  local = (PT_UPDATABILITY) (local & PT_NOT_UPDATABLE);
1165  break;
1166  }
1167 
1168  /* next statement */
1169  global = (PT_UPDATABILITY) (local & global);
1170  statement = statement->next;
1171  }
1172 
1173  return global;
1174 }
1175 
1176 /*
1177  * mq_updatable() - takes a subquery expansion of a class_, and
1178  * tests it for updatability
1179  * return: true on updatable
1180  * parser(in):
1181  * statement(in):
1182  */
1185 {
1186  PT_UPDATABILITY updatable;
1187  int num_classes = 0;
1188  int max = MAX_STACK_OBJECTS;
1189  DB_OBJECT *class_stack_array[MAX_STACK_OBJECTS];
1190  DB_OBJECT **classes = class_stack_array;
1191 
1192  updatable = mq_updatable_local (parser, statement, &classes, &num_classes, &max);
1193 
1194  /* don't keep dangling pointers on stack or in virtual memory */
1195  memset (classes, 0, max * sizeof (DB_OBJECT *));
1196 
1197  return updatable;
1198 }
1199 
1200 /*
1201  * mq_substitute_select_in_statement() - takes a subquery expansion of a class_,
1202  * in the form of a select, and a parse tree containing references to
1203  * the class and its attributes, and substitutes matching select
1204  * expressions for each attribute, and matching referenced classes
1205  * for each class
1206  * return: PT_NODE *, parse tree with local db table/class queries
1207  * expanded to local db expressions
1208  * parser(in): parser context
1209  * statement(in/out): statement into which class will be expanded
1210  * query_spec(in): query of class that will be expanded
1211  * class(in): class name of class that will be expanded
1212  */
1213 static PT_NODE *
1215 {
1217  PT_NODE *query_spec_from, *query_spec_columns;
1218  PT_NODE *attributes, *attr;
1219  PT_NODE *col;
1220 
1221  /* Replace columns/attributes. for each column/attribute name in table/class class, replace with actual select
1222  * column. */
1223 
1224  query_spec_columns = query_spec->info.query.q.select.list;
1225  query_spec_from = query_spec->info.query.q.select.from;
1226  if (query_spec_from == NULL)
1227  {
1228  PT_INTERNAL_ERROR (parser, "translate");
1229  return NULL;
1230  }
1231 
1232  /* fix up resolution of any method calls in the statement */
1233  info.old_id = class_->info.name.spec_id;
1234  info.new_id = query_spec_from->info.spec.id;
1235  (void) parser_walk_tree (parser, statement, mq_substitute_spec_in_method_names, &info, NULL, NULL);
1236 
1237  /* get vclass spec attrs */
1238  attributes = mq_fetch_attributes (parser, class_);
1239  if (attributes == NULL)
1240  {
1241  return NULL;
1242  }
1243 
1244  col = query_spec_columns;
1245  attr = attributes;
1246  if (PT_IS_VALUE_QUERY (query_spec) && col != NULL && attr != NULL)
1247  {
1248  assert (col->node_type == PT_NODE_LIST);
1249 
1250  col = col->info.node_list.list;
1251 
1252  /* skip oid */
1253  attr = attr->next;
1254  }
1255 
1256  for (; col && attr; col = col->next, attr = attr->next)
1257  {
1258  /* set spec_id */
1259  attr->info.name.spec_id = class_->info.name.spec_id;
1260  }
1261 
1262  while (col)
1263  {
1264  if (col->flag.is_hidden_column)
1265  {
1266  col = col->next;
1267  continue;
1268  }
1269  break;
1270  }
1271 
1272  if (col)
1273  { /* error */
1275  class_->info.name.original);
1276  statement = NULL;
1277  }
1278  if (attr)
1279  { /* error */
1281  class_->info.name.original);
1282  statement = NULL;
1283  }
1284 
1285  /* substitute attributes for query_spec_columns in statement */
1286  statement = mq_lambda (parser, statement, attributes, query_spec_columns);
1287 
1288  /* replace table */
1289  if (statement)
1290  {
1291  statement =
1292  mq_class_lambda (parser, statement, class_, query_spec_from, query_spec->info.query.q.select.where,
1293  query_spec->info.query.q.select.check_where, query_spec->info.query.q.select.group_by,
1294  query_spec->info.query.q.select.having);
1296  {
1297  /* mark as agg select */
1298  if (statement && statement->node_type == PT_SELECT)
1299  {
1301  }
1302  }
1303  }
1304 
1305  return statement;
1306 }
1307 
1308 /*
1309  * mq_substitute_spec_in_method_names() - substitue spec id in method names
1310  * return:
1311  * parser(in):
1312  * node(in):
1313  * void_arg(in):
1314  * continue_walk(in):
1315  */
1316 static PT_NODE *
1317 mq_substitute_spec_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1318 {
1320 
1321  if ((node->node_type == PT_METHOD_CALL) && (node->info.method_call.method_name)
1322  && (node->info.method_call.method_name->info.name.spec_id == info->old_id))
1323  {
1325  }
1326 
1327  return node;
1328 }
1329 
1330 /*
1331  * mq_is_pushable_subquery () - check if a subquery is pushable
1332  * returns: true if pushable, false otherwise
1333  * parser(in): parser context
1334  * query(in): query to check
1335  * is_only_spec(in): true if query is not joined in parent statement
1336  *
1337  * NOTE: a subquery is pushable if it's select list can be "pushed" up in it's
1338  * parent query without altering the output. For example, the following:
1339  * SELECT * FROM (SELECT * FROM t WHERE t.i > 2), u
1340  * can be rewritten as
1341  * SELECT * FROM t, u WHERE t.i > 2
1342  * thus, "SELECT * FROM t WHERE t.i > 2" is called "pushable".
1343  *
1344  * NOTE: inst_num(), groupby_num() and rownum are only pushable if the
1345  * query is not joined in the parent statement.
1346  *
1347  * NOTE: a query with joins is only pushable if it's not joined in the parent
1348  * statement
1349  */
1350 static bool
1351 mq_is_pushable_subquery (PARSER_CONTEXT * parser, PT_NODE * query, bool is_only_spec)
1352 {
1353  CHECK_PUSHABLE_INFO cpi;
1354 
1355  /* check nulls */
1356  if (query == NULL)
1357  {
1358  PT_INTERNAL_ERROR (parser, "wrong arguments passed to function");
1359  return false;
1360  }
1361 
1362  assert (parser);
1364 
1365  /* check for non-SELECTs */
1366  if (query->node_type != PT_SELECT)
1367  {
1368  /* not pushable */
1369  return false;
1370  }
1371 
1372  /* check for joins */
1373  if (!is_only_spec && query->info.query.q.select.from && query->info.query.q.select.from->next)
1374  {
1375  /* parent statement and subquery both have joins; not pushable */
1376  return false;
1377  }
1378 
1379  /* check for CONNECT BY */
1380  if (query->node_type == PT_SELECT && query->info.query.q.select.connect_by)
1381  {
1382  /* not pushable */
1383  return false;
1384  }
1385 
1386  /* check for DISTINCT */
1387  if (pt_is_distinct (query))
1388  {
1389  /* not pushable */
1390  return false;
1391  }
1392 
1393  /* check for aggregate or orderby_for */
1394  if (pt_has_aggregate (parser, query) || query->info.query.orderby_for)
1395  {
1396  /* not pushable */
1397  return false;
1398  }
1399 
1400  /* check select list */
1401  cpi.check_query = false; /* subqueries are pushable */
1402  cpi.check_method = true; /* methods are non-pushable */
1403  cpi.check_xxxnum = !is_only_spec;
1404  cpi.check_analytic = false; /* analytic functions are pushable */
1405 
1406  cpi.method_found = false;
1407  cpi.query_found = false;
1408  cpi.xxxnum_found = false;
1409  cpi.analytic_found = false;
1410 
1411  parser_walk_tree (parser, query->info.query.q.select.list, pt_check_pushable, (void *) &cpi, NULL, NULL);
1412 
1413  if (cpi.method_found || cpi.query_found || cpi.xxxnum_found || cpi.analytic_found)
1414  {
1415  /* query not pushable */
1416  return false;
1417  }
1418 
1419  /* check where clause */
1420  cpi.check_query = false; /* subqueries are pushable */
1421  cpi.check_method = true; /* methods are non-pushable */
1422  cpi.check_xxxnum = !is_only_spec;
1423  cpi.check_analytic = false; /* analytic functions are pushable */
1424 
1425  cpi.method_found = false;
1426  cpi.query_found = false;
1427  cpi.xxxnum_found = false;
1428  cpi.analytic_found = false;
1429 
1430  parser_walk_tree (parser, query->info.query.q.select.where, pt_check_pushable, (void *) &cpi, NULL, NULL);
1431 
1432  if (cpi.method_found || cpi.query_found || cpi.xxxnum_found || cpi.analytic_found)
1433  {
1434  /* query not pushable */
1435  return false;
1436  }
1437 
1438  /* if we got this far, query is pushable */
1439  return true;
1440 }
1441 
1442 /*
1443  * mq_update_order_by() - update the position number of order by clause and
1444  * add hidden column(s) at the end of the output list if
1445  * necessary.
1446  * return: PT_NODE *, parse tree with local db table/class queries expanded
1447  * to local db expressions
1448  * parser(in): parser context
1449  * statement(in): statement into which class will be expanded
1450  * query_spec(in): query of class that will be expanded
1451  * class(in): class name of class that will be expanded
1452  *
1453  * Note:
1454  * It includes 3 steps to update the position number of order by clause.
1455  * 1) Get the attr info from the vclass;
1456  * 2) Find the corresponding attr by the position number of order by clause;
1457  * 3) Compare the corresponding attr with the attr of output list,
1458  * a) if attr is in output list, update the position number of order by
1459  * clause;
1460  * b) if not, append a hidden column at the end of the output list, and
1461  * update the position number of order by clause.
1462  *
1463  */
1464 static PT_NODE *
1465 mq_update_order_by (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * query_spec, PT_NODE * class_)
1466 {
1467  PT_NODE *order, *val;
1468  PT_NODE *attributes, *attr;
1469  PT_NODE *node, *result;
1470  PT_NODE *save_data_type;
1471  int attr_count;
1472  int i;
1473 
1474  assert (statement->node_type == PT_SELECT && query_spec->info.query.order_by != NULL);
1475 
1476  statement->info.query.order_by =
1478  statement->info.query.order_by);
1479 
1480 
1481  /* 1 get vclass spec attrs */
1482  attributes = mq_fetch_attributes (parser, class_);
1483  if (attributes == NULL)
1484  {
1485  return NULL;
1486  }
1487 
1488  attr_count = 0;
1489  for (attr = attributes; attr != NULL; attr = attr->next)
1490  {
1491  /* set spec_id */
1492  attr->info.name.spec_id = class_->info.name.spec_id;
1493  attr_count++;
1494  }
1495 
1496  /* update the position number of order by clause */
1497  for (order = statement->info.query.order_by; order != NULL; order = order->next)
1498  {
1499  assert (order->node_type == PT_SORT_SPEC);
1500 
1501  val = order->info.sort_spec.expr;
1502  assert (val->node_type == PT_VALUE);
1503 
1504  if (attr_count < val->info.value.data_value.i)
1505  {
1506  /* order by is a hidden column and not in attribute list, in this case, we need append a hidden column at the
1507  * end of the output list. */
1508 
1509  /* 2 find from spec columns */
1510  for (i = 1, attr = query_spec->info.query.q.select.list; i < val->info.value.data_value.i; i++)
1511  {
1512  assert (attr != NULL);
1513  attr = attr->next;
1514  }
1515 
1516  save_data_type = attr->data_type;
1517  attr->data_type = NULL;
1518 
1519  for (i = 1, node = statement->info.query.q.select.list; node != NULL; node = node->next)
1520  {
1521  i++;
1522  }
1523  node = NULL;
1524  }
1525  else
1526  {
1527  /* 2 find the corresponding attribute */
1528  for (i = 1, attr = attributes; i < val->info.value.data_value.i; i++)
1529  {
1530  assert (attr != NULL);
1531  attr = attr->next;
1532  }
1533 
1534  assert (attr != NULL && attr->node_type == PT_NAME);
1535  save_data_type = attr->data_type;
1536  attr->data_type = NULL;
1537 
1538  for (node = statement->info.query.q.select.list, i = 1; node != NULL; node = node->next, i++)
1539  {
1540  /* 3 check whether attr is found in output list */
1541  if (pt_name_equal (parser, node, attr))
1542  {
1543  /* if yes, update position number of order by clause */
1544  val->info.value.data_value.i = i;
1545  val->info.value.db_value.data.i = i;
1546  val->info.value.text = NULL;
1547  order->info.sort_spec.pos_descr.pos_no = i;
1548  break;
1549  }
1550  }
1551  }
1552 
1553  /* if attr is not found in output list, append a hidden column at the end of the output list. */
1554  if (node == NULL)
1555  {
1556  result = parser_copy_tree (parser, attr);
1557  if (result == NULL)
1558  {
1559  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
1560  return NULL;
1561  }
1562  /* mark as a hidden column */
1563  result->flag.is_hidden_column = 1;
1564  parser_append_node (result, statement->info.query.q.select.list);
1565 
1566  /* update position number of order by clause */
1567  val->info.value.data_value.i = i;
1568  val->info.value.db_value.data.i = i;
1569  val->info.value.text = NULL;
1570  order->info.sort_spec.pos_descr.pos_no = i;
1571  }
1572 
1573  attr->data_type = save_data_type;
1574  }
1575 
1576  return statement;
1577 }
1578 
1579 /*
1580  * mq_substitute_subquery_in_statement() - This takes a subquery expansion of
1581  * a class_, in the form of a select, or union of selects,
1582  * and a parse tree containing references to the class and its attributes,
1583  * and substitutes matching select expressions for each attribute,
1584  * and matching referenced classes for each class
1585  * return: PT_NODE *, parse tree with local db table/class queries
1586  * expanded to local db expressions
1587  * parser(in):
1588  * statement(in):
1589  * query_spec(in):
1590  * class(in):
1591  * order_by(in):
1592  * what_for(in):
1593  *
1594  * Note:
1595  * 1) Order-by is passed down into sub portions of the unions, intersections and
1596  * differences.
1597  * This gives better algorithmic order when order by is present, allowing
1598  * sorting on smaller pieces, followed by linear merges.
1599  *
1600  * 2) All/distinct is NOT similarly passed down, since it is NOT a transitive
1601  * operation with mixtures of union, intersection and difference.
1602  * It may be true that if the top level guy is distinct, you will
1603  * get the same results if all sub levels are also distinct.
1604  * Anyway, it is safe not to do this, and may be not be safe to do.
1605  */
1606 static PT_NODE *
1608  PT_NODE * class_, PT_NODE * order_by, int what_for)
1609 {
1610  PT_NODE *tmp_result, *result, *arg1, *arg2, *statement_next;
1611  PT_NODE *class_spec, *statement_spec = NULL;
1612  PT_NODE *derived_table, *derived_spec, *derived_class;
1613  bool is_pushable_query, is_outer_joined;
1614  bool is_only_spec, rewrite_as_derived;
1615  bool is_index_ss, is_index_ls;
1616 
1617  result = tmp_result = NULL; /* init */
1618  class_spec = NULL;
1619  rewrite_as_derived = false;
1620 
1621  statement_next = statement->next;
1622  switch (query_spec->node_type)
1623  {
1624  case PT_SELECT:
1625  /* make a local copy of the statement */
1626  tmp_result = parser_copy_tree (parser, statement);
1627  if (tmp_result == NULL)
1628  {
1629  if (!pt_has_error (parser))
1630  {
1631  PT_INTERNAL_ERROR (parser, "failed to copy node tree");
1632  }
1633 
1634  goto exit_on_error;
1635  }
1636 
1637  /* Due to tree copy, the spec ids of methods are broken. Reset spec ids */
1638  mq_reset_ids_in_methods (parser, tmp_result);
1639 
1640  /* get statement spec */
1641  switch (tmp_result->node_type)
1642  {
1643  case PT_SELECT:
1644  statement_spec = tmp_result->info.query.q.select.from;
1645  break;
1646 
1647  case PT_UPDATE:
1648  statement_spec = tmp_result->info.update.spec;
1649  break;
1650 
1651  case PT_DELETE:
1652  statement_spec = tmp_result->info.delete_.spec;
1653  break;
1654 
1655  case PT_INSERT:
1656  /* since INSERT can not have a spec list or statement conditions, there is nothing to check */
1657  statement_spec = tmp_result->info.insert.spec;
1658  break;
1659 
1660  case PT_MERGE:
1661  statement_spec = tmp_result->info.merge.into;
1662  break;
1663 
1664  default:
1665  /* should not get here */
1666  assert (false);
1667  PT_INTERNAL_ERROR (parser, "unknown node");
1668  goto exit_on_error;
1669  }
1670 
1671  /* check found spec */
1672  class_spec = pt_find_spec (parser, statement_spec, class_);
1673  if (class_spec == NULL)
1674  {
1675  /* class_'s spec was not found in spec list */
1676  PT_INTERNAL_ERROR (parser, "class spec not found");
1677  goto exit_on_error;
1678  }
1679  else
1680  {
1681  /* check for (non-pushable) spec set */
1682  rewrite_as_derived = (class_spec->info.spec.entity_name != NULL
1683  && class_spec->info.spec.entity_name->node_type == PT_SPEC);
1684  }
1685 
1686  /* do not rewrite vclass_query as a derived table if spec belongs to an insert statement. */
1687  if (tmp_result->node_type == PT_INSERT)
1688  {
1689  rewrite_as_derived = false;
1690  }
1691  else
1692  {
1693  /* determine if class_spec is the only spec in the statement */
1694  is_only_spec = (statement_spec->next == NULL ? true : false);
1695 
1696  /* determine if spec is outer joined */
1697  is_outer_joined = mq_is_outer_join_spec (parser, class_spec);
1698 
1699  /* determine if vclass_query is pushable */
1700  is_pushable_query = mq_is_pushable_subquery (parser, query_spec, is_only_spec);
1701 
1702  /* rewrite vclass_query as a derived table if spec is outer joined or if query is not pushable */
1703  rewrite_as_derived = rewrite_as_derived || !is_pushable_query || is_outer_joined;
1704 
1705  if (PT_IS_QUERY (tmp_result))
1706  {
1707  rewrite_as_derived = rewrite_as_derived || (tmp_result->info.query.all_distinct == PT_DISTINCT)
1708  || (PT_IS_VALUE_QUERY (query_spec));
1709  }
1710  }
1711 
1712  if (rewrite_as_derived)
1713  {
1714  /* rewrite vclass query as a derived table */
1715  PT_NODE *tmp_class = NULL;
1716 
1717  /* rewrite vclass spec */
1718  class_spec = mq_rewrite_vclass_spec_as_derived (parser, tmp_result, class_spec, query_spec);
1719 
1720  /* get derived expending spec node */
1721  if (!class_spec || !(derived_table = class_spec->info.spec.derived_table)
1722  || !(derived_spec = derived_table->info.query.q.select.from)
1723  || !(derived_class = derived_spec->info.spec.flat_entity_list))
1724  {
1725  /* error */
1726  goto exit_on_error;
1727  }
1728 
1729  tmp_class = parser_copy_tree (parser, class_);
1730  if (tmp_class == NULL)
1731  {
1732  goto exit_on_error;
1733  }
1734  tmp_class->info.name.spec_id = derived_class->info.name.spec_id;
1735 
1736  /* now, derived_table has been derived. */
1737  if (pt_has_aggregate (parser, query_spec))
1738  {
1739  /* simply move WHERE's aggregate terms to HAVING. in mq_class_lambda(), this HAVING will be merged with
1740  * query_spec HAVING. */
1741  derived_table->info.query.q.select.having = derived_table->info.query.q.select.where;
1742  derived_table->info.query.q.select.where = NULL;
1743  }
1744 
1745  /* merge HINT of vclass spec */
1746  derived_table->info.query.q.select.hint =
1747  (PT_HINT_ENUM) (derived_table->info.query.q.select.hint | query_spec->info.query.q.select.hint);
1748  derived_table->info.query.q.select.ordered =
1750  derived_table->info.query.q.select.ordered);
1751 
1752  derived_table->info.query.q.select.use_nl =
1754  derived_table->info.query.q.select.use_nl);
1755 
1756  derived_table->info.query.q.select.use_idx =
1758  derived_table->info.query.q.select.use_idx);
1759 
1760  derived_table->info.query.q.select.index_ss =
1762  derived_table->info.query.q.select.index_ss);
1763 
1764  derived_table->info.query.q.select.index_ls =
1766  derived_table->info.query.q.select.index_ls);
1767 
1768  derived_table->info.query.q.select.use_merge =
1770  derived_table->info.query.q.select.use_merge);
1771 
1772  if (!order_by || query_spec->info.query.orderby_for)
1773  {
1774  if (query_spec->info.query.order_by)
1775  {
1776  /* update the position number of order by clause */
1777  derived_table = mq_update_order_by (parser, derived_table, query_spec, tmp_class);
1778  if (derived_table == NULL)
1779  {
1780  goto exit_on_error;
1781  }
1782  derived_table->info.query.flag.order_siblings = query_spec->info.query.flag.order_siblings;
1783  }
1784 
1785  if (query_spec->info.query.orderby_for)
1786  {
1787  derived_table->info.query.orderby_for =
1789  derived_table->info.query.orderby_for);
1790  }
1791  }
1792 
1793  /* merge USING INDEX clause of vclass spec */
1794  if (query_spec->info.query.q.select.using_index)
1795  {
1796  PT_NODE *ui;
1797 
1798  ui = parser_copy_tree_list (parser, query_spec->info.query.q.select.using_index);
1799  derived_table->info.query.q.select.using_index =
1800  parser_append_node (ui, derived_table->info.query.q.select.using_index);
1801  }
1802 
1803  class_spec->info.spec.derived_table =
1804  mq_substitute_select_in_statement (parser, class_spec->info.spec.derived_table, query_spec, tmp_class);
1805 
1806  if (tmp_class)
1807  {
1808  parser_free_tree (parser, tmp_class);
1809  }
1810 
1811  derived_table = class_spec->info.spec.derived_table;
1812  if (derived_table == NULL)
1813  { /* error */
1814  goto exit_on_error;
1815  }
1816 
1817  if (PT_IS_QUERY (derived_table))
1818  {
1819  if (query_spec->info.query.all_distinct == PT_DISTINCT)
1820  {
1821  derived_table->info.query.all_distinct = PT_DISTINCT;
1822  }
1823  }
1824 
1825  result = tmp_result;
1826  }
1827  else
1828  {
1829  /* expand vclass_query in parent statement */
1830  if (tmp_result->node_type == PT_SELECT)
1831  {
1832  is_index_ss = tmp_result->info.query.q.select.hint & PT_HINT_INDEX_SS;
1833  is_index_ls = tmp_result->info.query.q.select.hint & PT_HINT_INDEX_LS;
1834 
1835  /* merge HINT of vclass spec */
1836  tmp_result->info.query.q.select.hint =
1837  (PT_HINT_ENUM) (tmp_result->info.query.q.select.hint | query_spec->info.query.q.select.hint);
1838 
1839  tmp_result->info.query.q.select.ordered =
1841  tmp_result->info.query.q.select.ordered);
1842 
1843  tmp_result->info.query.q.select.use_nl =
1845  tmp_result->info.query.q.select.use_nl);
1846 
1847  tmp_result->info.query.q.select.use_idx =
1849  tmp_result->info.query.q.select.use_idx);
1850 
1851  if (!is_index_ss || tmp_result->info.query.q.select.index_ss != NULL)
1852  {
1853  tmp_result->info.query.q.select.index_ss =
1855  tmp_result->info.query.q.select.index_ss);
1856  }
1857 
1858  if (!is_index_ls || tmp_result->info.query.q.select.index_ls != NULL)
1859  {
1860  tmp_result->info.query.q.select.index_ls =
1862  tmp_result->info.query.q.select.index_ls);
1863  }
1864 
1865  tmp_result->info.query.q.select.use_merge =
1867  tmp_result->info.query.q.select.use_merge);
1868 
1869  assert (query_spec->info.query.orderby_for == NULL);
1870  if (!order_by && query_spec->info.query.order_by)
1871  {
1872  /* update the position number of order by clause and add a hidden column into the output list if
1873  * necessary. */
1874  tmp_result = mq_update_order_by (parser, tmp_result, query_spec, class_);
1875  if (tmp_result == NULL)
1876  {
1877  goto exit_on_error;
1878  }
1879  }
1880  }
1881 
1882  /* merge USING INDEX clause of vclass spec */
1883  if (query_spec->info.query.q.select.using_index)
1884  {
1885  PT_NODE *ui;
1886 
1887  ui = parser_copy_tree_list (parser, query_spec->info.query.q.select.using_index);
1888  if (tmp_result->node_type == PT_SELECT)
1889  {
1890  tmp_result->info.query.q.select.using_index =
1891  parser_append_node (ui, tmp_result->info.query.q.select.using_index);
1892  }
1893  else if (tmp_result->node_type == PT_UPDATE)
1894  {
1895  tmp_result->info.update.using_index = parser_append_node (ui, tmp_result->info.update.using_index);
1896  }
1897  else if (tmp_result->node_type == PT_DELETE)
1898  {
1899  tmp_result->info.delete_.using_index = parser_append_node (ui, tmp_result->info.delete_.using_index);
1900  }
1901  }
1902 
1903  result = mq_substitute_select_in_statement (parser, tmp_result, query_spec, class_);
1904  }
1905 
1906  /* set query id # */
1907  if (result)
1908  {
1909  if (PT_IS_QUERY (result))
1910  {
1911  result->info.query.id = (UINTPTR) result;
1912  }
1913  }
1914  else
1915  {
1916  goto exit_on_error;
1917  }
1918 
1919  break;
1920 
1921  case PT_UNION:
1922  case PT_DIFFERENCE:
1923  case PT_INTERSECTION:
1924  if (pt_has_aggregate (parser, statement))
1925  {
1926  /* this error will not occur now unless there is a system error. The above condition will cause the query to
1927  * be rewritten earlier. */
1929  result = NULL;
1930  }
1931  else if (statement->node_type == PT_SELECT)
1932  {
1933  PT_NODE *inside_order_by = NULL;
1934 
1935  /* the vclasses are rewritten in mq_push_paths->mq_rewrite_vclass_spec_as_derived;
1936  * this should guarantee that vclasses appear only in simple, generated SELECTs, without order_by;
1937  */
1938  assert (order_by == NULL);
1939 
1940  arg1 = query_spec->info.query.q.union_.arg1;
1941  arg2 = query_spec->info.query.q.union_.arg2;
1942 
1943  if (query_spec->info.query.order_by != NULL)
1944  {
1945  /* update the position number of order by clause */
1946  statement = mq_update_order_by (parser, statement, query_spec, class_);
1947  if (statement == NULL)
1948  {
1949  goto exit_on_error;
1950  }
1951  inside_order_by = statement->info.query.order_by;
1952  statement->info.query.order_by = NULL;
1953  }
1954 
1955  arg1 = mq_substitute_subquery_in_statement (parser, statement, arg1, class_, order_by, what_for);
1956  arg2 = mq_substitute_subquery_in_statement (parser, statement, arg2, class_, order_by, what_for);
1957 
1958  if (arg1 && arg2)
1959  {
1960  result = mq_union_bump_correlation (parser, arg1, arg2);
1961  /* reset node_type in case it was difference or intersection */
1962  if (result)
1963  {
1964  result->node_type = query_spec->node_type;
1965  }
1966  }
1967  else
1968  {
1969  if (query_spec->node_type == PT_INTERSECTION)
1970  {
1971  result = NULL;
1972  }
1973  else if (query_spec->node_type == PT_DIFFERENCE)
1974  {
1975  result = arg1;
1976  }
1977  else
1978  {
1979  if (arg1)
1980  {
1981  result = arg1;
1982  }
1983  else
1984  {
1985  result = arg2;
1986  }
1987  }
1988  }
1989 
1990  if (result != NULL)
1991  {
1992  if (query_spec->info.query.order_by != NULL)
1993  {
1994  result->info.query.order_by = inside_order_by;
1995  result->info.query.flag.order_siblings = query_spec->info.query.flag.order_siblings;
1996  }
1997 
1998  if (query_spec->info.query.orderby_for != NULL)
1999  {
2000  result->info.query.orderby_for =
2002  result->info.query.orderby_for);
2003  }
2004 
2005  if (query_spec->info.query.limit != NULL)
2006  {
2007  result->info.query.limit =
2008  parser_append_node (parser_copy_tree_list (parser, query_spec->info.query.limit),
2009  result->info.query.limit);
2010 
2011  result->info.query.flag.rewrite_limit = 1;
2012  }
2013 
2014  }
2015  }
2016  else if (statement->node_type == PT_UPDATE || statement->node_type == PT_DELETE)
2017  {
2018  /* create table t1(a int); create view v1 as select * from t1 t1 union select * from t1 t2; update t1,v1 set
2019  * t1.a=v1.a; rewrite to update t1,(select * from t1 t1 union select * from t1 t2) v1 set t1.a=v1.a; delete
2020  * a from t1 a,v1 b where a.a=b.a; rewrite to delete a from t1 a,(select * from t1 t1 union select * from t1
2021  * t2) b where a.a=b.a */
2022  tmp_result = parser_copy_tree (parser, statement);
2023  if (tmp_result == NULL)
2024  {
2025  if (!pt_has_error (parser))
2026  {
2027  PT_INTERNAL_ERROR (parser, "failed to copy node tree");
2028  }
2029 
2030  goto exit_on_error;
2031  }
2032 
2033  if (statement->node_type == PT_UPDATE)
2034  {
2035  statement_spec = tmp_result->info.update.spec;
2036  }
2037  else /* PT_DELETE */
2038  {
2039  statement_spec = tmp_result->info.delete_.spec;
2040  }
2041 
2042  class_spec = pt_find_spec (parser, statement_spec, class_);
2043  if (class_spec == NULL)
2044  {
2045  /* class_'s spec was not found in spec list */
2046  PT_INTERNAL_ERROR (parser, "class spec not found");
2047  goto exit_on_error;
2048  }
2049 
2050  class_spec = mq_rewrite_vclass_spec_as_derived (parser, tmp_result, class_spec, query_spec);
2051  if (class_spec == NULL)
2052  {
2053  goto exit_on_error;
2054  }
2055 
2056  result = tmp_result;
2057  }
2058  else
2059  {
2060  /* cannot be here */
2061  assert (0);
2062  }
2063 
2064  break;
2065 
2066  default:
2067  /* should not get here, that is an error! */
2068  assert (0);
2069  break;
2070  }
2071 
2072  if (result && PT_IS_QUERY (result))
2073  {
2074  if (query_spec->info.query.all_distinct == PT_DISTINCT)
2075  {
2076  if (rewrite_as_derived == true)
2077  {
2078  /* result has been substituted. skip and go ahead */
2079  }
2080  else
2081  {
2082  result->info.query.all_distinct = PT_DISTINCT;
2083  }
2084  }
2085  }
2086 
2087  if (result)
2088  {
2089  result->next = statement_next;
2090  }
2091 
2092  return result;
2093 
2094 exit_on_error:
2095 
2096  if (tmp_result)
2097  {
2098  parser_free_tree (parser, tmp_result);
2099  }
2100 
2101  return NULL;
2102 }
2103 
2104 /*
2105  * mq_substitute_subquery_list_in_statement() - takes a subquery list and
2106  * applies substitution to each one
2107  * return: PT_NODE *, translated list of statements
2108  * parser(in):
2109  * statement(in):
2110  * query_spec_list(in):
2111  * class(in):
2112  * order_by(in):
2113  * what_for(in):
2114  */
2115 static PT_NODE *
2117  PT_NODE * class_, PT_NODE * order_by, int what_for)
2118 {
2119  PT_NODE *query_spec = query_spec_list;
2120  PT_NODE *result_list = NULL;
2121  PT_NODE *result;
2122 
2123  while (query_spec)
2124  {
2125  result = mq_substitute_subquery_in_statement (parser, statement, query_spec, class_, order_by, what_for);
2126  if (result)
2127  {
2128  result_list = parser_append_node (result, result_list);
2129  }
2130  else if (er_errid_if_has_error () != NO_ERROR || pt_has_error (parser))
2131  {
2132  return NULL;
2133  }
2134 
2135  query_spec = query_spec->next;
2136  }
2137 
2138  return result_list;
2139 }
2140 
2141 
2142 /*
2143  * mq_translatable_class() -
2144  * return: 1 on translatable
2145  * parser(in):
2146  * class(in):
2147  */
2148 static int
2150 {
2151  /* if its a meta class_, its not translatable, even if its a meta vclass. */
2152  if (class_->info.name.meta_class == PT_META_CLASS || class_->info.name.meta_class == PT_CLASSOID_ATTR)
2153  {
2154  return 0;
2155  }
2156 
2157  /* vclasses, aka views, are otherwise translatable */
2158  if (db_is_vclass (class_->info.name.db_object) > 0)
2159  {
2160  return 1;
2161  }
2162 
2163  return 0;
2164 }
2165 
2166 /*
2167  * mq_is_union_translation() - tests a spec for a union translation
2168  * return:
2169  * parser(in):
2170  * spec(in):
2171  */
2172 static int
2174 {
2175  PT_NODE *entity;
2176  PT_NODE *subquery;
2177  int had_some_real_classes = 0;
2178  int had_some_virtual_classes = 0;
2179 
2180  if (spec == NULL || spec->info.spec.flat_entity_list == NULL)
2181  {
2182  return false;
2183  }
2184 
2186  {
2187  for (entity = spec->info.spec.flat_entity_list; entity != NULL; entity = entity->next)
2188  {
2189  if (!mq_translatable_class (parser, entity))
2190  {
2191  /* no translation for above cases */
2192  had_some_real_classes++;
2193  }
2194  else
2195  {
2196  had_some_virtual_classes++;
2197  subquery = mq_fetch_subqueries (parser, entity);
2198 
2199  if (subquery == NULL && er_has_error ())
2200  {
2201  if (!pt_has_error (parser))
2202  {
2203  /* Some unexpected errors (like ER_INTERRUPTED due to timeout) should be handled. */
2204  PT_ERROR (parser, entity, er_msg ());
2205  }
2206  return er_errid ();
2207  }
2208 
2209  if (subquery && subquery->node_type != PT_SELECT)
2210  {
2211  return true;
2212  }
2213  }
2214  }
2215  }
2216 
2217  if (had_some_virtual_classes > 1)
2218  return true;
2219  if (had_some_virtual_classes && had_some_real_classes)
2220  return true;
2221 
2222  return false;
2223 }
2224 
2225 /*
2226  * mq_check_authorization_path_entities() -
2227  * return: NO_ERROR on success, non-zero for ERROR
2228  * parser(in):
2229  * class_spec(in):
2230  * what_for(in):
2231  */
2232 static int
2234 {
2235  PT_NODE *path_spec, *entity;
2236  int error;
2237  bool skip_auth_check = false;
2238 
2239  error = NO_ERROR; /* init */
2240 
2241  /* check for authorization bypass: this feature should be used only for specs in SHOW statements; Note : all classes
2242  * expanded under the current spec sub-tree will be skipped by the authorization process */
2243  if (((int) class_spec->info.spec.auth_bypass_mask & what_for) == what_for)
2244  {
2245  assert (what_for != DB_AUTH_NONE);
2246  skip_auth_check = true;
2247  }
2248 
2249  /* Traverse each path list */
2250  for (path_spec = class_spec->info.spec.path_entities; path_spec != NULL; path_spec = path_spec->next)
2251  {
2252  /* Traverse entities */
2253  for (entity = path_spec->info.spec.flat_entity_list; entity != NULL; entity = entity->next)
2254  {
2255  /* check for current path */
2256  if (skip_auth_check)
2257  {
2258  continue;
2259  }
2260  error = db_check_authorization (entity->info.name.db_object, (DB_AUTH) what_for);
2261  if (error != NO_ERROR)
2262  { /* authorization fails */
2264  get_authorization_name ((DB_AUTH) what_for),
2265  db_get_class_name (entity->info.name.db_object));
2266  return error;
2267  }
2268  }
2269 
2270  /* Traverse sub-path list */
2271  error = mq_check_authorization_path_entities (parser, path_spec, what_for);
2272  if (error != NO_ERROR)
2273  { /* authorization fails */
2274  break;
2275  }
2276  }
2277 
2278  return error;
2279 }
2280 
2281 /*
2282  * mq_check_subqueries_for_prepare () -
2283  * return:
2284  * parser(in):
2285  * node(in):
2286  * subquery(in):
2287  */
2288 static int
2290 {
2291  if (node->flag.cannot_prepare == 1)
2292  {
2293  return 1;
2294  }
2295 
2296  while (subquery)
2297  {
2298  if (subquery->flag.cannot_prepare == 1)
2299  {
2300  return 1;
2301  }
2302  subquery = subquery->next;
2303  }
2304 
2305  return node->flag.cannot_prepare;
2306 }
2307 
2308 /*
2309  * mq_translate_tree() - translates a tree against a list of classes
2310  * return: PT_NODE *, parse tree with view and virtual class queries expanded
2311  * to leaf classes or local db tables/classes
2312  * parser(in):
2313  * tree(in/out):
2314  * spec_list(in):
2315  * order_by(in):
2316  * what_for(in):
2317  */
2318 static PT_NODE *
2319 mq_translate_tree (PARSER_CONTEXT * parser, PT_NODE * tree, PT_NODE * spec_list, PT_NODE * order_by, int what_for)
2320 {
2321  PT_NODE *entity;
2322  PT_NODE *class_spec;
2323  PT_NODE *subquery;
2324  PT_NODE *tree_union;
2325  PT_NODE *my_class;
2326  PT_NODE *pt_tmp;
2327  PT_NODE *real_classes;
2328  PT_NODE *real_flat_classes;
2329  PT_NODE *real_part;
2330  PT_NODE *substituted;
2331  PT_NODE *my_spec;
2332  int had_some_virtual_classes;
2333  int delete_old_node = false;
2334 
2335  /* for each table/class in class list, do leaf expansion or vclass/view expansion. */
2336 
2337  pt_tmp = tree;
2338  for (class_spec = spec_list; class_spec != NULL; class_spec = class_spec->next)
2339  {
2340  /* need to loop through entity specs! Currently, theres no way to represent the all correct results in a parse
2341  * tree or in xasl. */
2342  bool skip_auth_check = false;
2343  int update_flag = class_spec->info.spec.flag & PT_SPEC_FLAG_UPDATE;
2344  int delete_flag = class_spec->info.spec.flag & PT_SPEC_FLAG_DELETE;
2345  bool fetch_for_update;
2346  PT_FETCH_AS fetch_as = PT_NORMAL_SELECT;
2347 
2348  if ((what_for == DB_AUTH_SELECT) || (what_for == DB_AUTH_UPDATE && !update_flag)
2349  || (what_for == DB_AUTH_DELETE && !delete_flag))
2350  {
2351  /* used either in a query or an UPDATE/DELETE that does not alter the subquery */
2352  fetch_for_update = false;
2353  }
2354  else
2355  {
2356  fetch_for_update = true;
2357 
2358  if (what_for == DB_AUTH_UPDATE && tree->node_type != PT_MERGE)
2359  {
2360  /* we allow partial access for UPDATE statements */
2361  fetch_as = PT_PARTIAL_SELECT;
2362  }
2363  }
2364 
2365  had_some_virtual_classes = 0;
2366  real_classes = NULL;
2367  tree_union = NULL;
2368 
2369  if (((int) class_spec->info.spec.auth_bypass_mask & what_for) == what_for)
2370  {
2371  assert (what_for != DB_AUTH_NONE);
2372  skip_auth_check = true;
2373  }
2374 
2375  if (PT_SPEC_IS_DERIVED (class_spec))
2376  {
2377  /* no translation per se, but need to fix up proxy objects */
2378  tree = mq_fix_derived_in_union (parser, tree, class_spec->info.spec.id);
2379 
2380  /* check SELECT authorization rather than the authrization of opcode * */
2381  /* always check if one has SELECT authorization for path-expr */
2382  if (mq_check_authorization_path_entities (parser, class_spec, DB_AUTH_SELECT) != NO_ERROR)
2383  {
2384  return NULL; /* authorization fails */
2385  }
2386  }
2387  else if (class_spec->info.spec.meta_class != PT_META_CLASS
2388  && (class_spec->info.spec.derived_table_type != PT_IS_WHACKED_SPEC))
2389  {
2390  for (entity = class_spec->info.spec.flat_entity_list; entity != NULL; entity = entity->next)
2391  {
2392  if (mq_translatable_class (parser, entity) == 0
2393  || (PT_IS_SELECT (tree)
2396  {
2397  /* no translation for above cases */
2398  my_class = parser_copy_tree (parser, entity);
2399  if (!my_class)
2400  {
2401  return NULL;
2402  }
2403 
2404  /* check for authorization bypass: this feature should be used only for specs in SHOW statements;
2405  * Note : all classes expanded under the current spec sub-tree will be skipped by the authorization
2406  * process */
2407  if (!skip_auth_check
2408  && (db_check_authorization (my_class->info.name.db_object, (DB_AUTH) what_for) != NO_ERROR))
2409  {
2411  get_authorization_name ((DB_AUTH) what_for),
2412  db_get_class_name (my_class->info.name.db_object));
2413  return NULL;
2414  }
2415  my_class->next = real_classes;
2416  real_classes = my_class;
2417  }
2418  else
2419  {
2420  had_some_virtual_classes = 1;
2421 
2422  if (pt_has_error (parser))
2423  {
2424  return NULL;
2425  }
2426 
2427  if (!fetch_for_update)
2428  {
2429  subquery = mq_fetch_subqueries (parser, entity);
2430  }
2431  else
2432  {
2433  subquery = mq_fetch_subqueries_for_update (parser, entity, fetch_as, (DB_AUTH) what_for);
2434  }
2435 
2436  if (subquery != NULL)
2437  {
2438 
2439  if (tree == NULL || pt_has_error (parser))
2440  {
2441  /* an error was discovered parsing the sub query. */
2442  return NULL;
2443  }
2444 
2445  tree->flag.cannot_prepare = mq_check_subqueries_for_prepare (parser, tree, subquery);
2446 #if defined(CUBRID_DEBUG)
2447  fprintf (stdout, "\n<subqueries of %s are>\n %s\n", entity->info.name.original,
2448  parser_print_tree_list (parser, subquery));
2449 #endif /* CUBRID_DEBUG */
2450  substituted =
2451  mq_substitute_subquery_list_in_statement (parser, tree, subquery, entity, order_by, what_for);
2452 #ifdef CUBRID_DEBUG
2453  fprintf (stdout, "\n<substituted %s with subqueries is>\n %s\n", entity->info.name.original,
2454  parser_print_tree_list (parser, substituted));
2455 #endif /* CUBRID_DEBUG */
2456 
2457  if (substituted != NULL)
2458  {
2459  if (tree_union != NULL)
2460  {
2461  if (what_for == DB_AUTH_SELECT)
2462  {
2463  tree_union = mq_union_bump_correlation (parser, tree_union, substituted);
2464  if (tree_union && order_by)
2465  {
2466  tree_union->info.query.order_by = parser_copy_tree_list (parser, order_by);
2467  }
2468  }
2469  else
2470  {
2471  parser_append_node (substituted, tree_union);
2472  }
2473  }
2474  else
2475  {
2476  tree_union = substituted;
2477  }
2478  }
2479  }
2480 
2481  if (er_errid_if_has_error () != NO_ERROR || pt_has_error (parser))
2482  {
2483  return NULL;
2484  }
2485  }
2486  }
2487  /* check SELECT authorization rather than the authrization of opcode always check if one has SELECT
2488  * authorization for path-expr */
2489  if (mq_check_authorization_path_entities (parser, class_spec, DB_AUTH_SELECT) != NO_ERROR)
2490  {
2491  return NULL; /* authorization fails */
2492  }
2493  }
2494 
2495  if (had_some_virtual_classes)
2496  {
2497  delete_old_node = true;
2498  /* at least some of the classes were virtual were any "real" classes members of the class spec? */
2499  real_part = NULL;
2500  if (real_classes != NULL)
2501  {
2502  real_flat_classes = parser_copy_tree_list (parser, real_classes);
2503 
2504  for (entity = real_classes; entity != NULL; entity = entity->next)
2505  {
2506  /* finish building new entity spec */
2507  entity->info.name.resolved = NULL;
2508  }
2509 
2510  my_spec =
2511  pt_entity (parser, real_classes, parser_copy_tree (parser, class_spec->info.spec.range_var),
2512  real_flat_classes);
2513  my_spec->info.spec.id = class_spec->info.spec.id;
2514 
2515  real_part =
2516  mq_class_lambda (parser, parser_copy_tree (parser, tree), real_flat_classes, my_spec, NULL, NULL, NULL,
2517  NULL);
2518  }
2519 
2520  /* if the class spec had mixed real and virtual parts, recombine them. */
2521  if (real_part != NULL)
2522  {
2523  if (tree_union != NULL)
2524  {
2525  tree = mq_union_bump_correlation (parser, real_part, tree_union);
2526  }
2527  else
2528  {
2529  /* there were some vclasses, but all have vacuous query specs. */
2530  tree = real_part;
2531  }
2532  }
2533  else if (tree_union != NULL)
2534  {
2535  tree = tree_union;
2536  }
2537  else
2538  {
2539  if (tree && tree->node_type != PT_SELECT && tree->node_type != PT_UNION
2540  && tree->node_type != PT_DIFFERENCE && tree->node_type != PT_INTERSECTION)
2541  {
2542  tree = NULL;
2543  }
2544  }
2545  }
2546  else
2547  {
2548  /* Getting here means there were NO vclasses. all classes involved are "real" classes, so don't rewrite this
2549  * tree. */
2550  }
2551  }
2552 
2553 /*
2554  * We need to free pt_tmp at this point if the original tree pointer has
2555  * been reassgned. We can't simply parser_free_tree() the node since the new tree
2556  * may still have pointers to the lower nodes in the tree. So, we set
2557  * the NEXT pointer to NULL and then free it so the new tree is not
2558  * corrupted.
2559  */
2560  if (delete_old_node && (tree != pt_tmp))
2561  {
2562  PT_NODE_COPY_NUMBER_OUTERLINK (tree, pt_tmp);
2563  pt_tmp->next = NULL;
2564  parser_free_tree (parser, pt_tmp);
2565  }
2566 
2567  tree = mq_reset_ids_in_statement (parser, tree);
2568  return tree;
2569 }
2570 
2571 /*
2572  * mq_class_meth_corr_subq_pre() - Checks for class methods or subqueries
2573  * which are correlated level 1
2574  * return:
2575  * parser(in):
2576  * node(in):
2577  * void_arg(in):
2578  * continue_walk(in/out):
2579  */
2580 static PT_NODE *
2581 mq_class_meth_corr_subq_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
2582 {
2583  bool *found = (bool *) void_arg;
2584 
2585  if (!node || *found)
2586  return node;
2587 
2588  *continue_walk = PT_CONTINUE_WALK;
2589 
2590  if (node->node_type == PT_METHOD_CALL)
2591  {
2592  /* found class method */
2594  {
2595  *found = true;
2596  }
2597  }
2598  else if (pt_is_query (node))
2599  {
2600  /* don't dive into subqueries */
2601  *continue_walk = PT_LIST_WALK;
2602 
2603  /* found correlated subquery */
2604  if (node->info.query.correlation_level == 1)
2605  {
2606  *found = true;
2607  }
2608  }
2609  else if (pt_is_aggregate_function (parser, node))
2610  {
2611  /* don't dive into aggreate functions */
2612  *continue_walk = PT_LIST_WALK;
2613  }
2614 
2615  if (*found)
2616  {
2617  /* don't walk */
2618  *continue_walk = PT_STOP_WALK;
2619  }
2620 
2621  return node;
2622 
2623 } /* mq_class_meth_corr_subq_pre */
2624 
2625 
2626 /*
2627  * mq_has_class_methods_corr_subqueries
2628  *
2629  * Description:
2630  *
2631  * Returns true if the query contains class methods or
2632  * subqueries which are correlated level 1.
2633  */
2634 
2635 /*
2636  * mq_has_class_methods_corr_subqueries() - checks class methods or
2637  * subqueries which are correlated level 1
2638  * return: true on checked
2639  * parser(in):
2640  * node(in):
2641  */
2642 static bool
2644 {
2645  bool found = false;
2646 
2647  (void) parser_walk_tree (parser, node->info.query.q.select.list, mq_class_meth_corr_subq_pre, &found, NULL, NULL);
2648 
2649  if (!found)
2650  {
2651  (void) parser_walk_tree (parser, node->info.query.q.select.having, mq_class_meth_corr_subq_pre, &found, NULL,
2652  NULL);
2653  }
2654 
2655  return found;
2656 
2657 } /* mq_has_class_methods_corr_subqueries */
2658 
2659 
2660 /*
2661  * pt_check_pushable() - check for pushable
2662  * return:
2663  * parser(in):
2664  * tree(in):
2665  * arg(in/out):
2666  * continue_walk(in):
2667  *
2668  * Note:
2669  * subquery, method, rownum, inst_num(), orderby_num(), groupby_num()
2670  * does not pushable if we find these in corresponding item
2671  * in select_list of query
2672  */
2673 static PT_NODE *
2674 pt_check_pushable (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
2675 {
2676  CHECK_PUSHABLE_INFO *cinfop = (CHECK_PUSHABLE_INFO *) arg;
2677 
2678  if (!tree || *continue_walk == PT_STOP_WALK)
2679  {
2680  return tree;
2681  }
2682 
2683  switch (tree->node_type)
2684  {
2685  case PT_SELECT:
2686  case PT_UNION:
2687  case PT_DIFFERENCE:
2688  case PT_INTERSECTION:
2689  if (cinfop->check_query)
2690  {
2691  cinfop->query_found = true; /* not pushable */
2692  }
2693  break;
2694 
2695  case PT_METHOD_CALL:
2696  if (cinfop->check_method)
2697  {
2698  cinfop->method_found = true; /* not pushable */
2699  }
2700  break;
2701 
2702  case PT_EXPR:
2703  if (tree->info.expr.op == PT_ROWNUM || tree->info.expr.op == PT_INST_NUM || tree->info.expr.op == PT_ORDERBY_NUM)
2704  {
2705  if (cinfop->check_xxxnum)
2706  {
2707  cinfop->xxxnum_found = true; /* not pushable */
2708  }
2709  }
2710  break;
2711 
2712  case PT_FUNCTION:
2714  {
2715  if (cinfop->check_xxxnum)
2716  {
2717  cinfop->xxxnum_found = true; /* not pushable */
2718  }
2719  }
2720  else if (tree->info.function.analytic.is_analytic == true)
2721  {
2722  if (cinfop->check_analytic)
2723  {
2724  cinfop->analytic_found = true; /* not pushable */
2725  }
2726  }
2727  break;
2728 
2729  default:
2730  break;
2731  } /* switch (tree->node_type) */
2732 
2733  if (cinfop->query_found || cinfop->method_found || cinfop->xxxnum_found || cinfop->analytic_found)
2734  {
2735  /* not pushable */
2736  /* do not need to traverse anymore */
2737  *continue_walk = PT_STOP_WALK;
2738  }
2739 
2740  return tree;
2741 }
2742 
2743 /*
2744  * pt_pushable_query_in_pos() -
2745  * return: true on pushable query
2746  * parser(in):
2747  * query(in):
2748  * pos(in):
2749  */
2750 static bool
2752 {
2753  bool pushable = false; /* guess as not pushable */
2754 
2755  switch (query->node_type)
2756  {
2757  case PT_SELECT:
2758  {
2759  CHECK_PUSHABLE_INFO cinfo;
2760  PT_NODE *list;
2761  int i;
2762 
2763  /* Traverse select list */
2764  for (list = query->info.query.q.select.list, i = 0; list; list = list->next, i++)
2765  {
2766  /* init */
2767  cinfo.check_query = (i == pos) ? true : false;
2768  cinfo.check_method = (i == pos) ? true : false;
2769  cinfo.check_xxxnum = true; /* always check */
2770  cinfo.check_analytic = (i == pos) ? true : false;
2771 
2772  cinfo.query_found = false;
2773  cinfo.method_found = false;
2774  cinfo.xxxnum_found = false;
2775  cinfo.analytic_found = false;
2776 
2777  switch (list->node_type)
2778  {
2779  case PT_SELECT:
2780  case PT_UNION:
2781  case PT_DIFFERENCE:
2782  case PT_INTERSECTION:
2783  if (i == pos)
2784  {
2785  cinfo.query_found = true; /* not pushable */
2786  }
2787  break;
2788 
2789  case PT_METHOD_CALL:
2790  if (i == pos)
2791  {
2792  cinfo.method_found = true; /* not pushable */
2793  }
2794  break;
2795 
2796  case PT_EXPR:
2797  /* always check for rownum, inst_num(), orderby_num() */
2798  if (list->info.expr.op == PT_ROWNUM || list->info.expr.op == PT_INST_NUM
2799  || list->info.expr.op == PT_ORDERBY_NUM)
2800  {
2801  cinfo.xxxnum_found = true; /* not pushable */
2802  }
2803  else
2804  { /* do traverse */
2805  parser_walk_leaves (parser, list, pt_check_pushable, &cinfo, NULL, NULL);
2806  }
2807  break;
2808 
2809  case PT_FUNCTION:
2810  /* always check for groupby_num() */
2812  {
2813  cinfo.xxxnum_found = true; /* not pushable */
2814  }
2815  else if (list->info.function.analytic.is_analytic == true)
2816  {
2817  cinfo.analytic_found = true; /* not pushable */
2818  }
2819  else
2820  { /* do traverse */
2821  parser_walk_leaves (parser, list, pt_check_pushable, &cinfo, NULL, NULL);
2822  }
2823  break;
2824 
2825  default: /* do traverse */
2826  parser_walk_leaves (parser, list, pt_check_pushable, &cinfo, NULL, NULL);
2827  break;
2828  } /* switch (list->node_type) */
2829 
2830  /* check for subquery, method, rownum, inst_num(), orderby_num(), groupby_num(): does not pushable if we
2831  * find these in corresponding item in select_list of query */
2832  if (cinfo.query_found || cinfo.method_found || cinfo.xxxnum_found || cinfo.analytic_found)
2833  {
2834  break; /* not pushable */
2835  }
2836 
2837  } /* for (list = ...) */
2838 
2839  if (list == NULL)
2840  { /* check all select list */
2841  pushable = true; /* OK */
2842  }
2843  }
2844  break;
2845 
2846  case PT_UNION:
2847  case PT_DIFFERENCE:
2848  case PT_INTERSECTION:
2849  if (pt_pushable_query_in_pos (parser, query->info.query.q.union_.arg1, pos)
2850  && pt_pushable_query_in_pos (parser, query->info.query.q.union_.arg2, pos))
2851  {
2852  pushable = true; /* OK */
2853  }
2854  break;
2855 
2856  default: /* should not get here, that is an error! */
2857 #if defined(CUBRID_DEBUG)
2858  fprintf (stdout, "Illegal parse node type %d, in %s, at line %d. \n", query->node_type, __FILE__, __LINE__);
2859 #endif /* CUBRID_DEBUG */
2860  break;
2861  } /* switch (query->node_type) */
2862 
2863  return pushable;
2864 }
2865 
2866 /*
2867  * pt_find_only_name_id() - returns true if node name with the given
2868  * spec id is found
2869  * return:
2870  * parser(in):
2871  * tree(in):
2872  * arg(in/out):
2873  * continue_walk(in):
2874  */
2875 static PT_NODE *
2876 pt_find_only_name_id (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
2877 {
2878  FIND_ID_INFO *infop = (FIND_ID_INFO *) arg;
2879  PT_NODE *spec, *node = tree;
2880 
2881  /* do not need to traverse anymore */
2882  if (!tree || *continue_walk == PT_STOP_WALK)
2883  {
2884  return tree;
2885  }
2886 
2887  switch (node->node_type)
2888  {
2889  case PT_SELECT:
2890  case PT_UNION:
2891  case PT_DIFFERENCE:
2892  case PT_INTERSECTION:
2893  /* simply give up when we find query in predicate refer QA fixed/fderiv3.sql:line165 */
2894  infop->out.others_found = true;
2895  break;
2896 
2897  case PT_METHOD_CALL:
2898  /* simply give up when we find method in predicate */
2899  infop->out.others_found = true;
2900  break;
2901 
2902  case PT_DOT_:
2903  /* only check left side of DOT expression, right side is of no interest */
2904  *continue_walk = PT_LIST_WALK;
2905 
2906  do
2907  {
2908  node = node->info.dot.arg1;
2909  }
2910  while (node && node->node_type == PT_DOT_);
2911 
2912  if (node == NULL)
2913  {
2914  /* nothing found ... */
2915  break;
2916  }
2917  /* FALLTHRU */
2918 
2919  case PT_NAME:
2920  spec = infop->in.spec;
2921  /* match specified spec */
2922  if (node->info.name.spec_id == spec->info.spec.id)
2923  {
2924  infop->out.found = true;
2925  /* check for subquery, method: does not pushable if we find subquery, method in corresponding item in
2926  * select_list of query */
2927  if (infop->out.pushable)
2928  {
2929  PT_NODE *attr, *query;
2930  UINTPTR save_spec_id;
2931  int i;
2932 
2933  for (attr = infop->in.attr_list, i = 0; attr; attr = attr->next, i++)
2934  {
2935 
2936  if (attr->node_type != PT_NAME)
2937  {
2938  attr = NULL; /* unknown error */
2939  break;
2940  }
2941 
2942  save_spec_id = attr->info.name.spec_id; /* save */
2943  attr->info.name.spec_id = node->info.name.spec_id;
2944 
2945  /* found match in as_attr_list */
2946  if (pt_name_equal (parser, node, attr))
2947  {
2948  /* check for each query */
2949  for (query = infop->in.query_list; query && infop->out.pushable; query = query->next)
2950  {
2951  infop->out.pushable = pt_pushable_query_in_pos (parser, query, i);
2952  } /* for (query = ... ) */
2953  break;
2954  }
2955 
2956  attr->info.name.spec_id = save_spec_id; /* restore */
2957  } /* for (attr = ... ) */
2958 
2959  if (!attr)
2960  {
2961  /* impossible case. simply give up */
2962  infop->out.pushable = false;
2963  }
2964  }
2965  }
2966  else
2967  {
2968  /* check for other spec */
2969  for (spec = infop->in.others_spec_list; spec; spec = spec->next)
2970  {
2971  if (node->info.name.spec_id == spec->info.spec.id)
2972  {
2973  infop->out.others_found = true;
2974  break;
2975  }
2976  }
2977 
2978  /* not found in other spec */
2979  if (!spec)
2980  {
2981  /* is correlated other spec */
2982  infop->out.correlated_found = true;
2983  }
2984  }
2985  break;
2986 
2987  case PT_EXPR:
2988  /* simply give up when we find rownum, inst_num(), orderby_num() in predicate */
2989  if (node->info.expr.op == PT_ROWNUM || node->info.expr.op == PT_INST_NUM || node->info.expr.op == PT_ORDERBY_NUM)
2990  {
2991  infop->out.others_found = true;
2992  }
2993  break;
2994 
2995  case PT_FUNCTION:
2996  /* simply give up when we find groupby_num() in predicate */
2998  {
2999  infop->out.others_found = true;
3000  }
3001  break;
3002 
3003  case PT_DATA_TYPE:
3004  /* don't walk data type */
3005  *continue_walk = PT_LIST_WALK;
3006  break;
3007 
3008  default:
3009  break;
3010  } /* switch (node->node_type) */
3011 
3012  if (infop->out.others_found)
3013  {
3014  /* do not need to traverse anymore */
3015  *continue_walk = PT_STOP_WALK;
3016  }
3017 
3018  return tree;
3019 }
3020 
3021 /*
3022  * pt_sargable_term() -
3023  * return:
3024  * parser(in):
3025  * term(in): CNF expression
3026  * infop(in):
3027  */
3028 static bool
3030 {
3031  /* init output section */
3032  infop->out.found = false;
3033  infop->out.others_found = false;
3034  infop->out.correlated_found = false;
3035  infop->out.pushable = true; /* guess as true */
3036 
3037  parser_walk_leaves (parser, term, pt_find_only_name_id, infop, NULL, NULL);
3038 
3039  return infop->out.found && !infop->out.others_found;
3040 }
3041 
3042 /*
3043  * pt_check_copypush_subquery () - check derived subquery to push sargable term
3044  * into the derived subquery
3045  * return:
3046  * parser(in):
3047  * query(in):
3048  *
3049  * Note:
3050  * assumes cnf conversion is done
3051  */
3052 static int
3054 {
3055  int copy_cnt;
3056 
3057  if (query == NULL)
3058  {
3059  return 0;
3060  }
3061 
3062  /* init */
3063  copy_cnt = 0;
3064 
3065  switch (query->node_type)
3066  {
3067  case PT_SELECT:
3068  if (query->info.query.order_by && query->info.query.orderby_for)
3069  {
3070  copy_cnt++; /* found not-pushable query */
3071  }
3072  else if (pt_has_aggregate (parser, query) && query->info.query.q.select.group_by == NULL)
3073  {
3074  copy_cnt++; /* found not-pushable query */
3075  }
3076  break;
3077 
3078  case PT_UNION:
3079  case PT_DIFFERENCE:
3080  case PT_INTERSECTION:
3081  copy_cnt += pt_check_copypush_subquery (parser, query->info.query.q.union_.arg1);
3082  copy_cnt += pt_check_copypush_subquery (parser, query->info.query.q.union_.arg2);
3083  break;
3084 
3085  default:
3086  break;
3087  }
3088 
3089  return copy_cnt;
3090 }
3091 
3092 /*
3093  * pt_copypush_terms() - push sargable term into the derived subquery
3094  * return:
3095  * parser(in):
3096  * spec(in):
3097  * query(in/out):
3098  * term_list(in):
3099  * type(in):
3100  *
3101  * Note:
3102  * assumes cnf conversion is done
3103  */
3104 static void
3106 {
3107  PT_NODE *push_term_list;
3108 
3109  if (query == NULL || term_list == NULL)
3110  {
3111  return;
3112  }
3113 
3114  switch (query->node_type)
3115  {
3116  case PT_SELECT:
3117  /* copy terms */
3118  push_term_list = parser_copy_tree_list (parser, term_list);
3119 
3120  /* substitute as_attr_list's columns for select_list's columns in search condition */
3121  if (type == FIND_ID_INLINE_VIEW)
3122  {
3123  push_term_list =
3124  mq_lambda (parser, push_term_list, spec->info.spec.as_attr_list, query->info.query.q.select.list);
3125  }
3126 
3127  /* copy and put it in query's search condition */
3128  if (query->info.query.order_by && query->info.query.orderby_for)
3129  {
3130  ;
3131  }
3132  else
3133  {
3134  if (pt_has_aggregate (parser, query))
3135  {
3136  if (query->info.query.q.select.group_by)
3137  {
3138  /* push into HAVING clause */
3139  query->info.query.q.select.having =
3140  parser_append_node (push_term_list, query->info.query.q.select.having);
3141  }
3142  }
3143  else
3144  {
3145  /* push into WHERE clause */
3146  query->info.query.q.select.where = parser_append_node (push_term_list, query->info.query.q.select.where);
3147  }
3148  }
3149  break;
3150 
3151  case PT_UNION:
3152  case PT_DIFFERENCE:
3153  case PT_INTERSECTION:
3154  (void) pt_copypush_terms (parser, spec, query->info.query.q.union_.arg1, term_list, type);
3155  (void) pt_copypush_terms (parser, spec, query->info.query.q.union_.arg2, term_list, type);
3156  break;
3157 
3158  default:
3159  break;
3160  } /* switch (query->node_type) */
3161 
3162  return;
3163 }
3164 
3165 /*
3166  * mq_copypush_sargable_terms_helper() -
3167  * return:
3168  * parser(in):
3169  * statement(in):
3170  * spec(in):
3171  * new_query(in/out):
3172  * infop(in):
3173  */
3174 static int
3176  FIND_ID_INFO * infop)
3177 {
3178  PT_NODE *term, *new_term, *push_term_list;
3179  int push_cnt, push_correlated_cnt, copy_cnt;
3180  PT_NODE *temp;
3181  int nullable_cnt; /* nullable terms count */
3182  PT_NODE *save_next;
3183  bool is_afterjoinable;
3184 
3185  /* init */
3186  push_term_list = NULL;
3187  push_cnt = 0;
3188  push_correlated_cnt = 0;
3189 
3190  copy_cnt = -1;
3191 
3192  if (PT_IS_QUERY (new_query)
3193  && (pt_has_analytic (parser, new_query) || PT_SELECT_INFO_IS_FLAGED (new_query, PT_SELECT_INFO_COLS_SCHEMA)
3195  {
3196  /* don't copy push terms if target query has analytic functions */
3197  return push_cnt;
3198  }
3199 
3200  for (term = statement->info.query.q.select.where; term; term = term->next)
3201  {
3202  /* check for nullable-term */
3203  if (term->node_type == PT_EXPR)
3204  {
3205  save_next = term->next;
3206  term->next = NULL; /* cut-off link */
3207 
3208  nullable_cnt = 0; /* init */
3209  (void) parser_walk_tree (parser, term, NULL, NULL, qo_check_nullable_expr, &nullable_cnt);
3210 
3211  term->next = save_next; /* restore link */
3212 
3213  if (nullable_cnt)
3214  {
3215  continue; /* do not copy-push nullable-term */
3216  }
3217  }
3218  if (pt_sargable_term (parser, term, infop) && PT_PUSHABLE_TERM (infop))
3219  {
3220  /* copy term */
3221  new_term = parser_copy_tree (parser, term);
3222  /* for term, mark as copy-pushed term */
3223  if (term->node_type == PT_EXPR)
3224  {
3225  /* check for after-join term */
3226  is_afterjoinable = false; /* init */
3227  for (temp = spec; temp; temp = temp->next)
3228  {
3229  if (temp->info.spec.join_type == PT_JOIN_LEFT_OUTER
3231  || temp->info.spec.join_type == PT_JOIN_FULL_OUTER)
3232  {
3233  is_afterjoinable = true;
3234  break;
3235  }
3236  }
3237 
3238  if (is_afterjoinable)
3239  {
3240  ; /* may be after-join term. give up */
3241  }
3242  else
3243  {
3244  if (copy_cnt == -1) /* very the first time */
3245  {
3246  copy_cnt = pt_check_copypush_subquery (parser, new_query);
3247  }
3248 
3249  if (copy_cnt == 0) /* not found not-pushable query */
3250  {
3252  }
3253  }
3254 
3256  }
3257  push_term_list = parser_append_node (new_term, push_term_list);
3258 
3259  push_cnt++;
3260  if (infop->out.correlated_found)
3261  {
3262  push_correlated_cnt++;
3263  }
3264  }
3265  } /* for (term = ...) */
3266 
3267  if (push_cnt)
3268  {
3269  /* copy and push term in new_query's search condition */
3270  (void) pt_copypush_terms (parser, spec, new_query, push_term_list, infop->type);
3271 
3272  if (push_correlated_cnt)
3273  {
3274  /* set correlation level */
3275  if (new_query->info.query.correlation_level == 0)
3276  {
3277  new_query->info.query.correlation_level = statement->info.query.correlation_level + 1;
3278  }
3279  }
3280 
3281  /* free alloced */
3282  parser_free_tree (parser, push_term_list);
3283  }
3284 
3285  return push_cnt;
3286 }
3287 
3288 /*
3289  * mq_copypush_sargable_terms() -
3290  * return:
3291  * parser(in):
3292  * statement(in):
3293  * spec(in):
3294  */
3295 static int
3297 {
3298  PT_NODE *derived_table;
3299  int push_cnt = 0; /* init */
3300  FIND_ID_INFO info;
3301 
3302  if (statement->node_type == PT_SELECT
3303  /* never do copy-push optimization for a hierarchical query */
3305  && (derived_table = spec->info.spec.derived_table) && PT_IS_QUERY (derived_table)
3307  {
3308  info.type = FIND_ID_INLINE_VIEW; /* inline view */
3309  /* init input section */
3310  info.in.spec = spec;
3311  info.in.others_spec_list = statement->info.query.q.select.from;
3312  info.in.attr_list = spec->info.spec.as_attr_list;
3313  info.in.query_list = derived_table;
3314 
3315  push_cnt = mq_copypush_sargable_terms_helper (parser, statement, spec, derived_table, &info);
3316  }
3317 
3318  return push_cnt;
3319 }
3320 
3321 /*
3322  * mq_rewrite_vclass_spec_as_derived() -
3323  * return: rewritten SPEC with spec as simple derived select subquery
3324  * parser(in):
3325  * statement(in):
3326  * spec(in):
3327  * query_spec(in):
3328  */
3329 static PT_NODE *
3331 {
3332  PT_NODE *new_query = parser_new_node (parser, PT_SELECT);
3333  PT_NODE *new_spec;
3334  PT_NODE *v_attr_list, *v_attr;
3335  PT_NODE *from, *entity_name;
3336  FIND_ID_INFO info;
3337  PT_NODE *col;
3338  bool is_value_query = false;
3339  PT_NODE *attrs = NULL;
3340 
3341  if (new_query == NULL)
3342  {
3343  PT_INTERNAL_ERROR (parser, "allocate new node");
3344  return NULL;
3345  }
3346 
3347  /* mark as a derived vclass spec query */
3348  new_query->info.query.flag.vspec_as_derived = 1;
3349 
3350  if (query_spec != NULL && PT_IS_VALUE_QUERY (query_spec))
3351  {
3352  is_value_query = true;
3353  }
3354 
3355  if (is_value_query)
3356  {
3357  new_query->flag.is_value_query = 1;
3358 
3359  attrs = mq_fetch_attributes (parser, spec->info.spec.flat_entity_list);
3360  if (attrs == NULL && (pt_has_error (parser) || er_has_error ()))
3361  {
3362  return NULL;
3363  }
3364 
3365  attrs = parser_copy_tree_list (parser, attrs);
3366 
3367  if (attrs != NULL && attrs->type_enum == PT_TYPE_OBJECT)
3368  {
3369  attrs = attrs->next; /* skip oid */
3370 
3371  /* copy node_list value query list has nothing to do with table attributes */
3372  new_query->info.query.q.select.list = parser_copy_tree_list (parser, query_spec->info.query.q.select.list);
3373  }
3374  }
3375  else
3376  {
3377  new_query->info.query.q.select.list = mq_get_references (parser, statement, spec);
3378 
3379  for (col = new_query->info.query.q.select.list; col; col = col->next)
3380  {
3381  if (col->flag.is_hidden_column)
3382  {
3383  col->flag.is_hidden_column = 0;
3384  }
3385  }
3386 
3387  v_attr_list = mq_fetch_attributes (parser, spec->info.spec.flat_entity_list);
3388  if (v_attr_list == NULL && (pt_has_error (parser) || er_has_error ()))
3389  {
3390  return NULL;
3391  }
3392 
3393  v_attr_list = parser_copy_tree_list (parser, v_attr_list);
3394 
3395  /* exclude the first oid attr, append non-exist attrs to select list */
3396  if (v_attr_list && v_attr_list->type_enum == PT_TYPE_OBJECT)
3397  {
3398  v_attr_list = v_attr_list->next; /* skip oid attr */
3399  }
3400 
3401  for (v_attr = v_attr_list; v_attr; v_attr = v_attr->next)
3402  {
3403  v_attr->info.name.spec_id = spec->info.spec.id; /* init spec id */
3404  mq_insert_symbol (parser, &new_query->info.query.q.select.list, v_attr);
3405  } /* for (v_attr = ...) */
3406 
3407  /* free alloced */
3408  if (v_attr_list)
3409  {
3410  parser_free_tree (parser, v_attr_list);
3411  }
3412  }
3413 
3414  new_spec = parser_copy_tree (parser, spec);
3415  if (new_spec == NULL)
3416  {
3417  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
3418  return NULL;
3419  }
3420 
3421  new_query->info.query.q.select.from = new_spec;
3422  new_query->info.query.is_subquery = PT_IS_SUBQUERY;
3423  new_query->flag.cannot_prepare = statement->flag.cannot_prepare;
3424 
3425  /* free path entities, which will be handled by push_path */
3426  parser_free_tree (parser, new_spec->info.spec.path_entities);
3427  new_spec->info.spec.path_entities = NULL;
3428  /* remove outer join info, which is included in the spec too */
3429  new_spec->info.spec.join_type = PT_JOIN_NONE;
3430  parser_free_tree (parser, new_spec->info.spec.on_cond);
3431  new_spec->info.spec.on_cond = NULL;
3432 
3433  /* free old class spec stuff */
3434  parser_free_tree (parser, spec->info.spec.flat_entity_list);
3435  spec->info.spec.flat_entity_list = NULL;
3436  parser_free_tree (parser, spec->info.spec.except_list);
3437  spec->info.spec.except_list = NULL;
3438  parser_free_tree (parser, spec->info.spec.entity_name);
3439  spec->info.spec.entity_name = NULL;
3440 
3441  if (is_value_query)
3442  {
3443  for (v_attr = attrs; v_attr != NULL; v_attr = v_attr->next)
3444  {
3445  v_attr->info.name.spec_id = spec->info.spec.id;
3446  mq_insert_symbol (parser, &spec->info.spec.as_attr_list, v_attr);
3447  }
3448 
3449  parser_free_tree (parser, attrs);
3450  }
3451  else
3452  {
3453  spec->info.spec.as_attr_list = parser_copy_tree_list (parser, new_query->info.query.q.select.list);
3454  }
3457 
3458  /* move sargable terms */
3459  if ((statement->node_type == PT_SELECT) && (from = new_query->info.query.q.select.from)
3460  && (entity_name = from->info.spec.entity_name) && (entity_name->node_type != PT_SPEC))
3461  {
3462  info.type = FIND_ID_VCLASS; /* vclass */
3463  /* init input section */
3464  info.in.spec = spec;
3465  info.in.others_spec_list = statement->info.query.q.select.from;
3466  info.in.attr_list = mq_fetch_attributes (parser, entity_name);
3467  if (info.in.attr_list == NULL && (pt_has_error (parser) || er_has_error ()))
3468  {
3469  return NULL;
3470  }
3471 
3472  if (query_spec)
3473  {
3474  /* check only specified query spec of the vclass */
3475  info.in.query_list = query_spec;
3476  }
3477  else
3478  {
3479  /* check all query spec of the vclass */
3480  info.in.query_list = mq_fetch_subqueries (parser, entity_name);
3481  }
3482 
3483  (void) mq_copypush_sargable_terms_helper (parser, statement, spec, new_query, &info);
3484  }
3485 
3486  if (PT_IS_SELECT (query_spec) && query_spec->info.query.q.select.connect_by)
3487  {
3488  /* query spec of the vclass is hierarchical */
3489  new_query->info.query.q.select.connect_by =
3490  parser_copy_tree_list (parser, query_spec->info.query.q.select.connect_by);
3491  new_query->info.query.q.select.start_with =
3492  parser_copy_tree_list (parser, query_spec->info.query.q.select.start_with);
3493  new_query->info.query.q.select.after_cb_filter =
3494  parser_copy_tree_list (parser, query_spec->info.query.q.select.after_cb_filter);
3495  new_query->info.query.q.select.check_cycles = query_spec->info.query.q.select.check_cycles;
3496  new_query->info.query.q.select.single_table_opt = query_spec->info.query.q.select.single_table_opt;
3497  }
3498 
3499  new_query = mq_reset_ids_and_references (parser, new_query, new_spec);
3500 
3501  spec->info.spec.derived_table = new_query;
3502 
3503  return spec;
3504 }
3505 
3506 /*
3507  * mq_rewrite_query_as_derived () -
3508  * return: rewritten select statement with derived table subquery
3509  * parser(in):
3510  * query(in):
3511  *
3512  * Note: returned result depends on global schema state.
3513  * It was qo_rewrite_query_as_derived and moved to here to be public.
3514  */
3515 PT_NODE *
3517 {
3518  PT_NODE *new_query = NULL, *derived = NULL;
3519  PT_NODE *range = NULL, *spec = NULL, *temp, *node = NULL;
3520  PT_NODE **head;
3521  int i = 0;
3522 
3523  /* set line number to range name */
3524  range = pt_name (parser, "d3201");
3525  if (range == NULL)
3526  {
3527  PT_INTERNAL_ERROR (parser, "allocate new node");
3528  goto exit_on_error;
3529  }
3530 
3531  /* construct new spec We are now copying the query and updating the spec_id references */
3532  spec = parser_new_node (parser, PT_SPEC);
3533  if (spec == NULL)
3534  {
3535  PT_INTERNAL_ERROR (parser, "allocate new node");
3536  goto exit_on_error;
3537  }
3538 
3539  derived = parser_copy_tree (parser, query);
3540  derived = mq_reset_ids_in_statement (parser, derived);
3541 
3542  /* increase correlation level of the query */
3543  if (derived != NULL && query->info.query.correlation_level)
3544  {
3545  derived = mq_bump_correlation_level (parser, derived, 1, derived->info.query.correlation_level);
3546  }
3547 
3548  spec->info.spec.derived_table = derived;
3549  spec->info.spec.derived_table_type = PT_IS_SUBQUERY;
3550  spec->info.spec.range_var = range;
3551  spec->info.spec.id = (UINTPTR) spec;
3552  range->info.name.spec_id = (UINTPTR) spec;
3553 
3554  new_query = parser_new_node (parser, PT_SELECT);
3555  if (new_query == NULL)
3556  {
3557  PT_INTERNAL_ERROR (parser, "allocate new node");
3558  goto exit_on_error;
3559  }
3560 
3561  if (query->info.query.correlation_level)
3562  {
3564  }
3565 
3566  new_query->info.query.q.select.from = spec;
3567  new_query->info.query.is_subquery = query->info.query.is_subquery;
3568 
3569 
3570  temp = pt_get_select_list (parser, spec->info.spec.derived_table);
3571  head = &new_query->info.query.q.select.list;
3572 
3573  while (temp)
3574  {
3575  /* generate as_attr_list */
3576  if (temp->node_type == PT_NAME && temp->info.name.original != NULL)
3577  {
3578  /* we have the original name */
3579  node = pt_name (parser, temp->info.name.original);
3580  }
3581  else
3582  {
3583  /* don't have name for attribute; generate new name */
3584  node = pt_name (parser, mq_generate_name (parser, "a", &i));
3585  }
3586 
3587  if (node == NULL)
3588  {
3589  PT_INTERNAL_ERROR (parser, "allocate new node");
3590  goto exit_on_error;
3591  }
3592  /* set line, column number */
3593  node->line_number = temp->line_number;
3594  node->column_number = temp->column_number;
3595 
3596  node->info.name.meta_class = PT_NORMAL;
3597  node->info.name.resolved = range->info.name.original;
3598  node->info.name.spec_id = spec->info.spec.id;
3599  node->type_enum = temp->type_enum;
3600  node->data_type = parser_copy_tree (parser, temp->data_type);
3601  spec->info.spec.as_attr_list = parser_append_node (node, spec->info.spec.as_attr_list);
3602  /* keep out hidden columns from derived select list */
3603  if (query->info.query.order_by && temp->flag.is_hidden_column)
3604  {
3605  temp->flag.is_hidden_column = 0;
3606  }
3607  else
3608  {
3609  if (temp->node_type == PT_NAME && temp->info.name.meta_class == PT_SHARED)
3610  {
3611  /* This should not get lambda replaced during translation. Copy this node as-is rather than rewriting. */
3612  *head = parser_copy_tree (parser, temp);
3613  }
3614  else
3615  {
3616  *head = parser_copy_tree (parser, node);
3617  }
3618  head = &((*head)->next);
3619  }
3620 
3621  temp = temp->next;
3622  }
3623 
3624  /* move query id # */
3625  new_query->info.query.id = query->info.query.id;
3626  new_query->flag.recompile = query->flag.recompile;
3627  query->info.query.id = 0;
3628 
3629  return new_query;
3630 
3631 exit_on_error:
3632 
3633  if (node != NULL)
3634  {
3635  parser_free_node (parser, node);
3636  }
3637  if (new_query != NULL)
3638  {
3639  parser_free_node (parser, new_query);
3640  }
3641  if (derived != NULL)
3642  {
3643  parser_free_node (parser, derived);
3644  }
3645  if (spec != NULL)
3646  {
3647  parser_free_node (parser, spec);
3648  }
3649  if (range != NULL)
3650  {
3651  parser_free_node (parser, range);
3652  }
3653  return NULL;
3654 }
3655 
3656 /*
3657  * mq_rewrite_aggregate_as_derived() -
3658  * return: rewritten select statement with derived table
3659  * subquery to form accumulation on
3660  * parser(in):
3661  * agg_sel(in):
3662  */
3663 PT_NODE *
3665 {
3666  PT_NODE *derived, *range, *spec;
3667  PT_AGG_REWRITE_INFO info;
3668  PT_NODE *col, *tmp, *as_attr_list;
3669  int idx;
3670 
3671  /* create new subquery as derived */
3672  derived = parser_new_node (parser, PT_SELECT);
3673 
3674  if (derived == NULL)
3675  {
3676  PT_INTERNAL_ERROR (parser, "allocate new node");
3677  return NULL;
3678  }
3679 
3680  /* move hint, from, where, group_by, using_index part over */
3681  derived->info.query.q.select.hint = agg_sel->info.query.q.select.hint;
3682  agg_sel->info.query.q.select.hint = PT_HINT_NONE;
3683 
3684  derived->info.query.q.select.ordered = agg_sel->info.query.q.select.ordered;
3685  agg_sel->info.query.q.select.ordered = NULL;
3686 
3687  derived->info.query.q.select.use_nl = agg_sel->info.query.q.select.use_nl;
3688  agg_sel->info.query.q.select.use_nl = NULL;
3689 
3690  derived->info.query.q.select.use_idx = agg_sel->info.query.q.select.use_idx;
3691  agg_sel->info.query.q.select.use_idx = NULL;
3692 
3693  derived->info.query.q.select.index_ss = agg_sel->info.query.q.select.index_ss;
3694  agg_sel->info.query.q.select.index_ss = NULL;
3695 
3696  derived->info.query.q.select.index_ls = agg_sel->info.query.q.select.index_ls;
3697  agg_sel->info.query.q.select.index_ls = NULL;
3698 
3699  derived->info.query.q.select.use_merge = agg_sel->info.query.q.select.use_merge;
3700  agg_sel->info.query.q.select.use_merge = NULL;
3701 
3702  derived->info.query.q.select.from = agg_sel->info.query.q.select.from;
3703  agg_sel->info.query.q.select.from = NULL;
3704 
3705  derived->info.query.q.select.where = agg_sel->info.query.q.select.where;
3706  /* move original group_by to where in place */
3707  agg_sel->info.query.q.select.where = agg_sel->info.query.q.select.having;
3708  agg_sel->info.query.q.select.having = NULL;
3709 
3710  derived->info.query.q.select.group_by = agg_sel->info.query.q.select.group_by;
3711  agg_sel->info.query.q.select.group_by = NULL;
3712  /* move agg flag */
3715 
3716  derived->info.query.q.select.using_index = agg_sel->info.query.q.select.using_index;
3717  agg_sel->info.query.q.select.using_index = NULL;
3718 
3719  /* if the original statment is a merge, the new derived table becomes a merge and the outer select becomes a plain
3720  * vanilla select. */
3721  derived->info.query.q.select.flavor = agg_sel->info.query.q.select.flavor;
3722  agg_sel->info.query.q.select.flavor = PT_USER_SELECT;
3723 
3724  /* set correlation level */
3726  if (derived->info.query.correlation_level)
3727  {
3728  derived = mq_bump_correlation_level (parser, derived, 1, derived->info.query.correlation_level);
3729  }
3730 
3731  /* derived tables are always subqueries */
3732  derived->info.query.is_subquery = PT_IS_SUBQUERY;
3733  derived->flag.cannot_prepare = agg_sel->flag.cannot_prepare;
3734 
3735  /* move spec over */
3736  info.from = derived->info.query.q.select.from;
3737  info.derived_select = derived;
3738  info.select_stack = pt_pointer_stack_push (parser, NULL, derived);
3739 
3740  /* set derived range variable */
3741  range = parser_copy_tree (parser, info.from->info.spec.range_var);
3742  if (range == NULL)
3743  {
3744  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
3745  return NULL;
3746  }
3747 
3748 
3749  /* construct new spec */
3750  spec = parser_new_node (parser, PT_SPEC);
3751  if (spec == NULL)
3752  {
3753  PT_INTERNAL_ERROR (parser, "allocate new node");
3754  return NULL;
3755  }
3756 
3757  spec->info.spec.derived_table = derived;
3759  spec->info.spec.range_var = range;
3760  spec->info.spec.id = (UINTPTR) spec;
3761  range->info.name.spec_id = (UINTPTR) spec;
3762  info.new_from = spec;
3763 
3764  /* construct derived select list, convert agg_select names and paths */
3765  info.depth = 0; /* init */
3766  agg_sel->info.query.q.select.list =
3768  &info);
3769 
3770  info.depth = 0; /* init */
3771  agg_sel->info.query.q.select.where =
3772  parser_walk_tree (parser, agg_sel->info.query.q.select.where, mq_rewrite_agg_names, &info,
3773  mq_rewrite_agg_names_post, &info);
3774 
3775  /* cleanup */
3776  (void) pt_pointer_stack_pop (parser, info.select_stack, NULL);
3777 
3778  if (!derived->info.query.q.select.list)
3779  {
3780  /* we are doing something without names. Must be count(*) */
3781  derived->info.query.q.select.list = pt_resolve_star (parser, derived->info.query.q.select.from, NULL);
3782 
3783  /* reconstruct as_attr_list */
3784  idx = 0;
3785  as_attr_list = NULL;
3786  for (col = derived->info.query.q.select.list; col; col = col->next)
3787  {
3788  tmp = pt_name (parser, mq_generate_name (parser, "a", &idx));
3789  tmp->info.name.meta_class = PT_NORMAL;
3790  tmp->info.name.resolved = range->info.name.original;
3791  tmp->info.name.spec_id = spec->info.spec.id;
3792  tmp->type_enum = col->type_enum;
3793  tmp->data_type = parser_copy_tree (parser, col->data_type);
3794  as_attr_list = parser_append_node (tmp, as_attr_list);
3795  }
3796 
3797  spec->info.spec.as_attr_list = as_attr_list;
3798  }
3799 
3800  agg_sel->info.query.q.select.from = spec;
3801 
3802  return agg_sel;
3803 }
3804 
3805 /*
3806  * mq_translate_select() - recursively expands each sub-query in the where part
3807  * Then it expands this select statement against the classes which
3808  * appear in the from list
3809  * return: translated parse tree
3810  * parser(in):
3811  * select_statement(in):
3812  */
3813 static PT_NODE *
3815 {
3816  PT_NODE *from;
3817  PT_NODE *order_by = NULL;
3818  PT_NODE *into = NULL;
3819  PT_NODE *tree = NULL;
3820  PT_MISC_TYPE all_distinct = PT_ALL;
3821  int unique = 0;
3822 
3823  if (select_statement)
3824  {
3825  from = select_statement->info.query.q.select.from;
3826 
3827  order_by = select_statement->info.query.order_by;
3828  select_statement->info.query.order_by = NULL;
3829  into = select_statement->info.query.into_list;
3830  select_statement->info.query.into_list = NULL;
3831  all_distinct = select_statement->info.query.all_distinct;
3832 
3833  /* for each table/class in select_statements from part, do leaf expansion or vclass/view expansion. */
3834  tree = mq_translate_tree (parser, select_statement, from, order_by, DB_AUTH_SELECT);
3835  if (tree == NULL)
3836  {
3837  if (pt_has_error (parser))
3838  {
3839  return NULL;
3840  }
3841  else if (er_has_error ())
3842  {
3843  /* Some unexpected errors (like ER_INTERRUPTED due to timeout) should be handled. */
3844  PT_ERROR (parser, select_statement, er_msg ());
3845  return NULL;
3846  }
3847  }
3848 
3849  select_statement = tree;
3850  }
3851 
3852  /* restore the into part. and order by, if they are not already set. */
3853  if (select_statement)
3854  {
3855  if (!select_statement->info.query.order_by)
3856  {
3857  select_statement->info.query.order_by = order_by;
3858  }
3859 
3860  select_statement->info.query.into_list = into;
3861  if (all_distinct == PT_DISTINCT)
3862  {
3863  /* only set this to distinct. If the current spec is "all" bute the view is on a "distinct" query, the result
3864  * is still distinct. */
3865  select_statement->info.query.all_distinct = all_distinct;
3866  }
3867  }
3868 
3869  /* check for order dependent nodes */
3870  if (select_statement != NULL && select_statement->node_type == PT_SELECT
3871  && select_statement->info.query.order_by != NULL)
3872  {
3873  PT_NODE *list = NULL;
3874  int order_dep_count = 0, list_pos = 1;
3875 
3876  /* check select list for order dependent nodes */
3877  list = select_statement->info.query.q.select.list;
3878  while (list != NULL)
3879  {
3880  if (mq_is_order_dependent_node (list))
3881  {
3882  PT_NODE *sort_spec = select_statement->info.query.order_by;
3883  bool is_sorted = false;
3884 
3885  /* search in sort spec */
3886  while (sort_spec != NULL)
3887  {
3888  is_sorted |= (sort_spec->info.sort_spec.pos_descr.pos_no == list_pos);
3889  sort_spec = sort_spec->next;
3890  }
3891 
3892  if (!is_sorted)
3893  {
3894  /* mark nodes */
3896  order_dep_count++;
3897  }
3898  }
3899 
3900  list = list->next;
3901  list_pos++;
3902  }
3903 
3904  if (order_dep_count > 0)
3905  {
3906  /* rewrite statement */
3907  select_statement = mq_rewrite_order_dependent_query (parser, select_statement, &unique);
3908 
3909  /* reset IDs and recompile paths */
3910  mq_reset_ids_in_statement (parser, select_statement);
3911  }
3912  }
3913 
3914  /* check for analytic/aggregate combo */
3915  if (pt_has_analytic (parser, select_statement) && pt_has_aggregate (parser, select_statement))
3916  {
3917  /* we can't process analytics and aggregates in the same statement; we must build a subquery for the aggregation
3918  * and keep the parent statement for the analytics */
3919  mq_rewrite_aggregate_as_derived (parser, select_statement);
3920  mq_reset_ids_in_statement (parser, select_statement);
3921  }
3922 
3923  return select_statement;
3924 }
3925 
3926 /*
3927  * mq_check_update() - checks duplicated column names
3928  * return:
3929  * parser(in):
3930  * update_statement(in):
3931  */
3932 static void
3934 {
3935  pt_no_double_updates (parser, update_statement);
3936  pt_no_attr_and_meta_attr_updates (parser, update_statement);
3937 }
3938 
3939 /*
3940  * mq_check_delete() - checks for duplicate classes in table_list
3941  * parser(in): parser context
3942  * delete_stmt(in): delete statement
3943  *
3944  * NOTE: applies to multi-table delete statements:
3945  * DELETE <table_list> FROM <table_reference> ...
3946  * NOTE: all errors will be returned as parser errors
3947  */
3948 static void
3950 {
3951  PT_NODE *table, *search;
3952 
3953  if (delete_stmt == NULL)
3954  {
3955  return;
3956  }
3957 
3958  assert (delete_stmt->node_type == PT_DELETE);
3959 
3960  for (table = delete_stmt->info.delete_.target_classes; table; table = table->next)
3961  {
3962  for (search = table->next; search; search = search->next)
3963  {
3964  /* check if search is duplicate of table */
3966  && table->info.name.spec_id == search->info.name.spec_id)
3967  {
3968  /* same class found twice in table_list */
3970  search->info.name.resolved);
3971  return;
3972  }
3973  }
3974  }
3975 }
3976 
3977 /*
3978  * mq_translate_update() - leaf expansion or view expansion for update
3979  * return:
3980  * parser(in):
3981  * update_statement(in):
3982  */
3983 static PT_NODE *
3985 {
3986  PT_NODE *from;
3987  PT_NODE save = *update_statement;
3988 
3989  from = update_statement->info.update.spec;
3990 
3991  /* translate statement */
3992  update_statement = mq_translate_tree (parser, update_statement, from, NULL, DB_AUTH_UPDATE);
3993 
3994  if (update_statement)
3995  {
3996  /* mark specs on translated tree and add oids where necessary */
3997  pt_mark_spec_list_for_update (parser, update_statement);
3998 
3999  /* check update statement */
4000  mq_check_update (parser, update_statement);
4001  }
4002  if (update_statement == NULL && !pt_has_error (parser))
4003  {
4005  }
4006 
4007  return update_statement;
4008 }
4009 
4010 /*
4011  * mq_resolve_insert_statement() - resolve names in insert statement.
4012  * return: insert statement with resolved names.
4013  * parser(in):
4014  * insert_statement(in/out):
4015  */
4016 static PT_NODE *
4018 {
4019  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
4020  PT_NODE *odku = insert_statement->info.insert.odku_assignments;
4021  PT_NODE *from = insert_statement->info.insert.spec;
4022  PT_NODE *attr;
4023 
4024  /* reset spec_id for names not referencing the insert statement */
4025  if (odku != NULL)
4026  {
4027  odku = parser_walk_tree (parser, odku, mq_clear_other_ids, from, NULL, NULL);
4028  }
4029  for (attr = insert_statement->info.insert.attr_list; attr != NULL; attr = attr->next)
4030  {
4031  attr = parser_walk_tree (parser, attr, mq_clear_other_ids, from, NULL, NULL);
4032  }
4033 
4034  /* do name resolving */
4035  insert_statement = pt_resolve_names (parser, insert_statement, &sc_info);
4036  if (insert_statement == NULL || pt_has_error (parser))
4037  {
4038  return insert_statement;
4039  }
4040 
4041  insert_statement = mq_reset_ids (parser, insert_statement, from);
4042 
4043  if (odku != NULL)
4044  {
4045  /* need to check this in case something went wrong */
4046  insert_statement = pt_check_odku_assignments (parser, insert_statement);
4047  }
4048 
4049  return insert_statement;
4050 }
4051 
4052 
4053 /*
4054  * mq_replace_virtual_oid_with_real_oid () - Used for insert translate, forces
4055  * sub-queries to select real
4056  * instance OID's instead of virtual
4057  * OID's.
4058  *
4059  * return : Parse tree updated node.
4060  * parser (in) : Parser context.
4061  * node (in) : Parse tree node.
4062  * arg (in) : Void argument.
4063  * continue_walk (in) : Continue walk.
4064  */
4065 static PT_NODE *
4066 mq_replace_virtual_oid_with_real_oid (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
4067 {
4068  int error = NO_ERROR;
4069  if (node->node_type == PT_NAME)
4070  {
4071  if (node->info.name.meta_class == PT_VID_ATTR)
4072  {
4073  node->info.name.meta_class = PT_OID_ATTR;
4074  if (node->data_type)
4075  {
4076  /* set virtual object to NULL and real class entity_name will be used */
4078  }
4079  }
4080  else if (node->info.name.meta_class == PT_PARAMETER)
4081  {
4082  /* replace with an object value */
4083  DB_VALUE db_val;
4084  DB_OBJECT *obj = NULL;
4085  PT_NODE *result = NULL;
4086 
4087  pt_evaluate_tree_having_serial (parser, node, &db_val, 1);
4088  if (pt_has_error (parser))
4089  {
4090  /* quit */
4091  return node;
4092  }
4093  if (DB_VALUE_TYPE (&db_val) == DB_TYPE_VOBJ)
4094  {
4095  error = vid_vobj_to_object (&db_val, &obj);
4096  if (error != NO_ERROR)
4097  {
4098  PT_ERRORc (parser, node, er_msg ());
4099  return node;
4100  }
4101  db_make_object (&db_val, obj);
4102  }
4103  else if (DB_VALUE_TYPE (&db_val) == DB_TYPE_OBJECT)
4104  {
4105  obj = db_real_instance (db_get_object (&db_val));
4106  db_make_object (&db_val, obj);
4107  }
4108  else
4109  {
4110  /* do nothing */
4111  return node;
4112  }
4113  result = pt_dbval_to_value (parser, &db_val);
4114  if (result == NULL)
4115  {
4117  return node;
4118  }
4119  PT_NODE_MOVE_NUMBER_OUTERLINK (result, node);
4120  parser_free_tree (parser, node);
4121  return result;
4122  }
4123  }
4124  return node;
4125 }
4126 
4127 /*
4128  * mq_translate_insert() - leaf expansion or vclass/view expansion
4129  * return:
4130  * parser(in):
4131  * insert_statement(in):
4132  */
4133 static PT_NODE *
4135 {
4136  PT_NODE *from = NULL, *val = NULL, *attr = NULL, **val_hook = NULL;
4137  PT_NODE *next = insert_statement->next;
4138  PT_NODE *flat = NULL, *temp = NULL, **last = NULL;
4139  PT_NODE save = *insert_statement;
4140  PT_NODE *subquery = NULL;
4141  PT_SPEC_INFO *from_spec = NULL;
4142  bool viable;
4143  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
4144  int what_for = DB_AUTH_INSERT;
4145  int is_class = 0;
4146 
4147  insert_statement->next = NULL;
4148  from = insert_statement->info.insert.spec;
4149 
4150  if (insert_statement->info.insert.odku_assignments != NULL)
4151  {
4152  what_for = DB_AUTH_INSERT_UPDATE;
4153  }
4154 
4155  if (insert_statement->info.insert.do_replace)
4156  {
4157  assert (insert_statement->info.insert.odku_assignments == NULL);
4158  what_for = DB_AUTH_REPLACE;
4159  }
4160 
4161  insert_statement = mq_translate_tree (parser, insert_statement, from, NULL, what_for);
4162 
4163  /* check there are no double assignments after translate */
4164  pt_no_double_insert_assignments (parser, insert_statement);
4165  if (pt_has_error (parser))
4166  {
4167  return NULL;
4168  }
4169 
4170  if (insert_statement)
4171  {
4172  PT_NODE *t_save = insert_statement; /* save start node pointer */
4173  PT_NODE *head = NULL;
4174  PT_NODE *prev = NULL;
4175 
4176  while (insert_statement)
4177  {
4178  PT_NODE *crt_list = insert_statement->info.insert.value_clauses;
4179  bool multiple_tuples_insert = crt_list->next != NULL;
4180 
4181  if (crt_list->info.node_list.list_type == PT_IS_VALUE)
4182  {
4183  /* deal with case 3 */
4184  attr = insert_statement->info.insert.attr_list;
4185  val_hook = &crt_list->info.node_list.list;
4186  val = *val_hook;
4187 
4188  while (attr && val)
4189  {
4190  if (val->node_type == PT_INSERT && val->etc)
4191  {
4192  PT_NODE *val_next = val->next;
4193  PT_NODE *flat;
4194  DB_OBJECT *real_class = NULL;
4195 
4196  /* TODO what about multiple tuples insert? What should this code do? We give up processing for
4197  * now. */
4198  if (multiple_tuples_insert)
4199  {
4200  return NULL;
4201  }
4202 
4203  /* this is case 3 above. Need to choose the appropriate nested insert statement. */
4204  /* do you solve your problem? */
4205  if (head)
4206  { /* after the first loop */
4207  val->next = head;
4208  head = val;
4209  val->etc = NULL;
4210  }
4211  else
4212  { /* the first loop */
4213  val->next = (PT_NODE *) val->etc;
4214  head = val;
4215  val->etc = NULL;
4216  }
4217 
4218  if (attr->data_type && attr->data_type->info.data_type.entity)
4219  {
4220  real_class = attr->data_type->info.data_type.entity->info.name.db_object;
4221  }
4222 
4223  /* if there is a real class this must match, use it. otherwise it must be a "db_object" type, so
4224  * any will do. */
4225  if (real_class)
4226  {
4227  while (val)
4228  {
4229  if (val->info.insert.spec && (flat = val->info.insert.spec->info.spec.flat_entity_list)
4230  && flat->info.name.db_object == real_class)
4231  {
4232  break; /* found it */
4233  }
4234  prev = val;
4235  val = val->next;
4236  }
4237  }
4238 
4239  if (val)
4240  {
4241  if (val == head)
4242  {
4243  head = head->next;
4244  }
4245  else
4246  {
4247  prev->next = val->next;
4248  }
4249  }
4250  else
4251  {
4252  val = parser_new_node (parser, PT_VALUE);
4253  if (val == NULL)
4254  {
4255  PT_INTERNAL_ERROR (parser, "allocate new node");
4256  return NULL;
4257  }
4258 
4259  val->type_enum = PT_TYPE_NULL;
4260  }
4261 
4262  val->next = val_next;
4263  /* and finally replace it */
4264  *val_hook = val;
4265  }
4266 
4267  attr = attr->next;
4268  val_hook = &val->next;
4269  val = *val_hook;
4270  }
4271  }
4272 
4273  insert_statement = insert_statement->next;
4274  }
4275 
4276  if (head)
4277  {
4278  parser_free_tree (parser, head);
4279  }
4280 
4281  insert_statement = t_save;
4282 
4283  /* Now deal with case 1, 2 */
4284  last = &insert_statement;
4285 
4286  /* now pick a viable insert statement */
4287  while (*last)
4288  {
4289  temp = *last;
4290  from = temp->info.insert.spec;
4291  from_spec = &(from->info.spec);
4292  /* try to retrieve info from derived table */
4293  if (from_spec->derived_table_type == PT_IS_SUBQUERY)
4294  {
4295  from = parser_copy_tree (parser, from_spec->derived_table->info.query.q.select.from);
4296  temp->info.insert.spec = from;
4297  temp = mq_resolve_insert_statement (parser, temp);
4298  if (temp == NULL || pt_has_error (parser))
4299  {
4300  return NULL;
4301  }
4302  }
4303  flat = from->info.spec.flat_entity_list;
4304  if (flat == NULL)
4305  {
4306  assert (false);
4307  return NULL;
4308  }
4309 
4310  viable = false;
4311  is_class = db_is_class (flat->info.name.db_object);
4312  if (is_class < 0)
4313  {
4314  return NULL;
4315  }
4316  if (is_class)
4317  {
4318  viable = true;
4319  }
4320 
4321  if (viable)
4322  {
4323  /* propagate temp's type information upward now because mq_check_insert_compatibility calls
4324  * pt_class_assignable which expects accurate type information. */
4325  sc_info.top_node = temp;
4326  sc_info.donot_fold = false;
4327  (void) pt_semantic_type (parser, temp, &sc_info);
4328  }
4329 
4330  /* here we just go to the next item in the list. If it is a nested insert, the correct one will be selected
4331  * from the list at the outer level. If it is a top level insert, the correct one will be determined at run
4332  * time. */
4333  last = &temp->next;
4334  }
4335  }
4336 
4337  if (insert_statement)
4338  {
4339  if (insert_statement->info.insert.is_subinsert == PT_IS_SUBINSERT)
4340  {
4341  /* kludge to pass along nested list */
4342  insert_statement->etc = insert_statement->next;
4343  insert_statement->next = next;
4344  }
4345  }
4346  else if (!pt_has_error (parser))
4347  {
4349  }
4350 
4351  if (pt_has_error (parser))
4352  {
4353  return NULL;
4354  }
4355 
4356  subquery = pt_get_subquery_of_insert_select (insert_statement);
4357  if (subquery != NULL)
4358  {
4359  (void) parser_walk_tree (parser, subquery, mq_replace_virtual_oid_with_real_oid, NULL, NULL, NULL);
4360  }
4361 
4362  if (subquery != NULL && PT_IS_SELECT (subquery) && insert_statement->info.insert.odku_assignments != NULL)
4363  {
4364  /* The odku_assignments might refer nodes from the SELECT statements. Even though name resolving was already
4365  * performed on odku_assigments, we have to redo it here. If the SELECT target was a view, it has been rewritten
4366  * by mq_translate_local and names which referenced it were not updated. */
4367  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
4368  PT_NODE *odku = insert_statement->info.insert.odku_assignments;
4369 
4370  from = insert_statement->info.insert.spec;
4371  /* reset spec_id for names not referencing the insert statement */
4372  odku = parser_walk_tree (parser, odku, mq_clear_other_ids, from, NULL, NULL);
4373  if (odku == NULL)
4374  {
4375  return NULL;
4376  }
4377  /* redo name resolving */
4378  insert_statement = pt_resolve_names (parser, insert_statement, &sc_info);
4379  if (insert_statement == NULL || pt_has_error (parser))
4380  {
4381  return NULL;
4382  }
4383  /* need to recheck this in case something went wrong */
4384  insert_statement = pt_check_odku_assignments (parser, insert_statement);
4385  }
4386  insert_rewrite_names_in_value_clauses (parser, insert_statement);
4387  if (pt_has_error (parser))
4388  {
4389  return NULL;
4390  }
4391 
4392  return insert_statement;
4393 }
4394 
4395 /*
4396  * mq_translate_delete() - leaf expansion or view expansion for delete
4397  * return:
4398  * parser(in):
4399  * delete_statement(in):
4400  */
4401 static PT_NODE *
4403 {
4404  PT_NODE *from;
4405  PT_NODE save = *delete_statement;
4406 
4407  /* translate */
4408  from = delete_statement->info.delete_.spec;
4409  delete_statement = mq_translate_tree (parser, delete_statement, from, NULL, DB_AUTH_DELETE);
4410  if (delete_statement != NULL)
4411  {
4412  /* mark specs again on translated tree and add oids where necessary */
4413  pt_mark_spec_list_for_delete (parser, delete_statement);
4414 
4415  /* check delete statement */
4416  mq_check_delete (parser, delete_statement);
4417 
4418  if (pt_has_error (parser))
4419  {
4420  /* checking failed */
4421  return NULL;
4422  }
4423  }
4424  else if (!pt_has_error (parser))
4425  {
4427  }
4428 
4429  return delete_statement;
4430 }
4431 
4432 /*
4433  * mq_check_merge() - checks duplicated column names
4434  * return:
4435  * parser(in):
4436  * merge_statement(in):
4437  */
4438 static void
4440 {
4441  pt_no_double_updates (parser, merge_statement);
4442  pt_no_attr_and_meta_attr_updates (parser, merge_statement);
4443 }
4444 
4445 /*
4446  * mq_translate_merge() - leaf expansion or vclass/view expansion for merge
4447  * return:
4448  * parser(in):
4449  * merge_statement(in):
4450  */
4451 static PT_NODE *
4453 {
4454  PT_NODE *from, *flat;
4455  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
4456  DB_AUTH auth = DB_AUTH_NONE;
4457 
4458  from = merge_statement->info.merge.into;
4459  if (merge_statement->info.merge.update.assignment)
4460  {
4461  /* flag spec for update/delete */
4462  auth = (DB_AUTH) (auth | DB_AUTH_UPDATE);
4463  if (merge_statement->info.merge.update.has_delete)
4464  {
4465  auth = (DB_AUTH) (auth | DB_AUTH_DELETE);
4466  }
4467  }
4468  if (merge_statement->info.merge.insert.value_clauses)
4469  {
4470  auth = (DB_AUTH) (auth | DB_AUTH_INSERT);
4471  }
4472 
4473  merge_statement = mq_translate_tree (parser, merge_statement, from, NULL, auth);
4474 
4475  /* check statement */
4476  if (merge_statement)
4477  {
4478  if (merge_statement->info.merge.update.assignment)
4479  {
4480  /* mark specs again and add oids where necessary */
4481  pt_mark_spec_list_for_update (parser, merge_statement);
4482  if (merge_statement->info.merge.update.has_delete)
4483  {
4484  pt_mark_spec_list_for_delete (parser, merge_statement);
4485  }
4486  }
4487 
4488  (void) mq_check_merge (parser, merge_statement);
4489 
4490  flat = merge_statement->info.merge.into->info.spec.flat_entity_list;
4491  if (flat)
4492  {
4493  sc_info.top_node = merge_statement;
4494  sc_info.donot_fold = false;
4495  merge_statement = pt_semantic_type (parser, merge_statement, &sc_info);
4496  }
4497  }
4498 
4499  return merge_statement;
4500 }
4501 
4502 /*
4503  * mq_push_paths_select() -
4504  * return:
4505  * parser(in):
4506  * statement(in): select statement
4507  * spec(in): spec to examine as root of paths
4508  *
4509  * Note:
4510  * 1) virtual paths rooted in virtual objects coming from
4511  * query derived table pushed into those queries
4512  * 2) virtual path specs of muliple virtual classes
4513  * converted into a derived path spec
4514  * 3) virtual paths specs of a single virtual class
4515  * which translates to a union of real classes
4516  * also being converted into a derived path spec
4517  */
4518 static void
4520 {
4521  PT_NODE **paths;
4522  PT_NODE *path;
4523  PT_NODE *flat;
4524  PT_NODE *subquery;
4525  PT_NODE **path_next;
4526 
4527  while (spec)
4528  {
4529  paths = &spec->info.spec.path_entities;
4530  while (*paths)
4531  {
4532  path = *paths;
4533  path_next = &path->next;
4534  flat = path->info.spec.flat_entity_list;
4535  if (flat)
4536  {
4537  if (db_is_class (flat->info.name.db_object) <= 0)
4538  {
4540  {
4541  /* need to push this path inside spec */
4542  *paths = path->next;
4543  path->next = NULL;
4544  mq_push_path (parser, statement, spec, path);
4545  /* its gone, free it */
4546  parser_free_tree (parser, path);
4547  path_next = paths;
4548  break; /* out of while */
4549  }
4550  else if (spec->info.spec.derived_table_type && db_is_vclass (flat->info.name.db_object) > 0)
4551  {
4553  if (!subquery || subquery->next || flat->next)
4554  {
4555  /* this is non-updatable, or turns into a union, It must be rewritten to a derived path join. */
4556  *paths = path->next;
4557  path->next = NULL;
4558  path = mq_derived_path (parser, statement, path);
4559  /* path is rewritten, put it back */
4560  path->next = *paths;
4561  path_next = &path->next;
4562  *paths = path;
4563  break; /* out of while */
4564  }
4565  }
4566  }
4567  }
4568 
4569  /* if the path root is virtual, may need to fix up sub paths */
4570  if (path->info.spec.path_entities)
4571  {
4572  mq_push_paths_select (parser, statement, path->info.spec.path_entities);
4573  }
4574 
4575  paths = path_next;
4576  }
4577 
4578  spec = spec->next;
4579  }
4580 }
4581 
4582 /*
4583  * mq_check_rewrite_select() -
4584  * return: rewrited parse tree
4585  * parser(in):
4586  * select_statement(in):
4587  *
4588  * Note:
4589  * 1) virtual specs which are part of a join AND which would
4590  * translate to a union, are rewritten as derived.
4591  * (This is an optimization to avoid multiplying the number
4592  * of subqueries, joins and unions occuring.)
4593  *
4594  * 2) virtual specs of aggregate selects which would translate
4595  * to a union are rewritten as derived.
4596  */
4597 static PT_NODE *
4599 {
4600  PT_NODE *from;
4601  int is_union_translation = 0;
4602 
4604 
4605  /* Convert to cnf and tag taggable terms */
4606  select_statement->info.query.q.select.where = pt_cnf (parser, select_statement->info.query.q.select.where);
4607  if (select_statement->info.query.q.select.having)
4608  {
4609  select_statement->info.query.q.select.having = pt_cnf (parser, select_statement->info.query.q.select.having);
4610  }
4611 
4612  from = select_statement->info.query.q.select.from;
4613  if (from && (from->next || pt_has_aggregate (parser, select_statement)))
4614  {
4615  /* when translating joins, its important to maintain linearity of the translation. The cross-product of unions is
4616  * exponential. Therefore, we convert cross-products of unions to cross-products of derived tables. */
4617 
4618  is_union_translation = mq_is_union_translation (parser, from);
4619  if (is_union_translation < NO_ERROR)
4620  {
4621  return NULL;
4622  }
4623 
4624  if (is_union_translation != 0)
4625  {
4626  select_statement->info.query.q.select.from = from =
4627  mq_rewrite_vclass_spec_as_derived (parser, select_statement, from, NULL);
4628  if (from == NULL)
4629  {
4630  return NULL;
4631  }
4632  }
4633  else if (from->info.spec.derived_table_type == PT_IS_SUBQUERY)
4634  {
4635  (void) mq_copypush_sargable_terms (parser, select_statement, from);
4636  }
4637 
4638  while (from->next)
4639  {
4640  is_union_translation = mq_is_union_translation (parser, from->next);
4641  if (is_union_translation < NO_ERROR)
4642  {
4643  return NULL;
4644  }
4645 
4646  if (is_union_translation != 0)
4647  {
4648  from->next = mq_rewrite_vclass_spec_as_derived (parser, select_statement, from->next, NULL);
4649  }
4650  else if (from->next->info.spec.derived_table_type == PT_IS_SUBQUERY)
4651  {
4652  (void) mq_copypush_sargable_terms (parser, select_statement, from->next);
4653  }
4654  from = from->next;
4655  }
4656  }
4657  else
4658  {
4659  is_union_translation = false;
4660 
4661  /* see 'xtests/10010_vclass_set.sql' and 'err_xtests/check21.sql' */
4662  if (select_statement->info.query.is_view_spec == 0 && select_statement->info.query.oids_included == 0)
4663  {
4664  is_union_translation = mq_is_union_translation (parser, from);
4665  if (is_union_translation < NO_ERROR)
4666  {
4667  return NULL;
4668  }
4669 
4670  if (is_union_translation != 0)
4671  {
4672  select_statement->info.query.q.select.from =
4673  mq_rewrite_vclass_spec_as_derived (parser, select_statement, from, NULL);
4674  }
4675  }
4676 
4677  if (is_union_translation == false && from && from->info.spec.derived_table_type == PT_IS_SUBQUERY)
4678  {
4679  (void) mq_copypush_sargable_terms (parser, select_statement, from);
4680  }
4681  }
4682 
4683  return select_statement;
4684 }
4685 
4686 /*
4687  * mq_push_paths() - rewrites from specs, and path specs, to things
4688  * mq_translate_select can handle
4689  * return:
4690  * parser(in):
4691  * statement(in):
4692  * void_arg(in):
4693  * cw(in):
4694  */
4695 static PT_NODE *
4696 mq_push_paths (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk)
4697 {
4698  PT_NODE *tmp_node = NULL;
4699 
4700  if (statement == NULL)
4701  {
4702  return NULL;
4703  }
4704 
4705  switch (statement->node_type)
4706  {
4707  case PT_SELECT:
4709  {
4710  tmp_node = mq_check_rewrite_select (parser, statement);
4711  if (tmp_node == NULL)
4712  {
4713  if (!pt_has_error (parser) && er_has_error ())
4714  {
4715  /* Some unexpected errors (like ER_INTERRUPTED due to timeout) should be handled. */
4716  PT_ERROR (parser, statement, er_msg ());
4717  }
4718 
4719  statement = tmp_node;
4720 
4721  break;
4722  }
4723 
4724  statement = tmp_node;
4725  }
4726 
4728  {
4729  mq_push_paths_select (parser, statement, statement->info.query.q.select.from);
4730  }
4731  break;
4732 
4733  default:
4734  statement = statement;
4735  break;
4736  }
4737 
4738  return statement;
4739 }
4740 
4741 
4742 /*
4743  * mq_translate_local() - recursively expands each query against a view or
4744  * virtual class
4745  * return:
4746  * parser(in):
4747  * statement(in):
4748  * void_arg(in):
4749  * cw(in):
4750  */
4751 static PT_NODE *
4752 mq_translate_local (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk)
4753 {
4754  int line, column;
4755  PT_NODE *next;
4756  PT_NODE *indexp, *spec, *using_index;
4757  bool aggregate_rewrote_as_derived = false;
4758 
4759  if (statement == NULL)
4760  {
4761  return statement;
4762  }
4763 
4764  next = statement->next;
4765  statement->next = NULL;
4766 
4767  /* try to track original source line and column */
4768  line = statement->line_number;
4769  column = statement->column_number;
4770 
4771  switch (statement->node_type)
4772  {
4773  case PT_SELECT:
4774  statement = mq_translate_select (parser, statement);
4775 
4776  if (statement)
4777  {
4778  if (pt_has_aggregate (parser, statement) && mq_has_class_methods_corr_subqueries (parser, statement))
4779  {
4780  /* We need to push class methods or correlated subqueries from the select list into the derived table
4781  * because we have no other way of generating correct XASL for correlated subqueries on aggregate
4782  * queries. */
4783  statement = mq_rewrite_aggregate_as_derived (parser, statement);
4784  aggregate_rewrote_as_derived = true;
4785  }
4786  }
4787 
4788  break;
4789 
4790  case PT_UPDATE:
4791  statement = mq_translate_update (parser, statement);
4792  break;
4793 
4794  case PT_INSERT:
4795  statement = mq_translate_insert (parser, statement);
4796  break;
4797 
4798  case PT_DELETE:
4799  statement = mq_translate_delete (parser, statement);
4800  break;
4801 
4802  case PT_MERGE:
4803  statement = mq_translate_merge (parser, statement);
4804  break;
4805 
4806  default:
4807  statement = statement;
4808  break;
4809  }
4810 
4811  if (statement)
4812  {
4813  switch (statement->node_type)
4814  {
4815  case PT_SELECT:
4816  statement->info.query.is_subquery = PT_IS_SUBQUERY;
4817  break;
4818 
4819  case PT_UNION:
4820  case PT_DIFFERENCE:
4821  case PT_INTERSECTION:
4822  statement->info.query.is_subquery = PT_IS_SUBQUERY;
4825  break;
4826 
4827  default:
4828  break;
4829  }
4830 
4831  statement->line_number = line;
4832  statement->column_number = column;
4833  /* beware of simply restoring next because the newly rewritten statement can be a list. so we must append next
4834  * to statement. (The number of bugs caused by this multipurpose use of node->next tells us it's not a good
4835  * idea.) */
4836  parser_append_node (next, statement);
4837  }
4838 
4839  /* resolving using index */
4840  using_index = NULL;
4841  spec = NULL;
4842  if (!pt_has_error (parser) && statement)
4843  {
4844  switch (statement->node_type)
4845  {
4846  case PT_SELECT:
4847  spec = statement->info.query.q.select.from;
4848  if (aggregate_rewrote_as_derived && spec != NULL)
4849  {
4850  PT_NODE *derived_table = spec->info.spec.derived_table;
4851  assert (PT_SPEC_IS_DERIVED (spec));
4852  using_index = derived_table->info.query.q.select.using_index;
4853  spec = derived_table->info.query.q.select.from;
4854  }
4855  else
4856  {
4857  using_index = statement->info.query.q.select.using_index;
4858  }
4859  break;
4860 
4861  case PT_UPDATE:
4862  using_index = statement->info.update.using_index;
4863  spec = statement->info.update.spec;
4864  break;
4865 
4866  case PT_DELETE:
4867  using_index = statement->info.delete_.using_index;
4868  spec = statement->info.delete_.spec;
4869  break;
4870 
4871  default:
4872  break;
4873  }
4874  }
4875 
4876  /* resolve using index */
4877  indexp = using_index;
4878  if (indexp != NULL && spec != NULL)
4879  {
4880  for (; indexp; indexp = indexp->next)
4881  {
4882  if (pt_resolve_using_index (parser, indexp, spec) == NULL)
4883  {
4884  return NULL;
4885  }
4886  }
4887  }
4888 
4889  /* semantic check on using index */
4890  if (using_index != NULL)
4891  {
4892  if (mq_check_using_index (parser, using_index) != NO_ERROR)
4893  {
4894  return NULL;
4895  }
4896  }
4897 
4898  return statement;
4899 }
4900 
4901 
4902 /*
4903  * mq_check_using_index() - check the using index clause for semantic errors
4904  * return: error code
4905  * parser(in): current parser
4906  * using_index(in): list of PT_NODEs in USING INDEX clause
4907  */
4908 static int
4910 {
4911  PT_NODE *hint_none = NULL, *hint_all_except = NULL;
4912  PT_NODE *hint_use = NULL, *hint_force = NULL, *hint_ignore = NULL;
4913 
4914  bool has_errors = false;
4915 
4916  PT_NODE *index_hint = NULL;
4917  PT_NODE *node = NULL, *search_node = NULL;
4918  bool is_hint_class_none = false;
4919  bool is_hint_use = false, is_hint_force = false, is_hint_ignore = false;
4920 
4921  /* check for valid using_index node */
4922  if (using_index == NULL)
4923  {
4924  return NO_ERROR;
4925  }
4926 
4927  /* Gathering basic information about the index hints */
4928  node = using_index;
4929  while (node != NULL)
4930  {
4931  if (node->etc == (void *) PT_IDX_HINT_NONE)
4932  {
4933  /* USING INDEX NONE node found */
4934  assert (node->info.name.original == NULL && node->info.name.resolved == NULL);
4935  hint_none = node;
4936  }
4937  else if (node->etc == (void *) PT_IDX_HINT_ALL_EXCEPT)
4938  {
4939  hint_all_except = node;
4940  }
4941  else if (node->etc == (void *) PT_IDX_HINT_CLASS_NONE)
4942  {
4943  is_hint_class_none = true;
4944  }
4945  else if (node->etc == (void *) PT_IDX_HINT_USE)
4946  {
4947  /* found USE INDEX idx or USING INDEX idx node */
4948  assert (node->info.name.original != NULL && node->info.name.resolved != NULL);
4949  is_hint_use = true;
4950  if (hint_use == NULL)
4951  {
4952  hint_use = node;
4953  }
4954  }
4955  else if (node->etc == (void *) PT_IDX_HINT_FORCE)
4956  {
4957  /* found FORCE INDEX idx or USING INDEX idx(+) node */
4958  assert (node->info.name.original != NULL && node->info.name.resolved != NULL);
4959  is_hint_force = true;
4960  if (hint_force == NULL)
4961  {
4962  hint_force = node;
4963  }
4964  }
4965  else if (node->etc == (void *) PT_IDX_HINT_IGNORE)
4966  {
4967  /* found IGNORE INDEX idx or USING INDEX idx(-) node */
4968  assert (node->info.name.original != NULL && node->info.name.resolved != NULL);
4969  is_hint_ignore = true;
4970  if (hint_ignore == NULL)
4971  {
4972  hint_ignore = node;
4973  }
4974  }
4975  else
4976  {
4977  /* all hint nodes must have the etc flag set from the grammar */
4978  assert (false);
4979  }
4980 
4981  node = node->next;
4982  }
4983 
4984  /* check for USING INDEX NONE and {USE|FORCE} INDEX; error if both found */
4985  if (hint_none != NULL)
4986  {
4987  assert (hint_all_except == NULL);
4988 
4989  if (hint_use != NULL)
4990  {
4991  index_hint = hint_use;
4992  has_errors = true;
4993  }
4994  else if (hint_force != NULL)
4995  {
4996  index_hint = hint_force;
4997  has_errors = true;
4998  }
4999  if (has_errors)
5000  {
5001  /* {USE|FORCE} INDEX idx ... USING INDEX NONE case was found */
5003  "using index none", parser_print_tree (parser, index_hint));
5004  return ER_PT_SEMANTIC;
5005  }
5006  }
5007  else if (hint_all_except != NULL && (hint_use != NULL || hint_force != NULL || hint_ignore != NULL))
5008  {
5010  "USING INDEX ALL EXCEPT", "{USE|FORCE|IGNORE} INDEX");
5011  return ER_PT_SEMANTIC;
5012  }
5013 
5014  /*
5015  * USING INDEX t.none is incompatible with {USE|FORCE} INDEX [t.]idx
5016  * Check for USING INDEX class.NONE, class.any-index[(+)] or
5017  * {USE|FORCE} INDEX (class.any-index) ... USING INDEX class.NONE
5018  */
5019  node = using_index;
5020  while (node != NULL && is_hint_class_none && (is_hint_use || is_hint_force))
5021  {
5022  if (node->info.name.original == NULL && node->info.name.resolved != NULL
5023  && node->etc == (void *) PT_IDX_HINT_CLASS_NONE)
5024  {
5025  /* search trough all nodes again and check for other index hints on class_name */
5026  search_node = using_index;
5027  while (search_node != NULL)
5028  {
5029  if (search_node->info.name.original != NULL && search_node->info.name.resolved != NULL
5030  && (search_node->etc == (void *) PT_IDX_HINT_USE || search_node->etc == (void *) PT_IDX_HINT_FORCE)
5031  && !intl_identifier_casecmp (node->info.name.resolved, search_node->info.name.resolved))
5032  {
5033  /* class_name.idx_name and class_name.none found in USE INDEX and/or USING INDEX clauses */
5035  parser_print_tree (parser, node), parser_print_tree (parser, search_node));
5036 
5037  return ER_PT_SEMANTIC;
5038  }
5039 
5040  search_node = search_node->next;
5041  }
5042  }
5043 
5044  node = node->next;
5045  }
5046 
5047  /* no error */
5048  return NO_ERROR;
5049 }
5050 
5051 
5052 /*
5053  * mq_fetch_subqueries() - ask the schema manager for the cached parser
5054  * containing the compiled subqueries of the class
5055  * return:
5056  * parser(in):
5057  * class(in):
5058  */
5059 PT_NODE *
5061 {
5062  PARSER_CONTEXT *query_cache;
5063  DB_OBJECT *class_object;
5064 
5065  if (!class_ || !(class_object = class_->info.name.db_object) || db_is_class (class_object))
5066  {
5067  return NULL;
5068  }
5069 
5070  query_cache = sm_virtual_queries (parser, class_object);
5071 
5072  if (query_cache && query_cache->view_cache)
5073  {
5074  if (!(query_cache->view_cache->authorization & DB_AUTH_SELECT))
5075  {
5077  db_get_class_name (class_->info.name.db_object));
5078  return NULL;
5079  }
5080 
5081  if (parser != NULL && query_cache->error_msgs != NULL)
5082  {
5083  mq_copy_view_error_msgs (parser, query_cache);
5084  }
5085 
5086  return query_cache->view_cache->vquery_for_query_in_gdb;
5087  }
5088 
5089  return NULL;
5090 }
5091 
5092 #if defined(ENABLE_UNUSED_FUNCTION)
5093 /*
5094  * mq_collapse_dot() -
5095  * return: PT_NAME node with the printable form and type of a sub tree
5096  * parser(in):
5097  * tree(in): arg1 should be a name node.
5098  */
5099 static PT_NODE *
5100 mq_collapse_dot (PARSER_CONTEXT * parser, PT_NODE * tree)
5101 {
5102  PT_NODE *collapse;
5103  PT_NODE *arg1, *arg2;
5104 
5105  arg1 = tree->info.dot.arg1;
5106  arg2 = tree->info.dot.arg2;
5107 
5108  if (arg1->node_type != PT_NAME || arg2->node_type != PT_NAME)
5109  return tree; /* bail out */
5110 
5111  /* this path can be collapsed into a single thing (PT_NAME is used) */
5112  collapse = parser_new_node (parser, PT_NAME);
5113 
5114  if (collapse)
5115  {
5116  char *n;
5117  collapse->info.name.spec_id = arg1->info.name.spec_id;
5118  n = pt_append_string (parser, NULL, arg1->info.name.original);
5119  n = pt_append_string (parser, n, ".");
5120  n = pt_append_string (parser, n, arg2->info.name.original);
5121  collapse->info.name.original = n;
5122  collapse->info.name.meta_class = PT_NORMAL;
5123  collapse->info.name.resolved = arg1->info.name.resolved;
5125  collapse->next = tree->next;
5126  collapse->data_type = parser_copy_tree (parser, arg1->data_type);
5127  collapse->type_enum = tree->type_enum;
5128  tree->next = NULL;
5129  parser_free_tree (parser, tree);
5130  }
5131 
5132  return collapse;
5133 }
5134 #endif /* ENABLE_UNUSED_FUNCTION */
5135 
5136 /*
5137  * mq_set_types() - sets the type of each item in the select list to
5138  * match the class's attribute type
5139  * return:
5140  * parser(in):
5141  * query_spec(in):
5142  * attributes(in):
5143  * vclass_object(in):
5144  * cascaded_check(in):
5145  */
5146 static PT_NODE *
5147 mq_set_types (PARSER_CONTEXT * parser, PT_NODE * query_spec, PT_NODE * attributes, DB_OBJECT * vclass_object,
5148  int cascaded_check)
5149 {
5150  PT_NODE *col, *prev_col, *next_col, *new_col;
5151  PT_NODE *attr;
5152  PT_NODE *col_type;
5153  PT_NODE *attr_type;
5154  PT_NODE *attr_class;
5155  PT_NODE *flat = NULL;
5156 
5157  if (query_spec == NULL)
5158  {
5159  return NULL;
5160  }
5161 
5162  switch (query_spec->node_type)
5163  {
5164  case PT_SELECT:
5165  if (query_spec->info.query.q.select.from != NULL)
5166  {
5167  flat = query_spec->info.query.q.select.from->info.spec.flat_entity_list;
5168  }
5169  else
5170  {
5171  flat = NULL;
5172  }
5173 
5174  if (cascaded_check)
5175  {
5176  /* the piecemeal local check option list we have accumulated is now pointless. The user requested an honest
5177  * to god useful check option, instead. */
5178  parser_free_tree (parser, query_spec->info.query.q.select.check_where);
5179  query_spec->info.query.q.select.check_where =
5180  parser_copy_tree_list (parser, query_spec->info.query.q.select.where);
5181  }
5182 
5183  while (flat)
5184  {
5185  flat->info.name.virt_object = vclass_object;
5186  flat = flat->next;
5187  }
5188 
5189  attr = attributes;
5190  col = query_spec->info.query.q.select.list;
5191  if (PT_IS_VALUE_QUERY (query_spec) && col != NULL && attr != NULL)
5192  {
5193  assert (col->node_type == PT_NODE_LIST);
5194 
5195  col = col->info.node_list.list;
5196 
5197  /* skip oid */
5198  attr = attr->next;
5199  }
5200  prev_col = NULL;
5201  while (col && attr)
5202  {
5203  /* should check type compatibility here */
5204 
5205  if (attr->info.name.meta_class == PT_SHARED)
5206  {
5207  /* this should not get lambda replaced during translation. An easy way to emulate this is to simply
5208  * overwrite the column that would be replacing this. */
5209  next_col = col->next;
5210  col->next = NULL;
5211  parser_free_tree (parser, col);
5212 
5213  new_col = parser_copy_tree (parser, attr);
5214  new_col->info.name.db_object = vclass_object;
5215  new_col->next = next_col;
5216 
5217  if (prev_col == NULL)
5218  {
5219  query_spec->info.query.q.select.list = new_col;
5220  query_spec->type_enum = new_col->type_enum;
5221  if (query_spec->data_type)
5222  {
5223  parser_free_tree (parser, query_spec->data_type);
5224  }
5225  query_spec->data_type = parser_copy_tree_list (parser, new_col->data_type);
5226  }
5227  else
5228  {
5229  prev_col->next = new_col;
5230  }
5231 
5232  col = new_col;
5233  }
5234  else if (col->type_enum == PT_TYPE_NA || col->type_enum == PT_TYPE_NULL)
5235  {
5236  /* These are compatible with anything */
5237  }
5238  else if (attr->type_enum == PT_TYPE_OBJECT)
5239  {
5240  if ((attr_type = attr->data_type))
5241  {
5242  if (attr->info.name.meta_class == PT_OID_ATTR)
5243  {
5244  /* re-classify OID_ATTR as VID_ATTR */
5245  if (col->node_type == PT_NAME)
5247  }
5248 
5249  /* don't raise an error for the oid placeholder the column may not be an object for non-updatable
5250  * views */
5251  if (!(col_type = col->data_type) || col->type_enum != PT_TYPE_OBJECT)
5252  {
5253  if (attr != attributes)
5254  {
5256  attr->info.name.original);
5257  return NULL;
5258  }
5259  }
5260  else
5261  {
5262  /*
5263  * col_type->info.data_type.virt_type_enum
5264  * IS ALREADY SET!. Don't muck with it.
5265  */
5266  if ((attr_class = attr_type->info.data_type.entity))
5267  {
5268  if (db_is_vclass (attr_class->info.name.db_object) > 0)
5269  {
5270  col_type->info.data_type.virt_object = attr_class->info.name.db_object;
5271  }
5272  }
5273  }
5274  }
5275  }
5276  else if (col->type_enum != attr->type_enum)
5277  {
5278  if (col->node_type == PT_VALUE)
5279  {
5280  (void) pt_coerce_value (parser, col, col, attr->type_enum, attr->data_type);
5281  /* this should also set an error code if it fails */
5282  }
5283  else
5284  { /* need to CAST */
5285  new_col = pt_type_cast_vclass_query_spec_column (parser, attr, col);
5286  if (new_col != col)
5287  {
5288  if (prev_col == NULL)
5289  {
5290  query_spec->info.query.q.select.list = new_col;
5291  query_spec->type_enum = new_col->type_enum;
5292  if (query_spec->data_type)
5293  {
5294  parser_free_tree (parser, query_spec->data_type);
5295  }
5296  query_spec->data_type = parser_copy_tree_list (parser, new_col->data_type);
5297  }
5298  else
5299  {
5300  prev_col->next = new_col;
5301  }
5302 
5303  col = new_col;
5304  }
5305  }
5306  }
5307 
5308  /* save previous link */
5309  prev_col = col;
5310 
5311  /* advance to next attribute and column */
5312  attr = attr->next;
5313  col = col->next;
5314  }
5315 
5316  /* skip hidden column */
5317  while (col)
5318  {
5319  if (col->flag.is_hidden_column)
5320  {
5321  col = col->next;
5322  continue;
5323  }
5324  break;
5325  }
5326 
5327  if (col)
5328  {
5330  db_get_class_name (vclass_object));
5331  return NULL;
5332  }
5333 
5334  if (attr)
5335  {
5337  db_get_class_name (vclass_object));
5338  return NULL;
5339  }
5340 
5341  break;
5342 
5343  case PT_UNION:
5344  case PT_DIFFERENCE:
5345  case PT_INTERSECTION:
5346  mq_set_types (parser, query_spec->info.query.q.union_.arg1, attributes, vclass_object, cascaded_check);
5347  mq_set_types (parser, query_spec->info.query.q.union_.arg2, attributes, vclass_object, cascaded_check);
5348  break;
5349 
5350  default:
5351  /* could flag an error here, this should not happen */
5352  break;
5353  }
5354 
5355  return query_spec;
5356 }
5357 
5358 
5359 /*
5360  * mq_add_dummy_from_pre () - adds a dummy "FROM db-root" to view definitions
5361  * that do not have one.
5362 
5363  * Note: This is required so that the view handling code remains
5364  * consistent with the assumption that each SELECT in a view
5365  * has some hidden OID columns.
5366  * This only happens for views or sub-queries of views.
5367  * return:
5368  * parser(in):
5369  * node(in):
5370  * arg(in):
5371  * continue_walk(in):
5372  */
5373 static PT_NODE *
5374 mq_add_dummy_from_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
5375 {
5376  PT_NODE *fake_from;
5377 
5378  if (!node)
5379  {
5380  return node;
5381  }
5382 
5383  if (node->node_type != PT_SELECT || node->info.query.q.select.from != NULL)
5384  {
5385  return node;
5386  }
5387 
5388  fake_from = pt_add_table_name_to_from_list (parser, node, "db_root", NULL, DB_AUTH_NONE);
5389  if (fake_from == NULL)
5390  {
5391  *continue_walk = PT_STOP_WALK;
5392  return NULL;
5393  }
5394 
5395  return node;
5396 }
5397 
5398 /*
5399  * mq_translate_subqueries() - Translates virtual instance population
5400  * queries of any class
5401  * return: a select or union of selects
5402  * parser(in):
5403  * class_object(in):
5404  * attributes(in):
5405  * authorization(in/out):
5406  */
5407 static PT_NODE *
5408 mq_translate_subqueries (PARSER_CONTEXT * parser, DB_OBJECT * class_object, PT_NODE * attributes,
5409  DB_AUTH * authorization)
5410 {
5411  DB_QUERY_SPEC *db_query_spec;
5412  PT_NODE **result;
5413  PT_NODE *query_spec;
5414  PT_NODE *statements;
5415  PT_NODE *local_query;
5416  const char *query_spec_string;
5417  int cascaded_check;
5418  int local_check;
5419 
5420  if (db_is_class (class_object))
5421  {
5422  return NULL;
5423  }
5424 
5425  /* get query spec's */
5426  db_query_spec = db_get_query_specs (class_object);
5427 
5428  statements = NULL;
5429  local_query = NULL;
5430 
5431  cascaded_check = sm_get_class_flag (class_object, SM_CLASSFLAG_WITHCHECKOPTION);
5432  if (cascaded_check < 0)
5433  {
5434  return NULL;
5435  }
5436  local_check = sm_get_class_flag (class_object, SM_CLASSFLAG_LOCALCHECKOPTION);
5437  if (local_check < 0)
5438  {
5439  return NULL;
5440  }
5441 
5442  while (db_query_spec)
5443  {
5444  /* parse and compile the next query spec */
5445  query_spec_string = db_query_spec_string (db_query_spec);
5446  result = parser_parse_string_use_sys_charset (parser, query_spec_string);
5447 
5448  /* a system error, that allowed a syntax error to be in a query spec string. May want to augment the error
5449  * messages provided by parser_parse_string. */
5450  if (!result)
5451  {
5452  return NULL;
5453  }
5454 
5455  query_spec = *result;
5456 
5457  query_spec = parser_walk_tree (parser, query_spec, mq_add_dummy_from_pre, NULL, NULL, NULL);
5458  if (query_spec == NULL)
5459  {
5460  return NULL;
5461  }
5462 
5463  parser_walk_tree (parser, query_spec, pt_set_is_view_spec, NULL, NULL, NULL);
5464 
5465  /* apply semantic checks */
5466  query_spec = pt_compile (parser, query_spec);
5467 
5468  /* a system error, that allowed a semantic error to be in a query spec string. May want to augment the error
5469  * messages provided by parser_parse_string. */
5470  if (!query_spec)
5471  return NULL;
5472 
5473  if (local_check && query_spec->node_type == PT_SELECT)
5474  {
5475  /* We have a local check option for a simple select statement. This is the ANSI test case. It does not handle
5476  * a union with local check option. However, updatable unions are a CUBRID extension, so big deal.
5477  *
5478  * * We capture the local where clause before appending the nested views where clauses. */
5479  query_spec->info.query.q.select.check_where =
5480  parser_copy_tree_list (parser, query_spec->info.query.q.select.where);
5481  }
5482 
5483  if (authorization)
5484  {
5485  /* if authorizations requested, compute them */
5486  *authorization = (DB_AUTH) (*authorization & mq_compute_query_authorization (query_spec));
5487  }
5488 
5489  /* this will recursively expand the query spec into local queries. The mq_push_paths will convert the expression
5490  * as CNF. if subquery is in the expression, it may be copied several times. To avoid repeatedly convert the
5491  * expressions in subqueries and improve performance, we put mq_push_paths as post function. */
5492  local_query = parser_walk_tree (parser, query_spec, NULL, NULL, mq_push_paths, NULL);
5493  local_query = parser_walk_tree (parser, query_spec, NULL, NULL, mq_translate_local, NULL);
5494 
5495  local_query = pt_add_row_oid_name (parser, local_query);
5496 
5497  mq_set_types (parser, local_query, attributes, class_object, cascaded_check);
5498 
5499  /* Reset references to positions in query_spec_string for each node in this tree. These nodes will be used in
5500  * other contexts and these references are meaningless */
5501  local_query = parser_walk_tree (parser, local_query, mq_reset_references_to_query_string, NULL, NULL, NULL);
5502  if (local_query == NULL)
5503  {
5504  return NULL;
5505  }
5506 
5507  if (statements == NULL)
5508  {
5509  statements = local_query;
5510  }
5511  else if (local_query)
5512  {
5513  statements = pt_union (parser, statements, local_query);
5514  }
5515 
5516  db_query_spec = db_query_spec_next (db_query_spec);
5517  }
5518 
5519  return statements;
5520 }
5521 
5522 
5523 /*
5524  * mq_invert_assign() - Translates invertible expression into an
5525  * assignment expression
5526  * return:
5527  * parser(in):
5528  * attr(in):
5529  * expr(in):
5530  */
5531 static void
5532 mq_invert_assign (PARSER_CONTEXT * parser, PT_NODE * attr, PT_NODE * &expr, PT_NODE * inverted)
5533 {
5534  PT_NODE *result;
5535  const char *attr_name;
5536 
5537  assert (inverted != NULL);
5538 
5539  result = parser_new_node (parser, PT_EXPR);
5540 
5541  if (result == NULL)
5542  {
5543  PT_INTERNAL_ERROR (parser, "allocate new node");
5544  return;
5545  }
5546 
5547  result->info.expr.op = PT_ASSIGN;
5548 
5549  result->etc = attr;
5550  attr_name = attr->info.name.original;
5551  /* need to convert attr to value holder */
5552  attr->node_type = PT_VALUE;
5553  /* make info.value set up properly */
5554  memset (&(attr->info), 0, sizeof (attr->info));
5555  attr->info.value.text = attr_name;
5556  result->info.expr.arg1 = inverted->next; /* name */
5557  inverted->next = NULL;
5558  attr->next = NULL;
5559  result->info.expr.arg2 = inverted; /* right hand side */
5560 
5561  expr = result;
5562 }
5563 
5564 
5565 /*
5566  * mq_invert_subqueries() - Translates invertible subquery expressions into
5567  * an assignment expression
5568  * return:
5569  * parser(in):
5570  * select_statements(in):
5571  * attributes(in):
5572  */
5573 static void
5574 mq_invert_subqueries (PARSER_CONTEXT * parser, PT_NODE * select_statements, PT_NODE * attributes)
5575 {
5576  PT_NODE **column = NULL;
5577  PT_NODE *attr = NULL;
5578  PT_NODE *column_next = NULL;
5579  PT_NODE *attr_next = NULL;
5580  PT_NODE **column_prev = NULL;
5581  PT_NODE *inverted = NULL;
5582  PT_NODE **head = NULL;
5583  PT_NODE *temp = NULL;
5584 
5585  while (select_statements)
5586  {
5587  column = &select_statements->info.query.q.select.list;
5588  attr = parser_copy_tree_list (parser, attributes);
5589 
5590  // save the head before deleting a node if necesserary
5591  head = column;
5592 
5593  while (attr)
5594  {
5595  column_next = (*column)->next;
5596  attr_next = attr->next;
5597 
5598  // try to invert the node
5599  inverted = pt_invert (parser, *column, attr);
5600 
5601  // to avoid creating a new "empty" node, we better delete the column from the list
5602  if (inverted == NULL)
5603  {
5604  assert (!pt_has_error (parser));
5605 
5606  temp = *column;
5607  temp->next = NULL;
5608 
5609  if (column_prev != NULL)
5610  {
5611  // link the previous node to the next node
5612  (*column_prev)->next = column_next;
5613  }
5614  else
5615  {
5616  // move head to the right
5617  head = &column_next;
5618  }
5619 
5620  // move forward in list
5621  column = &((*column_prev)->next);
5622 
5623  // avoid a mem leak
5624  parser_free_tree (parser, temp);
5625  }
5626  else
5627  {
5628  // we change the column with the assignment
5629  mq_invert_assign (parser, attr, *column, inverted);
5630 
5631  if (*column == NULL)
5632  {
5633  break;
5634  }
5635 
5636  // set the link of the new node to next
5637  (*column)->next = column_next;
5638  column_prev = column;
5639  // move forward in list
5640  column = &((*column)->next);
5641  }
5642 
5643  attr = attr_next;
5644  }
5645 
5646  select_statements->info.query.q.select.list = *head;
5647  select_statements = select_statements->next;
5648  }
5649 }
5650 
5651 
5652 /*
5653  * mq_set_non_updatable_oid() -
5654  * return: none
5655  * parser(in): the parser context used to derive stmt
5656  * stmt(in/out): a SELECT/UNION/DIFFERENCE/INTERSECTION statement
5657  * virt_entity(in):
5658  */
5659 static void
5661 {
5662  PT_NODE *select_list;
5663 
5664  if (!parser || !stmt)
5665  {
5666  return;
5667  }
5668 
5669  switch (stmt->node_type)
5670  {
5671  case PT_SELECT:
5672  select_list = stmt->info.query.q.select.list;
5673  if (select_list != NULL && !PT_IS_VALUE_QUERY (stmt))
5674  {
5675  DB_VALUE vid;
5676 
5677  select_list->node_type = PT_FUNCTION;
5678  /* make info set up properly */
5679  memset (&(select_list->info), 0, sizeof (select_list->info));
5680  select_list->data_type->info.data_type.entity = NULL;
5682  select_list->type_enum = PT_TYPE_OBJECT;
5683 
5684  /* set vclass_name as literal string */
5685  db_make_string (&vid, db_get_class_name (virt_entity->info.name.db_object));
5686  select_list->info.function.arg_list = pt_dbval_to_value (parser, &vid);
5687  select_list->info.function.function_type = F_SEQUENCE;
5688 
5689  select_list->data_type->info.data_type.virt_object = virt_entity->info.name.db_object;
5690 
5691  pr_clear_value (&vid);
5692  }
5693  break;
5694  case PT_UNION:
5695  case PT_INTERSECTION:
5696  case PT_DIFFERENCE:
5697  mq_set_non_updatable_oid (parser, stmt->info.query.q.union_.arg1, virt_entity);
5698  mq_set_non_updatable_oid (parser, stmt->info.query.q.union_.arg2, virt_entity);
5699  break;
5700  default:
5701  break;
5702  }
5703 }
5704 
5705 /*
5706  * mq_check_cycle() -
5707  * return: true if the class object is found in the cycle detection buffer
5708  * fasle if not found, and add the object to the buffer
5709  * class_object(in):
5710  */
5711 static bool
5712 mq_check_cycle (DB_OBJECT * class_object)
5713 {
5714  unsigned int i, max, enter;
5715 
5716  enter = top_cycle % MAX_CYCLE;
5717  max = top_cycle < MAX_CYCLE ? top_cycle : MAX_CYCLE;
5718 
5719  for (i = 0; i < max; i++)
5720  {
5721  if (cycle_buffer[i] == class_object)
5722  {
5723  return true;
5724  }
5725  }
5726 
5727  /* otherwise increment top cycle and enter object in buffer */
5728  cycle_buffer[enter] = class_object;
5729  top_cycle++;
5730 
5731  return false;
5732 }
5733 
5734 
5735 /*
5736  * mq_free_virtual_query_cache() - Clear parse trees used for view translation,
5737  * and the cached parser
5738  * return: none
5739  * parser(in):
5740  */
5741 void
5743 {
5744  VIEW_CACHE_INFO *info;
5745 
5746  /* symbols is used to hold the virtual query cache */
5747  info = (VIEW_CACHE_INFO *) parser->view_cache;
5748 
5749  parser_free_tree (parser, info->attrs);
5750  parser_free_tree (parser, info->vquery_for_query);
5751  parser_free_tree (parser, info->vquery_for_query_in_gdb);
5752  parser_free_tree (parser, info->vquery_for_update);
5757 
5758  parser_free_parser (parser);
5759 
5760  return;
5761 }
5762 
5763 /*
5764  * mq_virtual_queries() - recursively expands each query against a view or
5765  * virtual class
5766  * return:
5767  * class_object(in):
5768  */
5771 {
5772  char buf[2000];
5773  const char *cname = db_get_class_name (class_object);
5774  PARSER_CONTEXT *parser = parser_create_parser ();
5775  PT_NODE **statements;
5776  VIEW_CACHE_INFO *symbols;
5777  DB_OBJECT *me = db_get_user ();
5778  DB_OBJECT *owner = db_get_owner (class_object);
5779 
5780  if (parser == NULL)
5781  {
5782  return NULL;
5783  }
5784 
5785  snprintf (buf, sizeof (buf), "select * from [%s]; ", cname);
5786  statements = parser_parse_string (parser, buf);
5787  parser->view_cache = (VIEW_CACHE_INFO *) parser_alloc (parser, sizeof (VIEW_CACHE_INFO));
5788  symbols = parser->view_cache;
5789 
5790  if (symbols == NULL)
5791  {
5792  PT_INTERNAL_ERROR (parser, "parser_alloc");
5793  return NULL;
5794  }
5795  symbols->nested_views = NULL;
5796 
5797  if (!ws_is_same_object (owner, me))
5798  {
5799  symbols->authorization = mq_compute_authorization (class_object);
5800  }
5801  else
5802  {
5803  /* no authorization check */
5804  symbols->authorization = DB_AUTH_ALL;
5805  }
5806 
5807  if (statements)
5808  {
5809  if (mq_check_cycle (class_object))
5810  {
5812  }
5813  }
5814 
5815  if (statements && !pt_has_error (parser))
5816  {
5818 
5819  statements[0] = pt_compile (parser, statements[0]);
5820 
5821  statements[0] = pt_add_row_oid_name (parser, statements[0]);
5822 
5823  if (statements[0] && !pt_has_error (parser))
5824  {
5825  symbols->attrs = statements[0]->info.query.q.select.list;
5827 
5828  statements[0]->info.query.q.select.list = NULL;
5829  parser_free_tree (parser, statements[0]);
5830 
5831  if (!ws_is_same_object (owner, me))
5832  {
5833  /* set user to owner to translate query specification. */
5834  AU_SET_USER (owner);
5835  }
5836 
5837  symbols->vquery_for_query =
5838  mq_translate_subqueries (parser, class_object, symbols->attrs, &symbols->authorization);
5839 
5840  /* no need to recheck authorizations */
5841  symbols->vquery_for_query_in_gdb = mq_translate_subqueries (parser, class_object, symbols->attrs, NULL);
5842 
5843  if (!pt_has_error (parser) && symbols->vquery_for_query)
5844  {
5845  PT_UPDATABILITY updatable = mq_updatable (parser, symbols->vquery_for_query);
5846 
5847  if (updatable == PT_PARTIALLY_UPDATABLE)
5848  {
5851  }
5852  else if (updatable == PT_UPDATABLE)
5853  {
5854  symbols->vquery_for_update = parser_copy_tree_list (parser, symbols->vquery_for_query);
5855  symbols->vquery_for_update = mq_flatten_union (parser, symbols->vquery_for_update);
5856 
5859 
5860  symbols->inverted_vquery_for_update =
5862 
5863  mq_invert_subqueries (parser, symbols->inverted_vquery_for_update, symbols->attrs);
5864 
5867 
5868  mq_invert_subqueries (parser, symbols->inverted_vquery_for_update_in_gdb, symbols->attrs);
5869  }
5870 
5871  if (updatable != PT_UPDATABLE)
5872  {
5873  PT_NODE *virt_class = parser_copy_tree (parser,
5874  symbols->attrs);
5875  if (virt_class == NULL)
5876  {
5877  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
5878  return NULL;
5879  }
5880 
5881  virt_class->info.name.db_object = class_object;
5882 
5883  mq_set_non_updatable_oid (parser, symbols->vquery_for_query, virt_class);
5884  mq_set_non_updatable_oid (parser, symbols->vquery_for_query_in_gdb, virt_class);
5885 
5886  parser_free_tree (parser, virt_class);
5887  }
5888  }
5889  }
5890  }
5891 
5892  if (!ws_is_same_object (owner, me))
5893  {
5894  /* set user to me */
5895  AU_SET_USER (me);
5896  }
5897 
5898  /* end cycle check */
5899  if (top_cycle > 0)
5900  {
5901  top_cycle--;
5902  cycle_buffer[top_cycle % MAX_CYCLE] = NULL;
5903  }
5904  else
5905  {
5906  top_cycle = 0;
5907  }
5908 
5909  return parser;
5910 }
5911 
5912 /*
5913  * mq_mark_location() -
5914  * return:
5915  * parser(in):
5916  * node(in):
5917  * arg(in):
5918  * continue_walk(in):
5919  */
5920 static PT_NODE *
5921 mq_mark_location (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
5922 {
5923  short *locp = (short *) arg;
5924 
5925  if (!locp && node->node_type == PT_SELECT)
5926  {
5927  short location = 0;
5928  PT_NODE *spec, *on_cond;
5929 
5930  for (spec = node->info.query.q.select.from; spec; spec = spec->next)
5931  {
5932  spec->info.spec.location = location++;
5933  on_cond = spec->info.spec.on_cond;
5934  if (on_cond)
5935  {
5936  switch (spec->info.spec.join_type)
5937  {
5938  case PT_JOIN_INNER:
5939  case PT_JOIN_LEFT_OUTER:
5940  case PT_JOIN_RIGHT_OUTER:
5941  parser_walk_tree (parser, on_cond, mq_mark_location, &(spec->info.spec.location), NULL, NULL);
5942  break;
5943  /* case PT_JOIN_FULL_OUTER: not supported */
5944 
5945  case PT_JOIN_NONE:
5946  default:
5947  break;
5948  } /* switch (spec->info.spec.join_type) */
5949 
5950  /* ON cond will be moved at optimize_queries */
5951  }
5952 
5953  if (spec->info.spec.entity_name)
5954  {
5955  PT_NODE *node = spec->info.spec.entity_name;
5956 
5957  if (node->node_type == PT_NAME)
5958  {
5959  node->info.name.location = spec->info.spec.location;
5960  }
5961  else if (node->node_type == PT_SPEC)
5962  {
5963  node->info.spec.location = spec->info.spec.location;
5964  }
5965  else
5966  {
5967  /* dummy else. this case will not happen */
5968  assert (0);
5969  }
5970  }
5971  }
5972  }
5973  else if (locp)
5974  {
5975  if (node->node_type == PT_EXPR)
5976  {
5977  node->info.expr.location = *locp;
5978  }
5979  else if (node->node_type == PT_NAME)
5980  {
5981  node->info.name.location = *locp;
5982  }
5983  else if (node->node_type == PT_VALUE)
5984  {
5985  node->info.value.location = *locp;
5986  }
5987  }
5988 
5989  return node;
5990 }
5991 
5992 /*
5993  * mq_check_non_updatable_vclass_oid() -
5994  * return:
5995  * parser(in):
5996  * node(in):
5997  * arg(in):
5998  * continue_walk(in):
5999  */
6000 static PT_NODE *
6001 mq_check_non_updatable_vclass_oid (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6002 {
6003  PT_NODE *dt;
6004  DB_OBJECT *vclass;
6005  bool strict = true, updatable;
6006 
6007  if (void_arg != NULL)
6008  {
6009  strict = *((bool *) void_arg);
6010  }
6011 
6012  switch (node->node_type)
6013  {
6014  case PT_FUNCTION:
6015  if (node->type_enum == PT_TYPE_OBJECT && (dt = node->data_type) && dt->type_enum == PT_TYPE_OBJECT
6016  && (vclass = dt->info.data_type.virt_object))
6017  {
6018  /* check for non-updatable vclass oid */
6019  if (strict)
6020  {
6021  updatable = mq_is_updatable_strict (vclass);
6022  }
6023  else
6024  {
6025  updatable = mq_is_updatable (vclass);
6026  }
6027 
6028  if (!updatable)
6029  {
6030  /* OID of non-updatable vclass found */
6032  /* use function to get name */
6033  db_get_class_name (vclass));
6034  *continue_walk = PT_STOP_WALK;
6035  }
6036  }
6037  break;
6038  default:
6039  break;
6040  }
6041 
6042  return node;
6043 }
6044 
6045 /*
6046  * mq_check_vclass_for_insert () - checks if view definition is valid for
6047  * INSERT statements (i.e. has only one target)
6048  * return: initial node
6049  * parser(in): parser context
6050  * query_spec(in): view definition
6051  */
6052 static bool
6054 {
6055  PT_NODE *spec = NULL;
6056 
6057  if (query_spec == NULL || query_spec->node_type != PT_SELECT)
6058  {
6059  /* nothing to do */
6060  return true;
6061  }
6062 
6063  /* fetch spec; if spec has a "next" it won't be updatable and the statement will be invalidated later */
6064  spec = query_spec->info.query.q.select.from;
6065  if (spec->info.spec.flat_entity_list && spec->info.spec.flat_entity_list->next)
6066  {
6068  return false;
6069  }
6070  else if (PT_SPEC_IS_DERIVED (spec))
6071  {
6072  return mq_check_vclass_for_insert (parser, spec->info.spec.derived_table);
6073  }
6074  else
6075  {
6076  assert (!PT_SPEC_IS_CTE (spec));
6077  }
6078 
6079  /* valid */
6080  return true;
6081 }
6082 
6083 /*
6084  * mq_rewrite_upd_del_top_level_specs () - rewrite top-level specs of UPDATE or
6085  * DELETE statements that are spec sets
6086  * or refer views with multiple queries
6087  * return: initial node
6088  * parser(in): parser context
6089  * statement(in): statement
6090  * arg(in):
6091  * continue_walk(in):
6092  */
6093 static PT_NODE *
6094 mq_rewrite_upd_del_top_level_specs (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk)
6095 {
6096  PT_NODE **spec = NULL;
6097 
6098  if (statement == NULL)
6099  {
6100  /* nothing to do */
6101  return NULL;
6102  }
6103 
6104  /* mark specs that will be subject to update or delete and retrieve spec list */
6105  switch (statement->node_type)
6106  {
6107  case PT_UPDATE:
6108  pt_mark_spec_list_for_update (parser, statement);
6109  spec = &statement->info.update.spec;
6110  break;
6111 
6112  case PT_DELETE:
6113  pt_mark_spec_list_for_delete (parser, statement);
6114  spec = &statement->info.delete_.spec;
6115  break;
6116 
6117  case PT_MERGE:
6118  spec = &statement->info.merge.into;
6119  if (statement->info.merge.update.assignment)
6120  {
6121  pt_mark_spec_list_for_update (parser, statement);
6122  if (statement->info.merge.update.has_delete)
6123  {
6124  pt_mark_spec_list_for_delete (parser, statement);
6125  }
6126  }
6127  break;
6128 
6129  case PT_INSERT:
6130  /* INSERT does not support rewrites so we must check that no rewrite is needed */
6131  spec = &statement->info.insert.spec;
6132  break;
6133 
6134  default:
6135  /* nothing to do */
6136  return statement;
6137  }
6138 
6139  while (*spec)
6140  {
6141  /* view definitions for select and for update might look different, so make sure to fetch the correct one */
6142  bool fetch_for_update = ((*spec)->info.spec.flag & PT_SPEC_FLAG_UPDATE)
6143  || ((*spec)->info.spec.flag & PT_SPEC_FLAG_DELETE) || (statement->node_type == PT_INSERT);
6144 
6145  if (fetch_for_update)
6146  {
6147  /* this will fetch a view spec in some illegal cases (e.g. DELETE on a view containing joins); these cases
6148  * will be handled later on */
6149  }
6150 
6151  if ((*spec)->info.spec.flat_entity_list)
6152  {
6153  /* fetch entity list */
6154  PT_NODE *subquery = NULL;
6155  PT_NODE *entity = (*spec)->info.spec.flat_entity_list;
6156  /* rewrite if multiple entities */
6157  bool multiple_entity = (entity != NULL && entity->next != NULL);
6158  bool rewrite = false, has_vclass = false;
6159 
6160  assert (!PT_SPEC_IS_CTE (*spec) && !PT_SPEC_IS_DERIVED (*spec));
6161 
6162  while (entity)
6163  {
6164  if (mq_translatable_class (parser, entity))
6165  {
6166  has_vclass = true;
6167 
6168  /* fetch class even if we've decided to rewrite; we need the definition later on */
6169  if (!fetch_for_update)
6170  {
6171  subquery = mq_fetch_subqueries (parser, entity);
6172  }
6173  else
6174  {
6175  subquery = mq_fetch_subqueries_for_update (parser, entity, PT_PARTIAL_SELECT, DB_AUTH_SELECT);
6176  }
6177 
6178  if (subquery != NULL && subquery->next != NULL)
6179  {
6180  /* rewrite if multiple queries in view spec */
6181  rewrite = true;
6182  }
6183  }
6184 
6185  entity = entity->next;
6186  }
6187 
6188  if (multiple_entity && has_vclass)
6189  {
6190  /* if at least one entity is a view, we need to rewrite */
6191  rewrite = true;
6192  }
6193 
6194  if (statement->node_type == PT_INSERT)
6195  {
6196  if (rewrite)
6197  {
6198  /* can't rewrite INSERT spec, throw error */
6200  return statement;
6201  }
6202  else
6203  {
6204  /* check deeper in view spec; errors will be set in mq_check_vclass_for_insert call, so there is no
6205  * reason to handle return value */
6206  (void) mq_check_vclass_for_insert (parser, subquery);
6207  }
6208  }
6209 
6210  if (rewrite)
6211  {
6212  /* rewrite is necessary */
6213  *spec = mq_rewrite_vclass_spec_as_derived (parser, statement, *spec, subquery);
6214  }
6215  }
6216 
6217  /* next! */
6218  spec = &((*spec)->next);
6219  }
6220 
6221  return statement;
6222 }
6223 
6224 /*
6225  * mq_translate_helper() - main workhorse for mq_translate
6226  * return:
6227  * parser(in):
6228  * node(in):
6229  */
6230 static PT_NODE *
6232 {
6233  PT_NODE *next;
6234  int err = NO_ERROR;
6235  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
6236  bool strict = true;
6237 
6238  if (!node)
6239  {
6240  return NULL;
6241  }
6242 
6243  sc_info.top_node = node;
6244  sc_info.donot_fold = false;
6245 
6246  /* save and zero link */
6247  next = node->next;
6248  node->next = NULL;
6249 
6250  switch (node->node_type)
6251  {
6252  /* only translate translatable statements */
6253  case PT_SELECT:
6255  /* FALLTHRU */
6256 
6257  case PT_UNION:
6258  case PT_DIFFERENCE:
6259  case PT_INTERSECTION:
6260  /*
6261  * The mq_push_paths will convert the expression as CNF. if subquery is
6262  * in the expression, it may be copied several times. To avoid repeatedly
6263  * convert the expressions in subqueries and improve performance, we
6264  * put mq_push_paths as post function.
6265  */
6266  node = parser_walk_tree (parser, node, NULL, NULL, mq_push_paths, NULL);
6267  node = parser_walk_tree (parser, node, NULL, NULL, mq_translate_local, NULL);
6268 
6269  mq_bump_order_dep_corr_lvl (parser, node);
6270 
6271  node = parser_walk_tree (parser, node, mq_mark_location, NULL, mq_check_non_updatable_vclass_oid, &strict);
6272 
6273  if (pt_has_error (parser))
6274  {
6275  goto exit_on_error;
6276  }
6277 
6278  if (node)
6279  {
6280  node->info.query.is_subquery = (PT_MISC_TYPE) (-1);
6281  if (node->node_type != PT_SELECT)
6282  {
6285  }
6286  }
6287 
6288  if (node)
6289  {
6290  /* mq_optimize works for queries only. Queries generated for update, insert or delete will go thru this path
6291  * when mq_translate is called, so will still get this optimization step applied. */
6292  node = mq_optimize (parser, node);
6293 
6294  /* repeat for constant folding */
6295  if (node)
6296  {
6297  node = pt_semantic_type (parser, node, &sc_info);
6298  }
6299  }
6300  break;
6301 
6302  case PT_INSERT:
6303  case PT_DELETE:
6304  case PT_UPDATE:
6305  case PT_MERGE:
6306  case PT_DO:
6307  /*
6308  * The mq_push_paths will convert the expression as CNF. if subquery is
6309  * in the expression, it may be copied several times. To avoid repeatedly
6310  * convert the expressions in subqueries and improve performance, we
6311  * put mq_push_paths as post function.
6312  */
6313  node = parser_walk_tree (parser, node, NULL, NULL, mq_push_paths, NULL);
6315 
6316  strict = false; /* no strict OID checking */
6317  node = parser_walk_tree (parser, node, mq_mark_location, NULL, mq_check_non_updatable_vclass_oid, &strict);
6318 
6319  if (pt_has_error (parser))
6320  {
6321  goto exit_on_error;
6322  }
6323 
6324  if (node)
6325  {
6326  node = mq_optimize (parser, node);
6327  if (node->node_type == PT_MERGE)
6328  {
6329  mq_auto_param_merge_clauses (parser, node);
6330  }
6331  /* repeat for constant folding */
6332  if (node)
6333  {
6334  node = pt_semantic_type (parser, node, &sc_info);
6335  }
6336  }
6337  break;
6338 
6339  default:
6340  break;
6341  }
6342 
6343  /* process FOR UPDATE clause */
6344  err = pt_for_update_prepare_query (parser, node);
6345  if (err != NO_ERROR)
6346  {
6347  return NULL;
6348  }
6349 
6350  /* restore link */
6351  if (node)
6352  {
6353  node->next = next;
6354  }
6355 
6356  if (pt_has_error (parser))
6357  {
6358  goto exit_on_error;
6359  }
6360 
6361  return node;
6362 
6363 exit_on_error:
6364 
6365  return NULL;
6366 }
6367 
6368 /*
6369  * pt_check_for_update_subquery() - check if there is a subquery with
6370  * FOR UPDATE clause.
6371  * return:
6372  * parser(in):
6373  * node(in):
6374  * arg(in/out): an address of an int. 0 for root, 1 if not root and error
6375  * code if a subquery with FOR UPDATE clause was found.
6376  * continue_walk(in):
6377  */
6378 static PT_NODE *
6379 pt_check_for_update_subquery (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
6380 {
6381  if (!*(int *) arg)
6382  {
6383  /* Processed the root node. All remaining PT_SELECT nodes are subqueries */
6384  *(int *) arg = 1;
6385  }
6386  else if (node->node_type == PT_SELECT)
6387  {
6389  {
6390  /* found a subquery with FOR UPDATE clause */
6392  *(int *) arg = ER_FAILED;
6393  *continue_walk = PT_STOP_WALK;
6394  return node;
6395  }
6396  }
6397 
6398  return node;
6399 }
6400 
6401 /*
6402  * pt_check_for_update_clause() - check the query for invalid use of FOR UPDATE
6403  * clause
6404  * return: NO_ERROR or error code
6405  * parser(in):
6406  * query(in): statement to be checked
6407  * root(in): true if this is the main statement and false otherwise.
6408  *
6409  * NOTE: Always call this function with root set to true. false value is used
6410  * internally.
6411  */
6412 static int
6413 pt_check_for_update_clause (PARSER_CONTEXT * parser, PT_NODE * query, bool root)
6414 {
6415  int error_code = 0;
6416  PT_NODE *spec = NULL, *next = NULL;
6417 
6418  if (query == NULL)
6419  {
6420  return NO_ERROR;
6421  }
6422 
6423  /* check for subqueries with FOR UPDATE clause */
6424  if (root)
6425  {
6426  next = query->next;
6427  query->next = NULL;
6428  parser_walk_tree (parser, query, pt_check_for_update_subquery, &error_code, NULL, NULL);
6429  query->next = next;
6430  if (error_code < 0)
6431  {
6432  return error_code;
6433  }
6434  }
6435 
6436  /* FOR UPDATE is availbale only in SELECT statements */
6437  if (query->node_type != PT_SELECT)
6438  {
6439  if (!root && PT_IS_QUERY (query))
6440  {
6442  return ER_FAILED;
6443  }
6444  return NO_ERROR;
6445  }
6446 
6447  /* Skip check if this is not a query with FOR UPDATE clause */
6449  {
6450  return NO_ERROR;
6451  }
6452 
6453  /* check for aggregate functions, GROUP BY and DISTINCT */
6454  if (pt_has_aggregate (parser, query) || pt_is_distinct (query))
6455  {
6457  return ER_FAILED;
6458  }
6459 
6460  /* check derived tables */
6461  for (spec = query->info.query.q.select.from; spec != NULL; spec = spec->next)
6462  {
6463  if ((!root || (spec->info.spec.flag & PT_SPEC_FLAG_FOR_UPDATE_CLAUSE)) && spec->info.spec.derived_table != NULL)
6464  {
6465  error_code = pt_check_for_update_clause (parser, spec->info.spec.derived_table, false);
6466  if (error_code != NO_ERROR)
6467  {
6468  return error_code;
6469  }
6470  }
6471  }
6472 
6473  return NO_ERROR;
6474 }
6475 
6476 /*
6477  * pt_for_update_prepare_query_internal() - reflag specs from FOR UPDATE
6478  * including those from subqueries
6479  * return: NO_ERROR or error code
6480  * parser(in):
6481  * query(in/out): query for which the specs are flagged.
6482  */
6483 static int
6485 {
6486  PT_NODE *from = NULL, *spec = NULL;
6487  bool has_for_update = false;
6488  int err = NO_ERROR;
6489 
6490  if (query == NULL || query->node_type != PT_SELECT)
6491  {
6492  return NO_ERROR;
6493  }
6494 
6495  has_for_update = (PT_SELECT_INFO_IS_FLAGED (query, PT_SELECT_INFO_FOR_UPDATE) ? true : false);
6496  from = query->info.query.q.select.from;
6497  for (spec = from; spec != NULL; spec = spec->next)
6498  {
6499  if (has_for_update && !(spec->info.spec.flag & PT_SPEC_FLAG_FOR_UPDATE_CLAUSE))
6500  {
6501  /* skip if the spec is not flagged for FOR UPDATE */
6502  continue;
6503  }
6504  if (spec->info.spec.derived_table != NULL)
6505  {
6506  err = pt_for_update_prepare_query_internal (parser, spec->info.spec.derived_table);
6507  if (err != NO_ERROR)
6508  {
6509  return err;
6510  }
6511  }
6512  else
6513  {
6514  spec->info.spec.flag = (PT_SPEC_FLAG) (spec->info.spec.flag | PT_SPEC_FLAG_FOR_UPDATE_CLAUSE);
6515  }
6516  }
6517 
6518  return NO_ERROR;
6519 }
6520 
6521 /*
6522  * pt_for_update_prepare_query() - check FOR UPDATE clause and reflag specs from
6523  * FOR UPDATE
6524  * return: returns the modified query.
6525  * parser(in):
6526  * query(in/out): query with FOR UPDATE clause for which the check and spec
6527  * flagging is made.
6528  */
6529 static int
6531 {
6532  int err = NO_ERROR;
6533 
6534  if (query == NULL)
6535  {
6536  return NO_ERROR;
6537  }
6538 
6539  err = pt_check_for_update_clause (parser, query, true);
6540  if (err != NO_ERROR)
6541  {
6542  return err;
6543  }
6544 
6546  {
6547  return NO_ERROR;
6548  }
6549 
6550  err = pt_for_update_prepare_query_internal (parser, query);
6551 
6552  return err;
6553 }
6554 
6555 /*
6556  * mq_translate() - expands each query against a view or virtual class
6557  * return:
6558  * parser(in):
6559  * node(in):
6560  */
6561 PT_NODE *
6562 mq_translate (PARSER_CONTEXT * parser, PT_NODE * volatile node)
6563 {
6564  volatile PT_NODE *return_node = NULL;
6565 
6566  if (!node)
6567  {
6568  return NULL;
6569  }
6570 
6571  /* set up an environment for longjump to return to if there is an out of memory error in pt_memory.c. DO NOT RETURN
6572  * unless PT_CLEAR_JMP_ENV is called to clear the environment. */
6573  PT_SET_JMP_ENV (parser);
6574 
6575  return_node = mq_translate_helper (parser, node);
6576 
6577  PT_CLEAR_JMP_ENV (parser);
6578 
6579  return (PT_NODE *) return_node;
6580 }
6581 
6582 
6583 
6584 /*
6585  *
6586  * Function group:
6587  * Functions for the translation of virtual queries
6588  *
6589  */
6590 
6591 
6592 /*
6593  * pt_lookup_symbol() -
6594  * return: symbol we are looking for, or NULL if not found
6595  * parser(in):
6596  * attr_list(in): attribute list to look for attr in
6597  * attr(in): attr to look for
6598  */
6599 static PT_NODE *
6601 {
6602  PT_NODE *list;
6603 
6604  if (!attr || attr->node_type != PT_NAME)
6605  {
6606  PT_INTERNAL_ERROR (parser, "resolution");
6607  return NULL;
6608  }
6609 
6610  for (list = attr_list; (list != NULL) && (!pt_name_equal (parser, list, attr)); list = list->next)
6611  {
6612  ; /* do nothing */
6613  }
6614 
6615  return list;
6616 }
6617 
6618 /*
6619  * mq_insert_symbol() - appends the symbol to the entities
6620  * return: none
6621  * parser(in): parser environment
6622  * listhead(in/out): entity_spec to add symbol to
6623  * attr(in): the attribute to add to the symbol table
6624  */
6625 void
6626 mq_insert_symbol (PARSER_CONTEXT * parser, PT_NODE ** listhead, PT_NODE * attr)
6627 {
6628  PT_NODE *new_node;
6629 
6630  if (!attr || attr->node_type != PT_NAME)
6631  {
6632  PT_INTERNAL_ERROR (parser, "translate");
6633  return;
6634  }
6635 
6636  /* only insert attributes */
6637  if (attr->info.name.meta_class == PT_PARAMETER)
6638  {
6639  return;
6640  }
6641 
6642  new_node = mq_lookup_symbol (parser, *listhead, attr);
6643  if (new_node == NULL)
6644  {
6645  new_node = parser_copy_tree (parser, attr);
6646  *listhead = parser_append_node (new_node, *listhead);
6647  }
6648 }
6649 
6650 /*
6651  * mq_generate_name() - generates printable names
6652  * return:
6653  * parser(in):
6654  * root(in):
6655  * version(in):
6656  */
6657 const char *
6658 mq_generate_name (PARSER_CONTEXT * parser, const char *root, int *version)
6659 {
6660  const char *generatedname;
6661  char temp[20];
6662 
6663  (*version)++;
6664 
6665  sprintf (temp, "_%d", *version);
6666 
6667  /* avoid "stepping" on root */
6668  generatedname = pt_append_string (parser, pt_append_string (parser, NULL, root), temp);
6669  return generatedname;
6670 }
6671 
6672 /*
6673  * mq_coerce_resolved() - re-sets PT_NAME node resolution to match
6674  * a new printable name
6675  * return:
6676  * parser(in):
6677  * node(in):
6678  * void_arg(in):
6679  * continue_walk(in/out):
6680  */
6681 static PT_NODE *
6682 mq_coerce_resolved (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6683 {
6684  PT_NODE *range = (PT_NODE *) void_arg;
6685  *continue_walk = PT_CONTINUE_WALK;
6686 
6687  /* if its not a name, leave it alone */
6688  if (node->node_type == PT_NAME)
6689  {
6690 
6691  if (node->info.name.spec_id == range->info.name.spec_id /* same entity spec */
6692  && node->info.name.resolved /* and has a resolved name, */
6693  && node->info.name.meta_class != PT_CLASS && node->info.name.meta_class != PT_VCLASS)
6694  {
6695  /* set the attribute resolved name */
6696  node->info.name.resolved = range->info.name.original;
6697  }
6698 
6699  /* sub nodes of PT_NAME are not names with range variables */
6700  *continue_walk = PT_LIST_WALK;
6701  }
6702  else if (node->node_type == PT_SPEC && node->info.spec.id == range->info.name.spec_id)
6703  {
6704  PT_NODE *flat = node->info.spec.flat_entity_list;
6705  /* sub nodes of PT_SPEC include flat class lists with range variables. Set them even though they are "class"
6706  * names. */
6707 
6708  for (; flat != NULL; flat = flat->next)
6709  {
6710  flat->info.name.resolved = range->info.name.original;
6711  }
6712  }
6713 
6714  return node;
6715 }
6716 
6717 /*
6718  * mq_set_all_ids() - sets PT_NAME node ids
6719  * return:
6720  * parser(in):
6721  * node(in):
6722  * void_arg(in):
6723  * continue_walk(in):
6724  */
6725 static PT_NODE *
6726 mq_set_all_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6727 {
6728  PT_NODE *spec = (PT_NODE *) void_arg;
6729 
6730  if (node->node_type == PT_NAME)
6731  {
6732  node->info.name.spec_id = spec->info.spec.id;
6734  }
6735 
6736  node->spec_ident = spec->info.spec.id;
6737 
6738  return node;
6739 }
6740 
6741 
6742 /*
6743  * mq_reset_all_ids() - re-sets PT_NAME node ids
6744  * return:
6745  * parser(in):
6746  * node(in):
6747  * void_arg(in):
6748  * continue_walk(in):
6749  */
6750 static PT_NODE *
6751 mq_reset_all_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6752 {
6753  PT_NODE *spec = (PT_NODE *) void_arg;
6754 
6755  if (node->node_type == PT_NAME && node->info.name.spec_id == spec->info.spec.id)
6756  {
6757  node->info.name.spec_id = (UINTPTR) spec;
6758  if (node->info.name.resolved /* has a resolved name */
6759  && node->info.name.meta_class != PT_CLASS && node->info.name.meta_class != PT_VCLASS)
6760  {
6761  /* set the attribute resolved name */
6763  }
6764 
6765  }
6766  else if (node->node_type == PT_SPEC && node->info.spec.id == spec->info.spec.id
6768  {
6769  /* fix up pseudo specs, although it probably does not matter */
6770  node->info.spec.id = (UINTPTR) spec;
6771  }
6772  else if (node->node_type == PT_CHECK_OPTION && node->info.check_option.spec_id == spec->info.spec.id)
6773  {
6774  node->info.check_option.spec_id = (UINTPTR) spec;
6775  }
6776 
6777  if (node->spec_ident == spec->info.spec.id)
6778  {
6779  node->spec_ident = (UINTPTR) spec;
6780  }
6781 
6782  return node;
6783 }
6784 
6785 
6786 /*
6787  * mq_reset_ids() - re-sets path entities of a spec by removing unreferenced
6788  * paths, reseting ids of remaining paths, and recursing on sub-paths
6789  * return:
6790  * parser(in):
6791  * statement(in):
6792  * spec(in):
6793  */
6794 PT_NODE *
6795 mq_reset_ids (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec)
6796 {
6797  PT_NODE *range;
6798 
6799  /* don't mess with pseudo specs */
6801  {
6802  return statement;
6803  }
6804 
6805  /* make sure range var always has same id as spec */
6806  range = spec->info.spec.range_var;
6807  if (range)
6808  {
6809  assert (range->node_type == PT_NAME);
6810  range->info.name.spec_id = spec->info.spec.id;
6811  }
6812 
6813  statement = parser_walk_tree (parser, statement, mq_reset_all_ids, spec, NULL, NULL);
6814 
6815  /* spec may or may not be part of statement. If it is, this is redundant. If its not, this will reset self
6816  * references, such as in path specs. */
6817  (void) parser_walk_tree (parser, spec, mq_reset_all_ids, spec, NULL, NULL);
6818 
6819  /* finally, set spec id */
6820  spec->info.spec.id = (UINTPTR) spec;
6821 
6822  return statement;
6823 }
6824 
6825 /*
6826  * mq_clear_all_ids() - clear previously resolved PT_NAME node
6827  * return:
6828  * parser(in):
6829  * node(in):
6830  * void_arg(in):
6831  * continue_walk(in):
6832  */
6833 static PT_NODE *
6834 mq_clear_all_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6835 {
6836  UINTPTR *spec_id_ptr = (UINTPTR *) void_arg;
6837 
6838  if (node->node_type == PT_NAME)
6839  {
6840  if ((spec_id_ptr != NULL && node->info.name.spec_id == (*spec_id_ptr)) || (spec_id_ptr == NULL))
6841  {
6842  node->info.name.spec_id = 0;
6843  }
6844  }
6845 
6846  if (pt_is_query (node))
6847  {
6848  *continue_walk = PT_LIST_WALK;
6849  }
6850  else
6851  {
6852  *continue_walk = PT_CONTINUE_WALK;
6853  }
6854 
6855  return node;
6856 }
6857 
6858 /*
6859  * mq_clear_other_ids () - clear ids for all nodes except the ones referencing
6860  * the spec list specified in void_arg
6861  * return : node
6862  * parser (in) : parser context
6863  * node (in) : node to reset
6864  * void_arg (in) : spec list
6865  * continue_walk (in) :
6866  */
6867 static PT_NODE *
6868 mq_clear_other_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6869 {
6870  if (node->node_type == PT_NAME)
6871  {
6872  PT_NODE *filter_spec = (PT_NODE *) void_arg;
6873  while (filter_spec != NULL)
6874  {
6875  if (node->info.name.spec_id == filter_spec->info.spec.id)
6876  {
6877  return node;
6878  }
6879  filter_spec = filter_spec->next;
6880  }
6881  node->info.name.spec_id = 0;
6882  }
6883  return node;
6884 }
6885 
6886 /*
6887  * mq_clear_ids () - recursively clear previously resolved PT_NAME nodes
6888  * return:
6889  * parser(in):
6890  * statement(in):
6891  * spec(in):
6892  */
6893 PT_NODE *
6895 {
6896  node =
6897  parser_walk_tree (parser, node, mq_clear_all_ids, (spec != NULL ? &spec->info.spec.id : NULL), pt_continue_walk,
6898  NULL);
6899 
6900  return node;
6901 }
6902 
6903 /*
6904  * mq_reset_spec_ids() - resets spec ids for a spec node
6905  * return:
6906  * parser(in):
6907  * node(in):
6908  * void_arg(in):
6909  * continue_walk(in):
6910  */
6911 static PT_NODE *
6912 mq_reset_spec_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6913 {
6914  PT_NODE *spec = NULL;
6915 
6916  switch (node->node_type)
6917  {
6918  case PT_SELECT:
6919  for (spec = node->info.query.q.select.from; spec; spec = spec->next)
6920  {
6921  /* might not be necessary to reset paths and references, but it's a good failsafe */
6922  mq_set_references (parser, node, spec);
6923  }
6924  break;
6925 
6926  case PT_UPDATE:
6927  for (spec = node->info.update.spec; spec; spec = spec->next)
6928  {
6929  /* only reset IDs, in case query will be rewritten as SELECT for broker execution */
6930  mq_reset_ids (parser, node, spec);
6931  }
6932  break;
6933 
6934  case PT_DELETE:
6935  for (spec = node->info.delete_.spec; spec; spec = spec->next)
6936  {
6937  /* only reset IDs, in case query will be rewritten as SELECT for broker execution */
6938  mq_reset_ids (parser, node, spec);
6939  }
6940  break;
6941 
6942  case PT_MERGE:
6943  for (spec = node->info.merge.into; spec; spec = spec->next)
6944  {
6945  /* only reset IDs, in case query will be rewritten as SELECT for broker execution */
6946  mq_reset_ids (parser, node, spec);
6947  }
6948  for (spec = node->info.merge.using_clause; spec; spec = spec->next)
6949  {
6950  /* only reset IDs, in case query will be rewritten as SELECT for broker execution */
6951  mq_reset_ids (parser, node, spec);
6952  }
6953  break;
6954  case PT_INSERT:
6955  if (node->info.insert.odku_assignments)
6956  {
6957  PT_NODE *values = node->info.insert.value_clauses;
6958  PT_NODE *select = values->info.node_list.list;
6959 
6960  if (select != NULL && select->node_type == PT_SELECT)
6961  {
6962  PT_NODE *assignments = node->info.insert.odku_assignments;
6963 
6964  spec = select->info.query.q.select.from;
6965  for (; spec; spec = spec->next)
6966  {
6967  for (; assignments; assignments = assignments->next)
6968  {
6969  parser_walk_tree (parser, assignments, mq_reset_all_ids, spec, NULL, NULL);
6970  }
6971  }
6972  }
6973  }
6974  break;
6975 
6976  default:
6977  break;
6978  }
6979 
6980  return (node);
6981 
6982 }
6983 
6984 /*
6985  * mq_reset_spec_in_method_names() - resets spec id in method name
6986  * return:
6987  * parser(in):
6988  * node(in):
6989  * void_arg(in):
6990  * continue_walk(in):
6991  *
6992  * NOTE: Currently this function reset spec_id only if the spec_id is
6993  * a name node.
6994  */
6995 static PT_NODE *
6996 mq_reset_spec_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
6997 {
6998  if (node->node_type == PT_METHOD_CALL)
6999  {
7000  PT_NODE *method_name;
7001  method_name = node->info.method_call.method_name;
7002  if (method_name)
7003  {
7004  PT_NODE *spec = (PT_NODE *) method_name->info.name.spec_id;
7005  if (spec && spec->node_type == PT_NAME)
7006  {
7007  method_name->info.name.spec_id = (UINTPTR) method_name;
7008  }
7009  }
7010  }
7011 
7012  return (node);
7013 }
7014 
7015 /*
7016  * mq_reset_ids_in_statement() - walks the statement and for each spec,
7017  * reset ids that reference that spec
7018  * return: statement having methods ids reseted
7019  * parser(in):
7020  * statement(in):
7021  */
7022 PT_NODE *
7024 {
7025 
7026  statement = parser_walk_tree (parser, statement, mq_reset_spec_ids, NULL, NULL, NULL);
7027 
7028  return (statement);
7029 
7030 }
7031 
7032 /*
7033  * mq_reset_ids_in_methods() - walks the statement and for each method reset id
7034  *
7035  * return:
7036  * parser(in):
7037  * statement(in):
7038  */
7039 PT_NODE *
7041 {
7042  statement = parser_walk_tree (parser, statement, mq_reset_spec_in_method_names, NULL, NULL, NULL);
7043 
7044  return (statement);
7045 }
7046 
7047 /*
7048  * mq_get_references_node() - gets referenced PT_NAME nodes
7049  * return:
7050  * parser(in):
7051  * node(in):
7052  * void_arg(in):
7053  * continue_walk(in/out):
7054  */
7055 static PT_NODE *
7056 mq_get_references_node (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7057 {
7058  PT_NODE *spec = (PT_NODE *) void_arg;
7059 
7060  if (node->node_type == PT_NAME && node->info.name.spec_id == spec->info.spec.id)
7061  {
7062  node->info.name.spec_id = (UINTPTR) spec;
7063  if (node->info.name.meta_class != PT_METHOD && node->info.name.meta_class != PT_HINT_NAME
7064  && node->info.name.meta_class != PT_INDEX_NAME)
7065  {
7066  /* filter out method name, hint argument name, index name nodes */
7067  mq_insert_symbol (parser, &spec->info.spec.referenced_attrs, node);
7068  }
7069  }
7070 
7071  if (node->node_type == PT_SPEC)
7072  {
7073  /* The only part of a spec node that could contain references to the given spec_id are derived tables,
7074  * path_entities, path_conjuncts, and on_cond. All the rest of the name nodes for the spec are not references,
7075  * but range variables, class names, etc. We don't want to mess with these. We'll handle the ones that we want by
7076  * hand. */
7077  node->info.spec.derived_table =
7079  node->info.spec.path_entities =
7081  node->info.spec.path_conjuncts =
7083  node->info.spec.on_cond =
7085  /* don't visit any other leaf nodes */
7086  *continue_walk = PT_LIST_WALK;
7087  }
7088 
7089  /* Data type nodes can not contain any valid references. They do contain class names and other things we don't want.
7090  */
7091  if (node->node_type == PT_DATA_TYPE)
7092  {
7093  *continue_walk = PT_LIST_WALK;
7094  }
7095 
7096  if (node->spec_ident == spec->info.spec.id)
7097  {
7098  node->spec_ident = (UINTPTR) spec;
7099  }
7100 
7101  return node;
7102 }
7103 
7104 
7105 /*
7106  * mq_reset_ids_and_references() - re-sets path entities of a spec by
7107  * removing unreferenced paths, reseting ids of remaining paths,
7108  * and recursing on sub-paths
7109  * return:
7110  * parser(in):
7111  * statement(in):
7112  * spec(in):
7113  */
7114 PT_NODE *
7116 {
7117  return mq_reset_ids_and_references_helper (parser, statement, spec, true /* default */ );
7118 }
7119 
7120 /*
7121  * mq_reset_ids_and_references_helper() -
7122  * return:
7123  * parser(in):
7124  * statement(in):
7125  * spec(in):
7126  * get_spec_referenced_attr(in):
7127  */
7128 PT_NODE *
7130  bool get_spec_referenced_attr)
7131 {
7132  /* don't mess with pseudo specs */
7134  {
7135  return statement;
7136  }
7137 
7138  statement = mq_reset_ids (parser, statement, spec);
7139 
7140  parser_free_tree (parser, spec->info.spec.referenced_attrs);
7141  spec->info.spec.referenced_attrs = NULL;
7142 
7143  statement = parser_walk_tree (parser, statement, mq_get_references_node, spec, pt_continue_walk, NULL);
7144 
7145  /* spec may or may not be part of statement. If it is, this is redundant. If its not, this will reset catch self
7146  * references, such as in path specs. */
7147  if (get_spec_referenced_attr)
7148  {
7149  (void) parser_walk_tree (parser, spec, mq_get_references_node, spec, pt_continue_walk, NULL);
7150  }
7151 
7152  return statement;
7153 }
7154 
7155 
7156 /*
7157  * mq_get_references() - returns a copy of a list of referenced names for
7158  * the given entity spec
7159  * return:
7160  * parser(in):
7161  * statement(in):
7162  * spec(in):
7163  */
7164 PT_NODE *
7166 {
7167  return mq_get_references_helper (parser, statement, spec, true /* default */ );
7168 }
7169 
7170 /*
7171  * mq_get_references_helper() -
7172  * return:
7173  * parser(in):
7174  * statement(in):
7175  * spec(in):
7176  * get_spec_referenced_attr(in):
7177  */
7178 PT_NODE *
7179 mq_get_references_helper (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec, bool get_spec_referenced_attr)
7180 {
7181  PT_NODE *references;
7182 
7183  statement = mq_reset_ids_and_references_helper (parser, statement, spec, get_spec_referenced_attr);
7184 
7185  references = spec->info.spec.referenced_attrs;
7186  spec->info.spec.referenced_attrs = NULL;
7187 
7188  return references;
7189 }
7190 
7191 /*
7192  * mq_referenced_pre() - looks for a name from a given entity spec
7193  * return:
7194  * parser(in):
7195  * node(in):
7196  * void_arg(in):
7197  * continue_walk(in):
7198  */
7199 static PT_NODE *
7200 mq_referenced_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7201 {
7202  EXISTS_INFO *info = (EXISTS_INFO *) void_arg;
7203  PT_NODE *spec = info->spec;
7204 
7205  /* don't count self references as being referenced. */
7206  if (node == spec)
7207  {
7208  *continue_walk = PT_LIST_WALK;
7209  return node;
7210  }
7211 
7212  if (node->node_type == PT_NAME && node->info.name.spec_id == spec->info.spec.id)
7213  {
7214  node->info.name.spec_id = (UINTPTR) spec;
7215  if (node->info.name.meta_class != PT_VCLASS)
7216  {
7217  info->referenced = 1;
7218  *continue_walk = PT_STOP_WALK;
7219  }
7220  }
7221 
7222  return node;
7223 }
7224 
7225 /*
7226  * mq_referenced_post() - looks for a name from a given entity spec
7227  * return:
7228  * parser(in):
7229  * node(in):
7230  * void_arg(in):
7231  * continue_walk(in):
7232  */
7233 static PT_NODE *
7234 mq_referenced_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7235 {
7236  if (*continue_walk != PT_STOP_WALK)
7237  {
7238  *continue_walk = PT_CONTINUE_WALK;
7239  }
7240  return node;
7241 }
7242 
7243 
7244 /*
7245  * mq_is_referenced() - tests if an entity is referenced in a spec
7246  * return: 1 on referenced
7247  * parser(in):
7248  * statement(in):
7249  * spec(in):
7250  */
7251 static int
7253 {
7254  EXISTS_INFO info;
7255  info.spec = spec;
7256  info.referenced = 0;
7257 
7258  parser_walk_tree (parser, statement, mq_referenced_pre, &info, mq_referenced_post, &info);
7259 
7260  return info.referenced;
7261 }
7262 
7263 
7264 /*
7265  * mq_reset_paths() - re-sets path entities of a spec by removing unreferenced
7266  * paths, reseting ids of remaining paths and recursing on sub-paths
7267  * return:
7268  * parser(in):
7269  * statement(in):
7270  * root_spec(in):
7271  */
7272 PT_NODE *
7273 mq_reset_paths (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * root_spec)
7274 {
7275  PT_NODE **path_spec_ptr = &root_spec->info.spec.path_entities;
7276  PT_NODE *path_spec = *path_spec_ptr;
7277 
7278  for (; path_spec != NULL; path_spec = *path_spec_ptr)
7279  {
7280  if (mq_is_referenced (parser, statement, path_spec))
7281  {
7282  /* keep it if its still referenced */
7283  statement = mq_reset_ids (parser, statement, path_spec);
7284 
7285  statement = mq_reset_paths (parser, statement, path_spec);
7286 
7287  path_spec_ptr = &path_spec->next;
7288  }
7289  else
7290  {
7291 #if 0
7292  /* its possible inder some perverse conditions for a virtual spec to disappear, while sub paths still apear.
7293  * Hear, we promote the sub-paths to the same level and re-check them all for references. */
7294  parser_append_node (path_spec->info.spec.path_entities, path_spec);
7295  path_spec->info.spec.path_entities = NULL;
7296 #endif /* 0 */
7297 
7298  /* remove path spec */
7299  *path_spec_ptr = path_spec->next;
7300  path_spec->next = NULL;
7301  parser_free_tree (parser, path_spec);
7302  }
7303  }
7304 
7305  return statement;
7306 }
7307 
7308 
7309 /*
7310  * mq_set_references_local() - sets the referenced attr list of entity
7311  * specifications and its sub-entities
7312  * return:
7313  * parser(in):
7314  * statement(in):
7315  * spec(in):
7316  */
7317 static PT_NODE *
7319 {
7320  PT_NODE *path_spec;
7321 
7322  parser_free_tree (parser, spec->info.spec.referenced_attrs);
7323  spec->info.spec.referenced_attrs = NULL;
7324 
7325  statement = parser_walk_tree (parser, statement, mq_get_references_node, spec, pt_continue_walk, NULL);
7326 
7327  path_spec = spec->info.spec.path_entities;
7328 
7329  for (; path_spec != NULL; path_spec = path_spec->next)
7330  {
7331  statement = mq_set_references_local (parser, statement, path_spec);
7332  }
7333 
7334  return statement;
7335 }
7336 
7337 
7338 /*
7339  * mq_set_references() - sets the referenced attr list of an entity
7340  * specification and all sub-entities
7341  * return:
7342  * parser(in):
7343  * statement(in):
7344  * spec(in):
7345  */
7346 PT_NODE *
7348 {
7349  /* don't mess with pseudo specs */
7350  if (!spec || spec->info.spec.derived_table_type == PT_IS_WHACKED_SPEC)
7351  {
7352  return statement;
7353  }
7354 
7355  statement = mq_reset_ids (parser, statement, spec);
7356 
7357  statement = mq_reset_paths (parser, statement, spec);
7358 
7359  statement = mq_set_references_local (parser, statement, spec);
7360 
7361  return statement;
7362 }
7363 
7364 
7365 /*
7366  * mq_reset_select_spec_node() - re-sets copied spec symbol table information
7367  * for a select which has just been substituted as a lambda argument in a view
7368  * return:
7369  * parser(in):
7370  * node(in):
7371  * void_arg(in):
7372  * continue_walk(in):
7373  */
7374 static PT_NODE *
7375 mq_reset_select_spec_node (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7376 {
7378 
7379  if (node->node_type == PT_SPEC && node->info.spec.id == info->id)
7380  {
7381  *info->statement = mq_reset_ids_and_references (parser, *info->statement, node);
7382  *info->statement = mq_translate_paths (parser, *info->statement, node);
7383  *info->statement = mq_reset_paths (parser, *info->statement, node);
7384  }
7385 
7386  return node;
7387 }
7388 
7389 /*
7390  * mq_reset_select_specs() - re-sets spec symbol table information for a select
7391  * which has just been substituted as a lambda argument in a view
7392  * return:
7393  * parser(in):
7394  * node(in):
7395  * void_arg(in):
7396  * continue_walk(in):
7397  */
7398 static PT_NODE *
7399 mq_reset_select_specs (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7400 {
7401  PT_NODE **statement = (PT_NODE **) void_arg;
7403  PT_NODE *spec;
7404 
7405  if (node->node_type == PT_SELECT)
7406  {
7407  spec = node->info.query.q.select.from;
7408  info.statement = statement;
7409  for (; spec != NULL; spec = spec->next)
7410  {
7411  info.id = spec->info.spec.id;
7412 
7413  /* now we know which specs must get reset. we need to find each instance of this spec in the statement, and
7414  * reset it. */
7415  *statement = parser_walk_tree (parser, *statement, mq_reset_select_spec_node, &info, NULL, NULL);
7416  }
7417  }
7418 
7419  return node;
7420 }
7421 
7422 
7423 /*
7424  * mq_reset_specs_from_column() - finds every select in column, then resets
7425  * id's and paths from that selects spec
7426  * return:
7427  * parser(in):
7428  * statement(in):
7429  * column(in):
7430  */
7431 static PT_NODE *
7433 {
7434  parser_walk_tree (parser, column, mq_reset_select_specs, &statement, NULL, NULL);
7435 
7436  return statement;
7437 }
7438 
7439 
7440 /*
7441  * mq_new_spec() - Create a new spec, given a class name
7442  * return:
7443  * parser(in):
7444  * class_name(in):
7445  */
7446 static PT_NODE *
7447 mq_new_spec (PARSER_CONTEXT * parser, const char *class_name)
7448 {
7449  PT_NODE *class_spec;
7450  PT_FLAT_SPEC_INFO info;
7451 
7452  if ((class_spec = parser_new_node (parser, PT_SPEC)) == NULL)
7453  {
7454  return NULL;
7455  }
7456  class_spec->info.spec.id = (UINTPTR) class_spec;
7457  class_spec->info.spec.only_all = PT_ONLY;
7458  class_spec->info.spec.meta_class = PT_META_CLASS;
7459  if ((class_spec->info.spec.entity_name = pt_name (parser, class_name)) == NULL)
7460  {
7461  return NULL;
7462  }
7463 
7464  info.spec_parent = NULL;
7465  info.for_update = false;
7466  class_spec = parser_walk_tree (parser, class_spec, pt_flat_spec_pre, &info, pt_continue_walk, NULL);
7467  return class_spec;
7468 }
7469 
7470 
7471 /*
7472  * mq_replace_name_with_path() - replace them with copies of path supplied,
7473  * ending in name node
7474  * return:
7475  * parser(in):
7476  * node(in):
7477  * void_arg(in):
7478  * continue_walk(in/out):
7479  *
7480  * Note:
7481  * ONLY do this for names matching the input expressions spec_id, which
7482  * is passed in in the info structure. Other names may be unrelated names
7483  * from subqueries in the expression being walked
7484  */
7485 static PT_NODE *
7486 mq_replace_name_with_path (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7487 {
7488  REPLACE_NAME_INFO *info = (REPLACE_NAME_INFO *) void_arg;
7489  PT_NODE *path = info->path;
7490  PT_NODE *next;
7491  *continue_walk = PT_CONTINUE_WALK;
7492 
7493  if (node->node_type == PT_NAME && node->info.name.spec_id == info->spec_id
7494  && (node->info.name.meta_class == PT_NORMAL || node->info.name.meta_class == PT_SHARED
7495  || node->info.name.meta_class == PT_OID_ATTR || node->info.name.meta_class == PT_VID_ATTR))
7496  {
7497  next = node->next;
7498  if (node->info.name.resolved)
7499  {
7500  /* names appearing in right side of dot expressions should not be replaced. We take advantage of the fact
7501  * that these do not have "resolved" set, to identify those names not to touch. All other names should have
7502  * "resolved" set, and be handled here. */
7503  path = parser_copy_tree (parser, path);
7504  if (path)
7505  {
7506  /* now make this a legitimate path right hand and make it print right, by setting its resolved to NULL. */
7507  node->info.name.resolved = NULL;
7508  path->info.expr.arg2 = node;
7509  path->type_enum = node->type_enum;
7510  parser_free_tree (parser, path->data_type);
7511  path->data_type = parser_copy_tree (parser, node->data_type);
7512  node = path;
7513  node->next = next;
7514  }
7515  }
7516 
7517  *continue_walk = PT_LIST_WALK;
7518  }
7519 
7520  if (node->node_type == PT_DATA_TYPE)
7521  {
7522  *continue_walk = PT_LIST_WALK;
7523  }
7524 
7525  return node;
7526 }
7527 
7528 
7529 /*
7530  * mq_substitute_path() -
7531  * return:
7532  * parser(in):
7533  * node(in):
7534  * path_info(in):
7535  */
7536 static PT_NODE *
7538 {
7539  PT_NODE *column;
7540  PT_NODE *next;
7541  REPLACE_NAME_INFO info;
7542  PT_NODE *query_spec_column = path_info->lambda_expr;
7543  UINTPTR spec_id = path_info->spec_id;
7544 
7545  /* prune other columns and copy */
7546  column = parser_copy_tree (parser, query_spec_column);
7547  if (column == NULL)
7548  {
7549  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
7550  return NULL;
7551  }
7552 
7553  if (column->node_type == PT_NAME)
7554  {
7555  if (column->info.name.meta_class == PT_SHARED)
7556  {
7557  PT_NODE *new_spec = mq_new_spec (parser,
7558  db_get_class_name (column->info.name.db_object));
7559 
7560  if (new_spec == NULL)
7561  {
7562  PT_INTERNAL_ERROR (parser, "mq_new_spec");
7563  return NULL;
7564  }
7565 
7566  path_info->new_specs = parser_append_node (new_spec, path_info->new_specs);
7567  column->info.name.spec_id = new_spec->info.spec.id;
7568  column->next = node->next;
7569  column->line_number = node->line_number;
7570  column->column_number = node->column_number;
7571  node->next = NULL;
7572  parser_free_tree (parser, node);
7573  node = column;
7574  }
7575  else
7576 #if 0
7577  if (PT_IS_OID_NAME (column))
7578  {
7579  /* path collapses a notch! */
7580  next = node->next;
7581  node = node->info.expr.arg1;
7582  node->next = next;
7583  }
7584  else
7585 #endif /* 0 */
7586  {
7587  parser_free_tree (parser, node->info.expr.arg2);
7588  node->info.expr.arg2 = column;
7589  column->info.name.resolved = NULL; /* make it print right */
7590  if (node->data_type)
7591  {
7592  parser_free_tree (parser, node->data_type);
7593  }
7594  node->data_type = parser_copy_tree (parser, column->data_type);
7595  }
7596  }
7597  else
7598  {
7599  next = node->next;
7600  parser_free_tree (parser, node->info.expr.arg2);
7601  node->info.expr.arg2 = NULL;
7602  node->next = NULL;
7603  info.path = node;
7604  info.spec_id = spec_id;
7605  node = parser_walk_tree (parser, column, mq_replace_name_with_path, (void *) &info, pt_continue_walk, NULL);
7606  if (node)
7607  {
7608  node->next = next;
7609  if (node->node_type == PT_EXPR)
7610  {
7611  /* if we replace a path expression with an expression, put parenthesis around it, because we are likely
7612  * IN another expression. If we need to print the outer expression, parenthesis gurantee the proper
7613  * expression precedence. */
7614  node->info.expr.paren_type = 1;
7615  }
7616  }
7617  }
7618 
7619  return node;
7620 }
7621 
7622 
7623 /*
7624  * mq_substitute_path_pre() - tests and substitutes for path expressions
7625  * matching the given name
7626  * return:
7627  * parser(in):
7628  * node(in):
7629  * void_arg(in):
7630  * continue_walk(in/out):
7631  */
7632 static PT_NODE *
7633 mq_substitute_path_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
7634 {
7635  PT_NODE *arg2;
7636  PT_NODE *next;
7637  PATH_LAMBDA_INFO *info = (PATH_LAMBDA_INFO *) void_arg;
7638 
7639  *continue_walk = PT_CONTINUE_WALK;
7640 
7641  if (node->node_type == PT_DOT_ && (arg2 = node->info.dot.arg2) && pt_name_equal (parser, arg2, &(info->lambda_name)))
7642  {
7643  /* need to replace node with the converted expression */
7644  node = mq_substitute_path (parser, node, info);
7645 
7646  /* no need to revisit these leaves */
7647  *continue_walk = PT_LIST_WALK;
7648  }
7649  else if (node->node_type == PT_NAME)
7650  {
7651  if (pt_name_equal (parser, node, &(info->lambda_name)))
7652  {
7653  /* this is a name reference in a spec somewhere */
7654  next = node->next;
7655  node->next = NULL;
7656  parser_free_tree (parser, node);
7657 
7658  node = parser_copy_tree (parser, info->lambda_expr);
7659  if (node == NULL)
7660  {
7661  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
7662  return NULL;
7663  }
7664  node->next = next;
7665  }
7666 
7667  /* no need to revisit these leaves */
7668  *continue_walk = PT_LIST_WALK;
7669  }
7670 
7671  return node;
7672 }
7673 
7674 
7675 /*
7676  * mq_path_name_lambda() - Search the tree for path expression right hand sides
7677  * matching the given name, and do path substitution on
7678  * those path expressions with the supplied argument
7679  * return:
7680  * parser(in):
7681  * statement(in):
7682  * lambda_name(in):
7683  * lambda_expr(in):
7684  * spec_id(in):
7685  */
7686 static PT_NODE *
7687 mq_path_name_lambda (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * lambda_name, PT_NODE * lambda_expr,
7688  UINTPTR spec_id)
7689 {
7690  PATH_LAMBDA_INFO info;
7691 
7692  /* copy the name because the reference is one of the things that will be replaced. */
7693  info.lambda_name = *lambda_name;
7694  info.lambda_expr = lambda_expr;
7695  info.spec_id = spec_id;
7696  info.new_specs = NULL;
7697 
7698  return parser_walk_tree (parser, statement, mq_substitute_path_pre, &info, pt_continue_walk, NULL);
7699 }
7700 
7701 
7702 /*
7703  * mq_reset_spec_distr_subpath_pre() - moving specs from the sub-path list to
7704  * the immediate path_entities list, and resetting ids in the statement
7705  * return:
7706  * parser(in):
7707  * spec(in):
7708  * void_arg(in):
7709  * continue_walk(in/out):
7710  */
7711 static PT_NODE *
7712 mq_reset_spec_distr_subpath_pre (PARSER_CONTEXT * parser, PT_NODE * spec, void *void_arg, int *continue_walk)
7713 {
7714  SPEC_RESET_INFO *info = (SPEC_RESET_INFO *) void_arg;
7715 
7716  if (spec == info->old_next)
7717  {
7718  *continue_walk = PT_STOP_WALK;
7719  }
7720  else
7721  {
7722  *continue_walk = PT_CONTINUE_WALK;
7723  }
7724 
7725  return spec;
7726 }
7727 
7728 /*
7729  * mq_reset_spec_distr_subpath_post() -
7730  * return:
7731  * parser(in):
7732  * spec(in):
7733  * void_arg(in):
7734  * continue_walk(in/out):
7735  */
7736 static PT_NODE *
7737 mq_reset_spec_distr_subpath_post (PARSER_CONTEXT * parser, PT_NODE * spec, void *void_arg, int *continue_walk)
7738 {
7739  SPEC_RESET_INFO *info = (SPEC_RESET_INFO *) void_arg;
7740  PT_NODE **sub_paths = info->sub_paths;
7741  PT_NODE *subspec = *sub_paths;
7742  PT_NODE *subspec_term;
7743  PT_NODE *arg1;
7744 
7745  *continue_walk = PT_CONTINUE_WALK; /* un-prune other sub-branches */
7746 
7747  if (spec != info->old_next && spec->node_type == PT_SPEC)
7748  {
7749  for (; subspec != NULL; subspec = *sub_paths)
7750  {
7751  subspec_term = subspec->info.spec.path_conjuncts;
7752  arg1 = subspec_term->info.expr.arg1;
7753 
7754  if ((arg1->node_type == PT_NAME && spec->info.spec.id == arg1->info.name.spec_id)
7755  || pt_find_id (parser, arg1, spec->info.spec.id))
7756  {
7757  /* a match. link it to this spec path entities */
7758  *sub_paths = subspec->next;
7759  subspec->next = spec->info.spec.path_entities;
7760  spec->info.spec.path_entities = subspec;
7761  }
7762  else
7763  {
7764  /* otherwise advance down the list with no side effects */
7765  sub_paths = &subspec->next;
7766  }
7767  }
7768 
7769  /* now that the sub-specs (if any) are attached, we can reset spec_ids and references. */
7770  info->statement = mq_reset_ids_and_references (parser, info->statement, spec);
7771  }
7772 
7773  return spec;
7774 }
7775 
7776 
7777 /*
7778  * mq_path_spec_lambda() - Replace old_spec (virtual) with new_spec (real)
7779  * return:
7780  * parser(in):
7781  * statement(in):
7782  * root_spec(in): points to the spec of the left hand side of the path
7783  * prev_ptr(in): points to the reference to old_spec
7784  * old_spec(out):
7785  * new_spec(in):
7786  *
7787  * Note:
7788  * If the new_spec is a join, this is an error. Only updatable
7789  * new_specs should be candidates. However, previous checks should
7790  * have already caught this.
7791  *
7792  * If the new_spec has path_entities, then the immedieate sub-path entities
7793  * of the old_spec must be distributed amoung the new_spec spec nodes.
7794  */
7795 static PT_NODE *
7796 mq_path_spec_lambda (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * root_spec, PT_NODE ** prev_ptr,
7797  PT_NODE * old_spec, PT_NODE * new_spec)
7798 {
7799  PT_NODE *root_flat;
7800  PT_NODE *old_flat;
7801  PT_NODE *new_flat;
7802  PT_NODE *sub_paths;
7803 
7804  root_flat = root_spec->info.spec.flat_entity_list;
7805  if (!root_flat)
7806  {
7807  /* its a derived table */
7808  root_flat = old_spec->info.spec.path_conjuncts->info.expr.arg1->data_type->info.data_type.entity;
7809  }
7810  old_flat = old_spec->info.spec.flat_entity_list;
7811  new_flat = new_spec->info.spec.flat_entity_list;
7812 
7813  sub_paths = old_spec->info.spec.path_entities;
7814  old_spec->info.spec.path_entities = NULL;
7815 
7816  if (new_spec->next)
7817  {
7819  old_flat->info.name.original, new_flat->info.name.original);
7820  }
7821 
7822  *prev_ptr = new_spec;
7823  new_spec->next = old_spec->next;
7824  old_spec->next = NULL;
7825  new_spec->info.spec.path_conjuncts = old_spec->info.spec.path_conjuncts;
7826  old_spec->info.spec.path_conjuncts = NULL;
7827  new_spec->line_number = old_spec->line_number;
7828  new_spec->column_number = old_spec->column_number;
7829 
7830  if (new_spec->info.spec.path_entities)
7831  {
7832  SPEC_RESET_INFO spec_reset;
7833  /* reset the spec_id's */
7834  spec_reset.statement = statement;
7835  spec_reset.sub_paths = &sub_paths;
7836  spec_reset.old_next = new_spec->next;
7837 
7838  new_spec =
7839  parser_walk_tree (parser, new_spec, mq_reset_spec_distr_subpath_pre, &spec_reset,
7840  mq_reset_spec_distr_subpath_post, &spec_reset);
7841 
7842  statement = spec_reset.statement;
7843  }
7844  else
7845  {
7846  /* The swap is one for one. All old sub paths must be direct sub-paths. */
7847  new_spec->info.spec.path_entities = sub_paths;
7848 
7849  /* reset the spec_id's */
7850  statement = mq_reset_ids_and_references (parser, statement, new_spec);
7851  }
7852 
7853  parser_free_tree (parser, old_spec);
7854 
7855  return statement;
7856 }
7857 
7858 
7859 /*
7860  * mq_translate_paths() - translates the composition virtual references to real
7861  * return:
7862  * parser(in):
7863  * statement(in):
7864  * root_spec(in):
7865  *
7866  * Note:
7867  *
7868  * The list of immediate sub-paths must be re-distributed amoung the
7869  * resulting real path specs. In the trivial case in which there is
7870  * a one to one correspondance, this means simply setting the path_entities
7871  * as it was before. Otherwise the name id's of each spec in the immediate
7872  * sub-path must be matched against the n candidate real specs, and appended
7873  * to its path_entities list.
7874  */
7875 static PT_NODE *
7876 mq_translate_paths (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * root_spec)
7877 {
7878  PT_NODE *references;
7879  PT_NODE *reference_list;
7880  PT_NODE *path_spec;
7881  PT_NODE *next;
7882  PT_NODE *flat;
7883  PT_NODE *join_term;
7884  PT_NODE **prev_ptr;
7885  PT_NODE *real_class;
7886  PT_NODE *expr;
7887  UINTPTR spec_id;
7888  PT_NODE *query_spec;
7889  PT_MISC_TYPE path_type; /* 0, or PT_PATH_INNER */
7890 
7891  if (root_spec == NULL)
7892  {
7893  return NULL;
7894  }
7895 
7896  prev_ptr = &root_spec->info.spec.path_entities;
7897  path_spec = *prev_ptr;
7898 
7899  while (path_spec && statement)
7900  {
7901  flat = path_spec->info.spec.flat_entity_list;
7902  join_term = path_spec->info.spec.path_conjuncts;
7903  if (!join_term)
7904  {
7905  PT_INTERNAL_ERROR (parser, "translate");
7906  }
7907  else if (flat && flat->info.name.meta_class == PT_CLASS /* NOT PT_META_CLASS */
7908  && (db_is_vclass (flat->info.name.db_object) > 0))
7909  {
7910  next = path_spec->next;
7911  references = mq_get_references (parser, statement, path_spec);
7912  reference_list = references; /* to be freed later */
7913  real_class = join_term->info.expr.arg1->data_type->info.data_type.entity;
7914  path_type = path_spec->info.spec.meta_class;
7915 
7916  while (references)
7917  {
7918  expr =
7919  mq_fetch_expression_for_real_class_update (parser, flat->info.name.db_object, references, real_class,
7920  PT_NORMAL_SELECT, DB_AUTH_SELECT, &spec_id);
7921 
7922  if (expr)
7923  {
7924  statement = mq_path_name_lambda (parser, statement, references, expr, spec_id);
7925  }
7926  references = references->next;
7927  }
7928  parser_free_tree (parser, reference_list);
7929 
7930  query_spec =
7932  flat = flat->next;
7933 
7934  while (flat && !query_spec)
7935  {
7936  query_spec =
7938  flat = flat->next;
7939  }
7940 
7941  /* at this point, if any of the virtual classes had a matching real class_, we will have found it */
7942  if (query_spec)
7943  {
7944  PT_NODE *temp;
7945  PT_NODE *new_spec;
7946 
7947  new_spec = parser_copy_tree_list (parser, query_spec->info.query.q.select.from);
7948 
7949  /* the following block of code attempts to gurantee that all candidate subclasses are copied to the
7950  * entity list of the path spec we are about to create.
7951  *
7952  * * relational proxies are made an exception, because 1) relational proxies can inherently only refer to
7953  * one table. */
7954  if (db_is_class (real_class->info.name.db_object) > 0)
7955  {
7956  /* find all the rest of the matches */
7957  for (; flat != NULL; flat = flat->next)
7958  {
7959  query_spec =
7960  mq_fetch_select_for_real_class_update (parser, flat, real_class, PT_NORMAL_SELECT,
7961  DB_AUTH_SELECT);
7962  if (query_spec && (temp = query_spec->info.query.q.select.from)
7963  && (temp = temp->info.spec.flat_entity_list) && (temp = parser_copy_tree_list (parser, temp)))
7964  {
7965  new_spec->info.spec.flat_entity_list =
7966  parser_append_node (temp, new_spec->info.spec.flat_entity_list);
7967  while (temp)
7968  {
7969  temp->info.name.spec_id = new_spec->info.spec.id;
7970  temp = temp->next;
7971  }
7972  }
7973  }
7974  }
7975 
7976  statement = mq_path_spec_lambda (parser, statement, root_spec, prev_ptr, path_spec, new_spec);
7977  }
7978  else
7979  {
7980  PT_INTERNAL_ERROR (parser, "translate");
7981  }
7982 
7983  path_spec = *prev_ptr; /* this was just over-written */
7984  /* if either the virtual or translated guys is an inner path (selector path) the result must be an inner
7985  * path, as opposed to the usual left join path semantics */
7986  if (path_type == PT_PATH_INNER)
7987  {
7988  path_spec->info.spec.meta_class = PT_PATH_INNER;
7989  }
7990 
7991  /* translate virtual sub-paths */
7992  statement = mq_translate_paths (parser, statement, path_spec);
7993  }
7994 
7995  prev_ptr = &path_spec->next;
7996  path_spec = *prev_ptr;
7997  }
7998 
7999  return statement;
8000 }
8001 
8002 
8003 /*
8004  * mq_rename_resolved() - re-sets name resolution to of an entity spec
8005  * and a tree to match a new printable name
8006  * return:
8007  * parser(in):
8008  * spec(in):
8009  * statement(in):
8010  * newname(in):
8011  */
8012 PT_NODE *
8013 mq_rename_resolved (PARSER_CONTEXT * parser, PT_NODE * spec, PT_NODE * statement, const char *newname)
8014 {
8015  if (!spec || !spec->info.spec.range_var || !statement)
8016  {
8017  return statement;
8018  }
8019 
8020  spec->info.spec.range_var->info.name.original = newname;
8021 
8022  /* this is just to make sure the id is properly set. Its probably not necessary. */
8023  spec->info.spec.range_var->info.name.spec_id = spec->info.spec.id;
8024 
8025  statement =
8027 
8028  return statement;
8029 }
8030 
8031 /*
8032  * mq_regenerate_if_ambiguous() - regenerate the exposed name
8033  * if ambiguity is detected
8034  * return:
8035  * parser(in):
8036  * spec(in):
8037  * statement(in):
8038  * from(in):
8039  */
8040 PT_NODE *
8042 {
8043  const char *newexposedname;
8044  const char *generatedname;
8045  int ambiguous;
8046  int i;
8047 
8048 
8049  newexposedname = spec->info.spec.range_var->info.name.original;
8050 
8051  if (1 < pt_name_occurs_in_from_list (parser, newexposedname, from))
8052  {
8053  /* Ambiguity is detected. rename the newcomer's printable name to fix this. */
8054  i = 0;
8055  ambiguous = true;
8056 
8057  while (ambiguous)
8058  {
8059  generatedname = mq_generate_name (parser, newexposedname, &i);
8060 
8061  ambiguous = 0 < pt_name_occurs_in_from_list (parser, generatedname, from);
8062  }
8063 
8064  /* generatedname is now non-ambiguous */
8065  statement = mq_rename_resolved (parser, spec, statement, generatedname);
8066  }
8067 
8068  return statement;
8069 }
8070 
8071 
8072 /*
8073  * mq_generate_unique() - generates a printable name not found in the name list
8074  * return:
8075  * parser(in):
8076  * name_list(in):
8077  */
8078 static PT_NODE *
8080 {
8081  int ambiguous = 1;
8082  int i = 0;
8083  PT_NODE *new_name = parser_copy_tree (parser, name_list);
8084  PT_NODE *temp = name_list;
8085 
8086  if (new_name == NULL)
8087  {
8088  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
8089  return NULL;
8090  }
8091 
8092  while (ambiguous)
8093  {
8094  new_name->info.name.original = mq_generate_name (parser, "a", &i);
8095  temp = name_list;
8096  while (temp && intl_identifier_casecmp (new_name->info.name.original, temp->info.name.original) != 0)
8097  {
8098  temp = temp->next;
8099  }
8100  if (!temp)
8101  {
8102  ambiguous = 0;
8103  }
8104  }
8105 
8106  return new_name;
8107 }
8108 
8109 
8110 /*
8111  * mq_invert_insert_select() - invert sub-query select lists
8112  * return:
8113  * parser(in):
8114  * attr(in):
8115  * subquery(in):
8116  */
8117 static void
8119 {
8120  PT_NODE **value;
8121  PT_NODE *value_next;
8122  PT_NODE *result;
8123 
8124  value = &subquery->info.query.q.select.list;
8125 
8126  while (*value)
8127  {
8128  /* ignore the the hidden columns e.g. append when check order by see mq_update_order_by (...) */
8129  if ((*value)->flag.is_hidden_column == 1)
8130  {
8131  value = &(*value)->next;
8132  continue;
8133  }
8134 
8135  if (!attr)
8136  {
8137  /* system error, should be caught in semantic pass */
8139  return;
8140  }
8141  value_next = (*value)->next;
8142  (*value)->next = NULL;
8143 
8144  (*value) = mq_translate_value (parser, *value);
8145  result = pt_invert (parser, attr, *value);
8146 
8147  if (result == NULL)
8148  {
8149  /* error not invertable/updatable */
8150  /* don't want to repeat this error */
8151  if (!pt_has_error (parser))
8152  {
8154  pt_short_print (parser, attr));
8155  }
8156  return;
8157  }
8158 
8159  if (result->next)
8160  {
8161  parser_free_tree (parser, result->next);
8162  }
8163 
8164  result->next = NULL;
8165  (*value) = result; /* the right hand side */
8166 
8167  attr = attr->next;
8168  (*value)->next = value_next;
8169 
8170  value = &(*value)->next;
8171  }
8172 }
8173 
8174 
8175 /*
8176  * mq_invert_insert_subquery() - invert sub-query select lists
8177  * return:
8178  * parser(in):
8179  * attr(in):
8180  * subquery(in):
8181  */
8182 static void
8184 {
8185  PT_NODE *attr_next;
8186  PT_NODE *result;
8187 
8188  switch (subquery->node_type)
8189  {
8190  case PT_SELECT:
8191  mq_invert_insert_select (parser, *attr, subquery);
8192  break;
8193 
8194  case PT_UNION:
8195  case PT_DIFFERENCE:
8196  case PT_INTERSECTION:
8197  mq_invert_insert_subquery (parser, attr, subquery->info.query.q.union_.arg1);
8198  if (!pt_has_error (parser))
8199  {
8200  mq_invert_insert_subquery (parser, attr, subquery->info.query.q.union_.arg2);
8201  }
8202  break;
8203 
8204  default:
8205  /* should not get here, that is an error! */
8206  /* its almost certainly recoverable, so ignore it */
8207  assert (0);
8208  break;
8209  }
8210 
8211  while (*attr && !pt_has_error (parser))
8212  {
8213  attr_next = (*attr)->next;
8214  (*attr)->next = NULL;
8215 
8216  pt_find_var (*attr, &result);
8217 
8218  if (!result)
8219  {
8220  /* error not invertable/updatable already set */
8221  return;
8222  }
8223 
8224  (*attr) = result; /* the name */
8225 
8226  (*attr)->next = attr_next;
8227 
8228  attr = &(*attr)->next;
8229  }
8230 }
8231 
8232 /*
8233  * mq_make_derived_spec() -
8234  * return:
8235  * parser(in):
8236  * node(in):
8237  * subquery(in):
8238  * idx(in):
8239  * spec_ptr(out):
8240  * attr_list_ptr(out):
8241  */
8242 PT_NODE *
8243 mq_make_derived_spec (PARSER_CONTEXT * parser, PT_NODE * node, PT_NODE * subquery, int *idx, PT_NODE ** spec_ptr,
8244  PT_NODE ** attr_list_ptr)
8245 {
8246  PT_NODE *range, *spec, *as_attr_list, *col, *tmp;
8247 
8248  /* remove unnecessary ORDER BY clause. */
8249  pt_try_remove_order_by (parser, subquery);
8250 
8251  /* set line number to range name */
8252  range = pt_name (parser, "av1861");
8253 
8254  /* construct new spec */
8255  spec = parser_new_node (parser, PT_SPEC);
8256 
8257  if (spec == NULL)
8258  {
8259  PT_INTERNAL_ERROR (parser, "allocate new node");
8260  return NULL;
8261  }
8262 
8263  spec->info.spec.derived_table = subquery;
8266  spec->info.spec.range_var = range;
8267  spec->info.spec.id = (UINTPTR) spec;
8268  range->info.name.spec_id = (UINTPTR) spec;
8269 
8270  /* add new spec to the spec list */
8271  node->info.query.q.select.from = parser_append_node (spec, node->info.query.q.select.from);
8272  /* set spec as unique */
8273  node = mq_regenerate_if_ambiguous (parser, spec, node, node->info.query.q.select.from);
8274 
8275  /* construct new attr_list */
8276  spec->info.spec.as_attr_list = as_attr_list = NULL; /* init */
8277  for (col = pt_get_select_list (parser, subquery); col; col = col->next)
8278  {
8279  tmp = pt_name (parser, mq_generate_name (parser, "av", idx));
8280  tmp->info.name.meta_class = PT_NORMAL;
8282  tmp->info.name.spec_id = spec->info.spec.id;
8283  tmp->type_enum = col->type_enum;
8284  tmp->data_type = parser_copy_tree (parser, col->data_type);
8286  /* keep out hidden columns from derived select list */
8287  if (subquery->info.query.order_by && col->flag.is_hidden_column)
8288  {
8289  col->flag.is_hidden_column = 0;
8290  tmp->flag.is_hidden_column = 0;
8292  }
8293  else
8294  {
8296  as_attr_list = parser_append_node (parser_copy_tree (parser, tmp), as_attr_list);
8297  }
8298  }
8299 
8300  /* save spec, attr */
8301  if (spec_ptr)
8302  {
8303  *spec_ptr = spec;
8304  }
8305 
8306  if (attr_list_ptr)
8307  {
8308  *attr_list_ptr = as_attr_list;
8309  }
8310 
8311  return node;
8312 } /* mq_make_derived_spec */
8313 
8314 /*
8315  * mq_class_lambda() - replace class specifiers with their corresponding
8316  * virtual from list
8317  * return:
8318  * parser(in):
8319  * statement(in):
8320  * class(in):
8321  * corresponding_spec(in):
8322  * class_where_part(in):
8323  * class_check_part(in):
8324  * class_group_by_part(in):
8325  * class_having_part(in):
8326  *
8327  * Note:
8328  * A subset of general statements is handled, being
8329  * select - replace the "entity_spec" node in from list
8330  * containing class in its flat_entity_list
8331  * append the where_part, if any.
8332  * update - replace the "entity_spec" node in entity_spec
8333  * if it contains class in its flat_entity_list
8334  * append the where_part, if any.
8335  * insert - replace the "name" node equal to class
8336  * union, difference, intersection
8337  * - the recursive result of this function on both arguments.
8338  */
8339 PT_NODE *
8340 mq_class_lambda (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * class_, PT_NODE * corresponding_spec,
8341  PT_NODE * class_where_part, PT_NODE * class_check_part, PT_NODE * class_group_by_part,
8342  PT_NODE * class_having_part)
8343 {
8344  PT_NODE *spec;
8345  PT_NODE **specptr = NULL;
8346  PT_NODE **where_part = NULL, **where_part_ex = NULL;
8347  PT_NODE **check_where_part = NULL;
8348  PT_NODE *newspec = NULL;
8349  PT_NODE *oldnext = NULL;
8350  PT_NODE *assign, *result;
8351  PT_NODE *attr = NULL, *attr_next = NULL;
8352  PT_NODE **value, *value_next;
8353  PT_NODE *crt_list = NULL, *attr_names = NULL, *attr_names_crt = NULL;
8354  bool build_att_names_list = false, for_update = false;
8355  PT_NODE **lhs, **rhs, *lhs_next, *rhs_next;
8356  const char *newresolved = class_->info.name.resolved;
8357 
8358  if (statement == NULL)
8359  {
8360  return NULL;
8361  }
8362 
8363  switch (statement->node_type)
8364  {
8365  case PT_SELECT:
8366  statement->info.query.is_subquery = PT_IS_SUBQUERY;
8367 
8368  specptr = &statement->info.query.q.select.from;
8369  where_part = &statement->info.query.q.select.where;
8370  check_where_part = &statement->info.query.q.select.check_where;
8371 
8372  if (class_group_by_part || class_having_part)
8373  {
8374  /* check for derived */
8375  if (statement->info.query.flag.vspec_as_derived == 1)
8376  {
8377  /* set GROUP BY */
8378  if (class_group_by_part)
8379  {
8380  if (statement->info.query.q.select.group_by)
8381  {
8382  /* this is impossible case. give up */
8383  goto exit_on_error;
8384  }
8385  else
8386  {
8387  statement->info.query.q.select.group_by = parser_copy_tree_list (parser, class_group_by_part);
8388  }
8389  }
8390 
8391  /* merge HAVING */
8392  if (class_having_part)
8393  {
8394  PT_NODE **having_part;
8395 
8396  having_part = &statement->info.query.q.select.having;
8397 
8398  *having_part = parser_append_node (parser_copy_tree_list (parser, class_having_part), *having_part);
8399  }
8400  }
8401  else
8402  {
8403  /* system error */
8404  goto exit_on_error;
8405  }
8406  }
8407 
8408  break;
8409 
8410  case PT_UPDATE:
8411  specptr = &statement->info.update.spec;
8412  where_part = &statement->info.update.search_cond;
8413 
8414  /* Add to statement expressions to check if 'with check option' specified */
8415  check_where_part = NULL;
8416  spec = statement->info.update.spec;
8417  while (spec != NULL && spec->info.spec.id != class_->info.name.spec_id)
8418  {
8419  spec = spec->next;
8420  }
8421  if (spec != NULL)
8422  {
8423  /* Verify if a check_option node already exists for current spec. If so then append condition to existing */
8424  PT_NODE *cw = statement->info.update.check_where;
8425  while (cw != NULL && cw->info.check_option.spec_id != spec->info.spec.id)
8426  {
8427  cw = cw->next;
8428  }
8429  if (cw == NULL)
8430  {
8431  cw = parser_new_node (parser, PT_CHECK_OPTION);
8432  if (cw == NULL)
8433  {
8434  goto exit_on_error;
8435  }
8436  cw->info.check_option.spec_id = corresponding_spec->info.spec.id;
8437  statement->info.update.check_where = parser_append_node (cw, statement->info.update.check_where);
8438  }
8439  check_where_part = &cw->info.check_option.expr;
8440  }
8441 
8442  for (assign = statement->info.update.assignment; assign != NULL; assign = assign->next)
8443  {
8444  /* get lhs, rhs */
8445  lhs = &(assign->info.expr.arg1);
8446  rhs = &(assign->info.expr.arg2);
8447  if (PT_IS_N_COLUMN_UPDATE_EXPR (*lhs))
8448  {
8449  /* get lhs element */
8450  lhs = &((*lhs)->info.expr.arg1);
8451 
8452  /* get rhs element */
8453  rhs = &((*rhs)->info.query.q.select.list);
8454  }
8455 
8456  for (; *lhs && *rhs; *lhs = lhs_next, *rhs = rhs_next)
8457  {
8458  /* cut-off and save next link */
8459  lhs_next = (*lhs)->next;
8460  (*lhs)->next = NULL;
8461  rhs_next = (*rhs)->next;
8462  (*rhs)->next = NULL;
8463 
8464  *rhs = mq_translate_value (parser, *rhs);
8465 
8466  result = pt_invert (parser, *lhs, *rhs);
8467  if (!result)
8468  {
8469  /* error not invertible/updatable */
8471  pt_short_print (parser, *lhs));
8472  goto exit_on_error;
8473  }
8474 
8475  if (*lhs)
8476  {
8477  parser_free_tree (parser, *lhs);
8478  }
8479  *lhs = result->next; /* the name */
8480  result->next = NULL;
8481  *rhs = result; /* the right hand side */
8482 
8483  lhs = &((*lhs)->next);
8484  rhs = &((*rhs)->next);
8485  }
8486  }
8487  break;
8488 
8489  case PT_DELETE:
8490  specptr = &statement->info.delete_.spec;
8491  where_part = &statement->info.delete_.search_cond;
8492  break;
8493 
8494  case PT_INSERT:
8495  specptr = &statement->info.insert.spec;
8496  check_where_part = &statement->info.insert.where;
8497 
8498  crt_list = statement->info.insert.value_clauses;
8499  if (crt_list->info.node_list.list_type == PT_IS_DEFAULT_VALUE
8500  || crt_list->info.node_list.list_type == PT_IS_VALUE)
8501  {
8502  for (; crt_list != NULL; crt_list = crt_list->next)
8503  {
8504  /* Inserting the default values in the original class will "insert" the default view values in the view.
8505  * We don't need to do anything. */
8506  if (crt_list->info.node_list.list_type == PT_IS_DEFAULT_VALUE)
8507  {
8508  continue;
8509  }
8510  assert (crt_list->info.node_list.list_type == PT_IS_VALUE);
8511 
8512  /* We need to invert expressions now. */
8513  if (attr_names == NULL)
8514  {
8515  /* We'll also build a list of attribute names. */
8516  build_att_names_list = true;
8517  }
8518  else
8519  {
8520  /* The list of attribute names has already been built. */
8521  build_att_names_list = false;
8522  }
8523 
8524  attr = statement->info.insert.attr_list;
8525  value = &crt_list->info.node_list.list;
8526  while (*value)
8527  {
8528  if (attr == NULL)
8529  {
8530  /* System error, should have been caught in the semantic pass */
8532  goto exit_on_error;
8533  }
8534 
8535  attr_next = attr->next;
8536  attr->next = NULL;
8537  value_next = (*value)->next;
8538  (*value)->next = NULL;
8539 
8540  (*value) = mq_translate_value (parser, *value);
8541  result = pt_invert (parser, attr, *value);
8542 
8543  if (result == NULL)
8544  {
8545  /* error not invertable/updatable */
8547  pt_short_print (parser, attr));
8548  goto exit_on_error;
8549  }
8550 
8551  if (build_att_names_list)
8552  {
8553  if (attr_names_crt == NULL)
8554  {
8555  /* This is the first attribute in the name list. */
8556  attr_names_crt = attr_names = result->next;
8557  }
8558  else
8559  {
8560  attr_names_crt->next = result->next;
8561  attr_names_crt = attr_names_crt->next;
8562  }
8563  result->next = NULL;
8564  }
8565  else
8566  {
8567  parser_free_tree (parser, result->next);
8568  result->next = NULL;
8569  }
8570 
8571  attr->next = attr_next;
8572  attr = attr->next;
8573 
8574  (*value) = result; /* the right hand side */
8575  (*value)->next = value_next;
8576  value = &(*value)->next;
8577  }
8578  }
8579 
8580  if (attr_names != NULL)
8581  {
8582  parser_free_tree (parser, statement->info.insert.attr_list);
8583  statement->info.insert.attr_list = attr_names;
8584  attr_names = NULL;
8585  }
8586  }
8587  else if (crt_list->info.node_list.list_type == PT_IS_SUBQUERY)
8588  {
8589  assert (crt_list->next == NULL);
8590  assert (crt_list->info.node_list.list->next == NULL);
8591 
8592  mq_invert_insert_subquery (parser, &statement->info.insert.attr_list, crt_list->info.node_list.list);
8593  }
8594  else
8595  {
8596  assert (false);
8597  }
8598  break;
8599 
8600  case PT_MERGE:
8601  specptr = &statement->info.merge.into;
8602  where_part = &statement->info.merge.update.search_cond;
8603  where_part_ex = &statement->info.merge.insert.class_where;
8604  /* Add to statement expressions to check if 'with check option' specified */
8605  check_where_part = NULL;
8606  spec = statement->info.merge.into;
8607  if (spec != NULL && spec->info.spec.id == class_->info.name.spec_id)
8608  {
8609  /* Verify if a check_option node already exists for current spec. If so then append condition to existing */
8610  PT_NODE *cw = statement->info.merge.check_where;
8611  while (cw != NULL && cw->info.check_option.spec_id != spec->info.spec.id)
8612  {
8613  cw = cw->next;
8614  }
8615  if (cw == NULL)
8616  {
8617  cw = parser_new_node (parser, PT_CHECK_OPTION);
8618  if (cw == NULL)
8619  {
8620  goto exit_on_error;
8621  }
8622  cw->info.check_option.spec_id = corresponding_spec->info.spec.id;
8623  statement->info.merge.check_where = parser_append_node (cw, statement->info.merge.check_where);
8624  }
8625  check_where_part = &cw->info.check_option.expr;
8626  }
8627 
8628  /* check invertible on update assignments */
8629  if (statement->info.merge.update.assignment != NULL)
8630  {
8631  for (assign = statement->info.merge.update.assignment; assign != NULL; assign = assign->next)
8632  {
8633  /* get lhs, rhs */
8634  lhs = &(assign->info.expr.arg1);
8635  rhs = &(assign->info.expr.arg2);
8636  if (PT_IS_N_COLUMN_UPDATE_EXPR (*lhs))
8637  {
8638  /* get lhs element */
8639  lhs = &((*lhs)->info.expr.arg1);
8640 
8641  /* get rhs element */
8642  rhs = &((*rhs)->info.query.q.select.list);
8643  }
8644 
8645  for (; *lhs && *rhs; *lhs = lhs_next, *rhs = rhs_next)
8646  {
8647  /* cut-off and save next link */
8648  lhs_next = (*lhs)->next;
8649  (*lhs)->next = NULL;
8650  rhs_next = (*rhs)->next;
8651  (*rhs)->next = NULL;
8652 
8653  *rhs = mq_translate_value (parser, *rhs);
8654 
8655  result = pt_invert (parser, *lhs, *rhs);
8656  if (!result)
8657  {
8658  /* error not invertible/updatable */
8660  pt_short_print (parser, *lhs));
8661  goto exit_on_error;
8662  }
8663 
8664  if (*lhs)
8665  {
8666  parser_free_tree (parser, *lhs);
8667  }
8668  *lhs = result->next; /* the name */
8669  result->next = NULL;
8670  *rhs = result; /* the right hand side */
8671 
8672  lhs = &((*lhs)->next);
8673  rhs = &((*rhs)->next);
8674  }
8675  }
8676  }
8677 
8678  /* check insert part attributes */
8679  crt_list = statement->info.merge.insert.value_clauses;
8680  if (crt_list == NULL)
8681  {
8682  break;
8683  }
8684  if (crt_list->info.node_list.list_type == PT_IS_DEFAULT_VALUE
8685  || crt_list->info.node_list.list_type == PT_IS_VALUE)
8686  {
8687  for (; crt_list != NULL; crt_list = crt_list->next)
8688  {
8689  /* Inserting the default values in the original class will "insert" the default view values in the view.
8690  * We don't need to do anything. */
8691  if (crt_list->info.node_list.list_type == PT_IS_DEFAULT_VALUE)
8692  {
8693  continue;
8694  }
8695  assert (crt_list->info.node_list.list_type == PT_IS_VALUE);
8696 
8697  /* We need to invert expressions now. */
8698  if (attr_names == NULL)
8699  {
8700  /* We'll also build a list of attribute names. */
8701  build_att_names_list = true;
8702  }
8703  else
8704  {
8705  /* The list of attribute names has already been built. */
8706  build_att_names_list = false;
8707  }
8708 
8709  attr = statement->info.merge.insert.attr_list;
8710  value = &crt_list->info.node_list.list;
8711  while (*value)
8712  {
8713  if (attr == NULL)
8714  {
8715  /* System error, should have been caught in the semantic pass */
8717  break;
8718  }
8719 
8720  attr_next = attr->next;
8721  attr->next = NULL;
8722  value_next = (*value)->next;
8723  (*value)->next = NULL;
8724 
8725  (*value) = mq_translate_value (parser, *value);
8726  result = pt_invert (parser, attr, *value);
8727 
8728  if (result == NULL)
8729  {
8730  /* error not invertable/updatable */
8732  pt_short_print (parser, attr));
8733  break;
8734  }
8735 
8736  if (build_att_names_list)
8737  {
8738  if (attr_names_crt == NULL)
8739  {
8740  /* This is the first attribute in the name list. */
8741  attr_names_crt = attr_names = result->next;
8742  }
8743  else
8744  {
8745  attr_names_crt->next = result->next;
8746  attr_names_crt = attr_names_crt->next;
8747  }
8748  result->next = NULL;
8749  }
8750  else
8751  {
8752  parser_free_tree (parser, result->next);
8753  result->next = NULL;
8754  }
8755 
8756  attr->next = attr_next;
8757  attr = attr->next;
8758 
8759  (*value) = result; /* the right hand side */
8760  (*value)->next = value_next;
8761  value = &(*value)->next;
8762  }
8763  }
8764 
8765  if (attr_names != NULL)
8766  {
8767  parser_free_tree (parser, statement->info.merge.insert.attr_list);
8768  statement->info.merge.insert.attr_list = attr_names;
8769  attr_names = NULL;
8770  }
8771  }
8772  else
8773  {
8774  assert (false);
8775  }
8776  break;
8777 
8778 #if 0 /* this is impossible case */
8779  case PT_UNION:
8780  case PT_DIFFERENCE:
8781  case PT_INTERSECTION:
8782  statement->info.query.q.union_.arg1 =
8783  mq_class_lambda (parser, statement->info.query.q.union_.arg1, class_, corresponding_spec, class_where_part,
8784  class_check_part, class_group_by_part, class_having_part);
8785  statement->info.query.q.union_.arg2 =
8786  mq_class_lambda (parser, statement->info.query.q.union_.arg2, class_, corresponding_spec, class_where_part,
8787  class_check_part, class_group_by_part, class_having_part);
8788  break;
8789 #endif /* this is impossible case */
8790 
8791  default:
8792  /* system error */
8793  goto exit_on_error;
8794  }
8795 
8796  /* handle is a where parts of view sub-querys */
8797  if (where_part)
8798  {
8799  /* force sub expressions to be parenthesized for correct printing. Otherwise, the associativity may be wrong when
8800  * the statement is printed and sent to a local database */
8801  if (class_where_part && class_where_part->node_type == PT_EXPR)
8802  {
8803  class_where_part->info.expr.paren_type = 1;
8804  }
8805  if ((*where_part) && (*where_part)->node_type == PT_EXPR)
8806  {
8807  (*where_part)->info.expr.paren_type = 1;
8808  }
8809  /* The "where clause" is in the form of a list of CNF "and" terms. In order to "and" together the view's "where
8810  * clause" with the statement's, we must maintain this list of terms. Using a 'PT_AND' node here will have the
8811  * effect of losing the "and" terms on the tail of either list. */
8812  *where_part = parser_append_node (parser_copy_tree_list (parser, class_where_part), *where_part);
8813  /* class where part of merge insert clause */
8814  if (where_part_ex)
8815  {
8816  if ((*where_part_ex) && (*where_part_ex)->node_type == PT_EXPR)
8817  {
8818  (*where_part_ex)->info.expr.paren_type = 1;
8819  }
8820  *where_part_ex = parser_append_node (parser_copy_tree_list (parser, class_where_part), *where_part_ex);
8821  }
8822  }
8823  if (check_where_part)
8824  {
8825  if (class_check_part && class_check_part->node_type == PT_EXPR)
8826  {
8827  class_check_part->info.expr.paren_type = 1;
8828  }
8829  if ((*check_where_part) && (*check_where_part)->node_type == PT_EXPR)
8830  {
8831  (*check_where_part)->info.expr.paren_type = 1;
8832  }
8833  *check_where_part = parser_append_node (parser_copy_tree_list (parser, class_check_part), *check_where_part);
8834  }
8835 
8836  if (specptr)
8837  {
8838  spec = *specptr;
8839  while (spec && class_->info.name.spec_id != spec->info.spec.id)
8840  {
8841  specptr = &spec->next;
8842  spec = *specptr;
8843  }
8844  if (spec)
8845  {
8846  SPEC_RESET_INFO spec_reset;
8847  PT_NODE *subpaths;
8848 
8849  newspec = parser_copy_tree_list (parser, corresponding_spec);
8850  oldnext = spec->next;
8851  spec->next = NULL;
8852  subpaths = spec->info.spec.path_entities;
8853  spec_reset.sub_paths = &subpaths;
8854  spec_reset.statement = statement;
8855  spec_reset.old_next = oldnext;
8856  spec->info.spec.path_entities = NULL;
8857  if (newspec)
8858  {
8860  {
8861  /* flat_entity_list is needed to gather referenced oids in xasl_generation
8862  * in pt_spec_to_xasl_class_oid_list */
8864  spec->info.spec.flat_entity_list = NULL;
8865  }
8866  else
8867  {
8868  if (newspec->info.spec.entity_name == NULL)
8869  {
8870  newspec->info.spec.entity_name = spec->info.spec.entity_name;
8871  /* spec will be free later, we don't want the entity_name will be freed */
8872  spec->info.spec.entity_name = NULL;
8873  }
8875  }
8876 
8877  newspec->info.spec.location = spec->info.spec.location;
8878  /* move join info */
8879  if (spec->info.spec.join_type != PT_JOIN_NONE)
8880  {
8881  newspec->info.spec.join_type = spec->info.spec.join_type;
8882  newspec->info.spec.on_cond = spec->info.spec.on_cond;
8883  spec->info.spec.on_cond = NULL;
8884  }
8885  }
8886  for_update = (PT_SELECT_INFO_IS_FLAGED (statement, PT_SELECT_INFO_FOR_UPDATE)
8888  parser_free_tree (parser, spec);
8889 
8890  if (newspec)
8891  {
8892  *specptr = newspec;
8893  parser_append_node (oldnext, newspec);
8894 
8895  newspec =
8896  parser_walk_tree (parser, newspec, mq_reset_spec_distr_subpath_pre, &spec_reset,
8897  mq_reset_spec_distr_subpath_post, &spec_reset);
8898 
8899  statement = spec_reset.statement;
8900  }
8901  else
8902  {
8903  PT_INTERNAL_ERROR (parser, "translate");
8904  goto exit_on_error;
8905  }
8906  }
8907  else
8908  {
8909  /* we are doing a null substitution. ie the classes don't match the spec. The "correct translation" is NULL.
8910  * */
8911  goto exit_on_error;
8912  }
8913  }
8914 
8915  if (statement)
8916  {
8917  /* The spec id's are those copied from the cache. They are unique in this statment tree, but will not be unique
8918  * if this tree is once more translated against the same virtual class_. Now, the newly introduced entity specs,
8919  * are gone through and the id's for each and each name reset again to a new (uncopied) unique number, to
8920  * preserve the uniqueness of the specs. */
8921  for (spec = newspec; spec != NULL; spec = spec->next)
8922  {
8923  if (spec == oldnext)
8924  {
8925  break; /* these are already ok */
8926  }
8927 
8928  /* translate virtual sub-paths */
8929  statement = mq_translate_paths (parser, statement, spec);
8930 
8931  /* reset ids of path specs, or toss them, as necessary */
8932  statement = mq_reset_paths (parser, statement, spec);
8933 
8934  if (for_update)
8935  {
8937  }
8938  }
8939 
8940 
8941  if (newspec)
8942  {
8943  if (!PT_IS_QUERY_NODE_TYPE (statement->node_type))
8944  {
8945  /* PT_INSERT, PT_UPDATE, PT_DELETE */
8946  statement = mq_rename_resolved (parser, newspec, statement, newresolved);
8947  newspec = newspec->next;
8948  }
8949  for (spec = newspec; spec != NULL; spec = spec->next)
8950  {
8951  if (spec == oldnext || statement == NULL)
8952  {
8953  break; /* these are already ok */
8954  }
8955  if (spec->info.spec.range_var->alias_print)
8956  {
8957  char *temp;
8958  temp = pt_append_string (parser, NULL, newresolved);
8959  temp = pt_append_string (parser, temp, ":");
8960  temp = pt_append_string (parser, temp, spec->info.spec.range_var->alias_print);
8961  spec->info.spec.range_var->alias_print = temp;
8962  }
8963  else
8964  {
8965  spec->info.spec.range_var->alias_print = newresolved;
8966  }
8967  statement = mq_regenerate_if_ambiguous (parser, spec, statement, statement->info.query.q.select.from);
8968  }
8969  }
8970  }
8971 
8972  return statement;
8973 
8974 exit_on_error:
8975  if (attr_names != NULL)
8976  {
8977  parser_free_tree (parser, attr_names);
8978  }
8979  return NULL;
8980 }
8981 
8982 
8983 /*
8984  * mq_push_arg2() - makes the first item of each top level select into
8985  * path expression with arg2
8986  * return:
8987  * parser(in):
8988  * query(in):
8989  * dot_arg2(in):
8990  */
8991 static PT_NODE *
8992 mq_push_arg2 (PARSER_CONTEXT * parser, PT_NODE * query, PT_NODE * dot_arg2)
8993 {
8994  PT_NODE *dot;
8995  PT_NODE *spec = NULL;
8996  PT_NODE *new_spec;
8997  PT_NODE *name;
8998 
8999  switch (query->node_type)
9000  {
9001  case PT_SELECT:
9003  {
9004  query->info.query.q.select.list = mq_push_arg2 (parser, query->info.query.q.select.list, dot_arg2);
9005  }
9006  else
9007  {
9008  name = query->info.query.q.select.list;
9009  if (name->node_type != PT_NAME)
9010  {
9011  if (name->node_type == PT_DOT_)
9012  {
9013  name = name->info.dot.arg2;
9014  }
9015  else if (name->node_type == PT_METHOD_CALL)
9016  {
9017  name = name->info.method_call.method_name;
9018  }
9019  else
9020  {
9021  name = NULL;
9022  }
9023  }
9024  if (name)
9025  {
9026  spec = pt_find_entity (parser, query->info.query.q.select.from, name->info.name.spec_id);
9027  }
9028 
9029  if (spec == NULL)
9030  {
9031  break;
9032  }
9033 
9034  dot = parser_copy_tree (parser, dot_arg2);
9035  if (dot == NULL)
9036  {
9037  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
9038  return NULL;
9039  }
9040 
9041  dot->info.dot.arg1 = query->info.query.q.select.list;
9042  query->info.query.q.select.list = dot;
9043  new_spec = pt_insert_entity (parser, dot, spec, NULL);
9044  parser_free_tree (parser, query->data_type);
9045  query->type_enum = dot->type_enum;
9046  query->data_type = parser_copy_tree_list (parser, dot->data_type);
9047  query = mq_translate_paths (parser, query, spec);
9048  query = mq_reset_paths (parser, query, spec);
9049  }
9050  break;
9051 
9052  case PT_UNION:
9053  case PT_INTERSECTION:
9054  case PT_DIFFERENCE:
9055  query->info.query.q.union_.arg1 = mq_push_arg2 (parser, query->info.query.q.union_.arg1, dot_arg2);
9056  query->info.query.q.union_.arg2 = mq_push_arg2 (parser, query->info.query.q.union_.arg2, dot_arg2);
9057  parser_free_tree (parser, query->data_type);
9058  query->type_enum = query->info.query.q.union_.arg1->type_enum;
9059  query->data_type = parser_copy_tree_list (parser, query->info.query.q.union_.arg1->data_type);
9060  break;
9061 
9062  default:
9063  break;
9064  }
9065 
9066  return query;
9067 }
9068 
9069 
9070 /*
9071  * mq_lambda_node_pre() - creates extra spec frames for each select
9072  * return:
9073  * parser(in):
9074  * tree(in):
9075  * void_arg(in):
9076  * continue_walk(in):
9077  */
9078 static PT_NODE *
9079 mq_lambda_node_pre (PARSER_CONTEXT * parser, PT_NODE * tree, void *void_arg, int *continue_walk)
9080 {
9081  MQ_LAMBDA_ARG *lambda_arg = (MQ_LAMBDA_ARG *) void_arg;
9082  PT_EXTRA_SPECS_FRAME *spec_frame;
9083 
9084  if (tree->node_type == PT_SELECT)
9085  {
9086  spec_frame = (PT_EXTRA_SPECS_FRAME *) malloc (sizeof (PT_EXTRA_SPECS_FRAME));
9087 
9088  if (spec_frame == NULL)
9089  {
9090  PT_INTERNAL_ERROR (parser, "malloc");
9091  return NULL;
9092  }
9093  spec_frame->next = lambda_arg->spec_frames;
9094  spec_frame->extra_specs = NULL;
9095  lambda_arg->spec_frames = spec_frame;
9096  }
9097 
9098  return tree;
9099 
9100 } /* mq_lambda_node_pre */
9101 
9102 
9103 /*
9104  * mq_lambda_node() - applies the lambda test to the node passed to it,
9105  * and conditionally substitutes a copy of its corresponding tree
9106  * return:
9107  * parser(in):
9108  * node(in):
9109  * void_arg(in):
9110  * continue_walk(in):
9111  */
9112 static PT_NODE *
9113 mq_lambda_node (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
9114 {
9115  MQ_LAMBDA_ARG *lambda_arg = (MQ_LAMBDA_ARG *) void_arg;
9116  PT_NODE *save_node_next, *result, *arg1, *spec;
9117  PT_NODE *dt1, *dt2;
9118  PT_EXTRA_SPECS_FRAME *spec_frame;
9119  PT_NODE *save_data_type;
9120  PT_NODE *name, *tree;
9121 
9122  result = node;
9123 
9124  switch (node->node_type)
9125  {
9126 
9127  case PT_DOT_:
9128  /* Check if the recursive call left an "illegal" path expression */
9129  if ((arg1 = node->info.dot.arg1))
9130  {
9131  save_node_next = node->next;
9132  if (PT_IS_QUERY_NODE_TYPE (arg1->node_type))
9133  {
9134  node->info.dot.arg1 = NULL;
9135  node->next = NULL;
9136 
9137  result = mq_push_arg2 (parser, arg1, node);
9138 
9139  parser_free_tree (parser, node); /* re-use this memory */
9140  /* could free data_type, and entity_list here too. */
9141 
9142  /* if this name was in a name list, keep the list tail */
9143  if (result)
9144  {
9145  result->next = save_node_next;
9146  }
9147  }
9148  else if (arg1->node_type == PT_NAME && PT_IS_OID_NAME (arg1))
9149  {
9150  /* we have an artificial path, from a view that selects an oid, eg create view foo (a) as select x from x
9151  * It would be nice to translate this to just the RHS, but subsequent path translation would have nothing
9152  * to key off of. */
9153 
9154  }
9155  else if (PT_IS_NULL_NODE (arg1))
9156  {
9157  /* someone did a select a.b from view, where a is a null the result is also NULL. */
9158 
9159  node->info.dot.arg1 = NULL;
9160  node->next = NULL;
9161 
9162  result = arg1;
9163 
9164  parser_free_tree (parser, node); /* re-use this memory */
9165 
9166  /* if this name was in a name list, keep the list tail */
9167  result->next = save_node_next;
9168  }
9169  }
9170  break;
9171 
9172  case PT_NAME:
9173  for (name = lambda_arg->name_list, tree = lambda_arg->tree_list; name && tree;
9174  name = name->next, tree = tree->next)
9175  {
9176  /* If the names are equal, substitute new sub tree Here we DON't want to do the usual strict name-datatype
9177  * matching. This is where we project one object attribute as another, so we deliberately allow the loosely
9178  * typed match by nulling the data_type. */
9179  save_data_type = name->data_type; /* save */
9180  name->data_type = NULL;
9181 
9182  if (pt_name_equal (parser, node, name))
9183  {
9184  save_node_next = node->next;
9185  node->next = NULL;
9186 
9187  result = parser_copy_tree (parser, tree); /* substitute */
9188 
9189  /* Keep hidden column information during view translation */
9190  if (result)
9191  {
9192  result->line_number = node->line_number;
9193  result->column_number = node->column_number;
9194  result->flag.is_hidden_column = node->flag.is_hidden_column;
9195  result->buffer_pos = node->buffer_pos;
9196 #if 0
9197  result->info.name.original = node->info.name.original;
9198 #endif /* 0 */
9199  }
9200 
9201  /* we may have just copied a whole query, if so, reset its id's */
9202  result = mq_reset_specs_from_column (parser, result, tree);
9203 
9204  if (lambda_arg->spec_frames && node->info.name.meta_class == PT_SHARED)
9205  {
9206  PT_NODE *class_spec;
9207  PT_NODE *entity;
9208 
9209  /* check for found */
9210  for (class_spec = lambda_arg->spec_frames->extra_specs; class_spec; class_spec = class_spec->next)
9211  {
9212  entity = class_spec->info.spec.entity_name;
9213  if (!intl_identifier_casecmp (entity->info.name.original, result->info.name.resolved))
9214  {
9215  break; /* found */
9216  }
9217  }
9218 
9219  if (!class_spec)
9220  { /* not found */
9221  class_spec = mq_new_spec (parser, result->info.name.resolved);
9222  if (class_spec == NULL)
9223  {
9224  return NULL;
9225  }
9226 
9227  /* add the new spec to the extra_specs */
9228  lambda_arg->spec_frames->extra_specs =
9229  parser_append_node (class_spec, lambda_arg->spec_frames->extra_specs);
9230  }
9231 
9232  /* resolve the name node to the new spec */
9233  result->info.name.spec_id = class_spec->info.spec.id;
9234  }
9235 
9236  parser_free_tree (parser, node); /* re-use this memory */
9237 
9238  result->next = save_node_next;
9239 
9240  name->data_type = save_data_type; /* restore */
9241 
9242  break; /* exit for-loop */
9243  }
9244 
9245  /* name did not match. go ahead */
9246  name->data_type = save_data_type; /* restore */
9247  }
9248 
9249  break;
9250 
9251  case PT_SELECT:
9252  /* maintain virtual data type information */
9253  if ((dt1 = result->data_type) && result->info.query.q.select.list
9254  && (dt2 = result->info.query.q.select.list->data_type))
9255  {
9256  parser_free_tree (parser, result->data_type);
9257  result->data_type = parser_copy_tree_list (parser, dt2);
9258  }
9259  /* pop the extra spec frame and add any extra specs to the from list */
9260  spec_frame = lambda_arg->spec_frames;
9261  lambda_arg->spec_frames = lambda_arg->spec_frames->next;
9262  result->info.query.q.select.from = parser_append_node (spec_frame->extra_specs, result->info.query.q.select.from);
9263 
9264  /* adding specs may have created ambiguous spec names */
9265  for (spec = spec_frame->extra_specs; spec != NULL; spec = spec->next)
9266  {
9267  result = mq_regenerate_if_ambiguous (parser, spec, result, result->info.query.q.select.from);
9268  }
9269 
9270  free_and_init (spec_frame);
9271  break;
9272 
9273  case PT_UNION:
9274  case PT_DIFFERENCE:
9275  case PT_INTERSECTION:
9276  /* maintain virtual data type information */
9277  if ((dt1 = result->data_type) && result->info.query.q.union_.arg1
9278  && (dt2 = result->info.query.q.union_.arg1->data_type))
9279  {
9280  parser_free_tree (parser, result->data_type);
9281  result->data_type = parser_copy_tree_list (parser, dt2);
9282  }
9283  break;
9284 
9285  default:
9286  break;
9287  }
9288 
9289  return result;
9290 }
9291 
9292 /*
9293  * mq_lambda() - modifies name nodes with copies of a corresponding tree
9294  * return:
9295  * parser(in):
9296  * tree_with_names(in):
9297  * name_node_list(in):
9298  * corresponding_tree_list(in):
9299  */
9300 PT_NODE *
9301 mq_lambda (PARSER_CONTEXT * parser, PT_NODE * tree_with_names, PT_NODE * name_node_list,
9302  PT_NODE * corresponding_tree_list)
9303 {
9304  MQ_LAMBDA_ARG lambda_arg;
9305  PT_NODE *tree;
9306  PT_NODE *name;
9307 
9308  lambda_arg.name_list = name_node_list;
9309  lambda_arg.tree_list = corresponding_tree_list;
9310  lambda_arg.spec_frames = NULL;
9311 
9312  for (name = lambda_arg.name_list, tree = lambda_arg.tree_list; name && tree; name = name->next, tree = tree->next)
9313  {
9314  if (tree->node_type == PT_EXPR)
9315  {
9316  /* make sure it will print with proper precedance. we don't want to replace "name" with "1+2" in 4*name, and
9317  * get 4*1+2. It should be 4*(1+2) instead. */
9318  tree->info.expr.paren_type = 1;
9319  }
9320 
9321  if (name->node_type != PT_NAME)
9322  { /* unkonwn error */
9323  tree = tree_with_names;
9324  goto exit_on_error;
9325  }
9326 
9327  }
9328 
9329  tree = parser_walk_tree (parser, tree_with_names, mq_lambda_node_pre, &lambda_arg, mq_lambda_node, &lambda_arg);
9330 
9331 exit_on_error:
9332 
9333  return tree;
9334 }
9335 
9336 
9337 /*
9338  * mq_set_virt_object() - checks and sets name nodes of object type
9339  * virtual object information
9340  * return:
9341  * parser(in):
9342  * node(in):
9343  * void_arg(in):
9344  * continue_walk(in):
9345  */
9346 static PT_NODE *
9347 mq_set_virt_object (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
9348 {
9349  PT_NODE *spec = (PT_NODE *) void_arg;
9350  PT_NODE *dt;
9351  PT_NODE *cls;
9352 
9353  if (node->node_type == PT_NAME && node->info.name.spec_id == spec->info.spec.id && (dt = node->data_type)
9354  && node->type_enum == PT_TYPE_OBJECT && (cls = dt->info.data_type.entity)
9355  /* To distinguish between "V" and "class V" (V is a view) */
9356  && cls->info.name.meta_class != PT_META_CLASS)
9357  {
9358  if (db_is_vclass (cls->info.name.db_object) > 0)
9359  {
9360  dt->info.data_type.virt_object = cls->info.name.db_object;
9361  if (mq_is_updatable (cls->info.name.db_object))
9362  {
9363  PARSER_CONTEXT *query_cache;
9364  PT_NODE *flat;
9365 
9366  flat = mq_fetch_one_real_class_get_cache (cls->info.name.db_object, &query_cache);
9367 
9368  if (flat)
9369  {
9370  dt->info.data_type.entity = parser_copy_tree_list (parser, flat);
9371  }
9372  }
9373  else
9374  {
9375  dt->info.data_type.entity = NULL;
9376  }
9377  parser_free_tree (parser, cls);
9378  }
9379  }
9380 
9381  return node;
9382 }
9383 
9384 
9385 /*
9386  * mq_fix_derived() - fixes derived table and checks for virtual object types
9387  * return:
9388  * parser(in):
9389  * select_statement(in):
9390  * spec(in):
9391  */
9392 static PT_NODE *
9393 mq_fix_derived (PARSER_CONTEXT * parser, PT_NODE * select_statement, PT_NODE * spec)
9394 {
9395  PT_NODE *attr = spec->info.spec.as_attr_list;
9396  PT_NODE *attr_next;
9397  PT_NODE *dt;
9398  PT_NODE *cls;
9399  int had_virtual, any_had_virtual;
9400 
9401  any_had_virtual = 0;
9402  while (attr)
9403  {
9404  dt = attr->data_type;
9405  had_virtual = 0;
9406  if (dt && attr->type_enum == PT_TYPE_OBJECT)
9407  {
9408  cls = dt->info.data_type.entity;
9409  while (cls)
9410  {
9411  /* To distinguish between "V" and "class V" (V is a view) */
9412  if (cls->info.name.meta_class != PT_META_CLASS && db_is_vclass (cls->info.name.db_object) > 0)
9413  {
9415  had_virtual = 1;
9416  }
9417  cls = cls->next;
9418  }
9419  }
9420  attr_next = attr->next;
9421  if (had_virtual)
9422  {
9423  any_had_virtual = 1;
9424  }
9425  attr = attr_next;
9426  }
9427 
9428  mq_reset_ids (parser, select_statement, spec);
9429 
9430  if (any_had_virtual)
9431  {
9432  select_statement = parser_walk_tree (parser, select_statement, mq_set_virt_object, spec, NULL, NULL);
9433  select_statement = mq_translate_paths (parser, select_statement, spec);
9434  select_statement = mq_reset_paths (parser, select_statement, spec);
9435  }
9436 
9437  return select_statement;
9438 }
9439 
9440 
9441 /*
9442  * mq_fix_derived_in_union() - fixes the derived tables in queries
9443  * return:
9444  * parser(in):
9445  * statement(in):
9446  * spec_id(in):
9447  *
9448  * Note:
9449  * It performs two functions
9450  * 1) In a given select, the outer level derived table spec
9451  * is not in general the SAME spec being manipulated here.
9452  * This spec is a copy of the outer spec, with the same id.
9453  * Thus, we use the spec_id to find the derived table of interest
9454  * to 'fix up'.
9455  * 2) Since the statement may have been translated to a union,
9456  * there may be multiple derived tables to fix up. This
9457  * recurses for unions to do so.
9458  */
9459 PT_NODE *
9460 mq_fix_derived_in_union (PARSER_CONTEXT * parser, PT_NODE * statement, UINTPTR spec_id)
9461 {
9462  PT_NODE *spec;
9463 
9464  if (statement == NULL)
9465  {
9466  return NULL;
9467  }
9468 
9469  switch (statement->node_type)
9470  {
9471  case PT_SELECT:
9472  spec = statement->info.query.q.select.from;
9473  while (spec && spec->info.spec.id != spec_id)
9474  {
9475  spec = spec->next;
9476  }
9477  if (spec)
9478  {
9479  statement = mq_fix_derived (parser, statement, spec);
9480  }
9481  else
9482  {
9483  PT_INTERNAL_ERROR (parser, "translate");
9484  }
9485  break;
9486 
9487  case PT_DELETE:
9488  spec = statement->info.delete_.spec;
9489  while (spec && spec->info.spec.id != spec_id)
9490  {
9491  spec = spec->next;
9492  }
9493  if (spec)
9494  {
9495  statement = mq_fix_derived (parser, statement, spec);
9496  }
9497  else
9498  {
9499  PT_INTERNAL_ERROR (parser, "translate");
9500  }
9501  break;
9502 
9503  case PT_UPDATE:
9504  spec = statement->info.update.spec;
9505  while (spec && spec->info.spec.id != spec_id)
9506  {
9507  spec = spec->next;
9508  }
9509  if (spec)
9510  {
9511  statement = mq_fix_derived (parser, statement, spec);
9512  }
9513  else
9514  {
9515  PT_INTERNAL_ERROR (parser, "translate");
9516  }
9517  break;
9518 
9519  case PT_MERGE:
9520  {
9521  spec = statement->info.merge.into;
9522  spec->next = statement->info.merge.using_clause;
9523 
9524  while (spec && spec->info.spec.id != spec_id)
9525  {
9526  spec = spec->next;
9527  }
9528  if (spec)
9529  {
9530  statement = mq_fix_derived (parser, statement, spec);
9531  }
9532  else
9533  {
9534  PT_INTERNAL_ERROR (parser, "translate");
9535  }
9536 
9537  if (statement)
9538  {
9539  statement->info.merge.into->next = NULL;
9540  }
9541  }
9542  break;
9543 
9544  case PT_UNION:
9545  case PT_DIFFERENCE:
9546  case PT_INTERSECTION:
9547  statement->info.query.q.union_.arg1 =
9548  mq_fix_derived_in_union (parser, statement->info.query.q.union_.arg1, spec_id);
9549  statement->info.query.q.union_.arg2 =
9550  mq_fix_derived_in_union (parser, statement->info.query.q.union_.arg2, spec_id);
9551  break;
9552 
9553  default:
9554  PT_INTERNAL_ERROR (parser, "translate");
9555  break;
9556  }
9557 
9558  return statement;
9559 }
9560 
9561 
9562 /*
9563  * mq_translate_value() - translate a virtual object to the real object
9564  * return:
9565  * parser(in):
9566  * value(in):
9567  */
9568 static PT_NODE *
9570 {
9571  PT_NODE *data_type, *class_;
9572  DB_OBJECT *real_object, *real_class;
9573  DB_VALUE *db_value;
9574 
9575  if (value->node_type == PT_VALUE && value->type_enum == PT_TYPE_OBJECT && (data_type = value->data_type)
9576  && (class_ = data_type->info.data_type.entity) && class_->node_type == PT_NAME
9577  && db_is_vclass (class_->info.name.db_object) > 0)
9578  {
9579  data_type->info.data_type.virt_object = class_->info.name.db_object;
9580  real_object = db_real_instance (value->info.value.data_value.op);
9581  if (real_object)
9582  {
9583  real_class = db_get_class (real_object);
9584  class_->info.name.db_object = db_get_class (real_object);
9585  class_->info.name.original = db_get_class_name (class_->info.name.db_object);
9586  value->info.value.data_value.op = real_object;
9587 
9588  db_value = pt_value_to_db (parser, value);
9589  if (db_value)
9590  {
9591  db_make_object (db_value, value->info.value.data_value.op);
9592  }
9593 
9594  }
9595  }
9596 
9597  return value;
9598 }
9599 
9600 
9601 /*
9602  * mq_push_dot_in_query() - Generate a new dot expression from the i'th column
9603  * and the name passed in for every select list
9604  * return:
9605  * parser(in):
9606  * query(in):
9607  * i(in):
9608  * name(in):
9609  */
9610 static void
9611 mq_push_dot_in_query (PARSER_CONTEXT * parser, PT_NODE * query, int i, PT_NODE * name)
9612 {
9613  PT_NODE *col;
9614  PT_NODE *new_col;
9615  PT_NODE *root;
9616  PT_NODE *new_spec;
9617 
9618  if (query)
9619  {
9620  switch (query->node_type)
9621  {
9622  case PT_SELECT:
9623  col = query->info.query.q.select.list;
9624  while (i > 0 && col)
9625  {
9626  col = col->next;
9627  i--;
9628  }
9629  if (col && col->node_type == PT_NAME && PT_IS_OID_NAME (col))
9630  {
9631  root = pt_find_entity (parser, query->info.query.q.select.from, col->info.name.spec_id);
9632  new_col = parser_copy_tree (parser, name);
9633  if (new_col == NULL)
9634  {
9635  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
9636  return;
9637  }
9638 
9639  new_col->info.name.spec_id = col->info.name.spec_id;
9640  new_col->info.name.resolved = col->info.name.resolved;
9641  root = pt_find_entity (parser, query->info.query.q.select.from, col->info.name.spec_id);
9642  }
9643  else
9644  {
9645  new_col = parser_new_node (parser, PT_DOT_);
9646 
9647  if (new_col == NULL)
9648  {
9649  PT_INTERNAL_ERROR (parser, "allocate new node");
9650  return;
9651  }
9652 
9653  new_col->info.dot.arg1 = parser_copy_tree (parser, col);
9654  if (new_col->info.dot.arg1 == NULL)
9655  {
9656  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
9657  return;
9658  }
9659 
9660  new_col->info.dot.arg2 = parser_copy_tree (parser, name);
9661  if (new_col->info.dot.arg2 == NULL)
9662  {
9663  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
9664  return;
9665  }
9666 
9667  new_col->info.dot.arg2->info.name.spec_id = 0;
9668  new_col->info.dot.arg2->info.name.resolved = NULL;
9669  new_col->type_enum = name->type_enum;
9670  new_col->data_type = parser_copy_tree_list (parser, name->data_type);
9671  root = NULL;
9672 
9673  if (col == NULL)
9674  {
9675  return;
9676  }
9677 
9678  if (col->node_type == PT_NAME)
9679  {
9680  root = pt_find_entity (parser, query->info.query.q.select.from, col->info.name.spec_id);
9681  }
9682  else if (col->node_type == PT_DOT_)
9683  {
9684  root =
9685  pt_find_entity (parser, query->info.query.q.select.from, col->info.dot.arg2->info.name.spec_id);
9686  }
9687  if (root)
9688  {
9689  new_spec = pt_insert_entity (parser, new_col, root, NULL);
9690  if (new_spec)
9691  {
9692  new_col->info.dot.arg2->info.name.spec_id = new_spec->info.spec.id;
9693  }
9694  else
9695  {
9696  /* error is set by pt_insert_entity */
9697  }
9698  }
9699  }
9700  parser_append_node (new_col, col);
9701  break;
9702 
9703  case PT_UNION:
9704  case PT_DIFFERENCE:
9705  case PT_INTERSECTION:
9706  mq_push_dot_in_query (parser, query->info.query.q.union_.arg1, i, name);
9707  mq_push_dot_in_query (parser, query->info.query.q.union_.arg2, i, name);
9708  break;
9709 
9710  default:
9711  /* should not get here, that is an error! */
9712  /* its almost certainly recoverable, so ignore it */
9713  assert (0);
9714  break;
9715  }
9716  }
9717 }
9718 
9719 
9720 /*
9721  * mq_clean_dot() -
9722  * return:
9723  * parser(in):
9724  * node(in):
9725  * void_arg(in):
9726  * continue_walk(in):
9727  */
9728 static PT_NODE *
9729 mq_clean_dot (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
9730 {
9731  PT_NODE *spec = (PT_NODE *) void_arg;
9732  PT_NODE *temp;
9733  PT_NODE *next;
9734 
9735  if (node == NULL)
9736  {
9737  return node;
9738  }
9739 
9740  switch (node->node_type)
9741  {
9742  case PT_DOT_:
9743  if (node->info.dot.arg2->info.name.spec_id == spec->info.spec.id)
9744  {
9745  next = node->next;
9746  temp = node->info.dot.arg2;
9747  node->info.dot.arg2 = NULL;
9748  node->next = NULL;
9749  parser_free_tree (parser, node);
9750  node = temp;
9751  node->next = next;
9752  }
9753  break;
9754 
9755  default:
9756  break;
9757  }
9758 
9759  return node;
9760 }
9761 
9762 
9763 /*
9764  * mq_push_path() -
9765  * return:
9766  * parser(in):
9767  * statement(in): a select statement needing fixing
9768  * spec(in): the spec of the derived query
9769  * path(in): the path to push inside the spec
9770  */
9771 PT_NODE *
9772 mq_push_path (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * spec, PT_NODE * path)
9773 {
9774  PT_NODE *cols = spec->info.spec.as_attr_list;
9775  PT_NODE *new_col;
9776  PT_NODE *sub_paths;
9777  PT_NODE *refs, *free_refs;
9778  PT_NODE *join = path->info.spec.path_conjuncts;
9779  int i = pt_find_attribute (parser, join->info.expr.arg1, cols);
9780 
9781  refs = mq_get_references (parser, statement, path);
9782  free_refs = refs;
9783  path->info.spec.referenced_attrs = NULL;
9784 
9785  if (i >= 0)
9786  {
9787  while (refs)
9788  {
9789  if (!PT_IS_OID_NAME (refs))
9790  {
9791  /* for each referenced attribute, 1) Make a new derived table symbol on referenced and as_attr_lists. 2)
9792  * Create a new path node on each select list made from the referenced name and the column corresponding
9793  * to the join arg1. 3) replace the names in statement corresponding to references with generated name. */
9794  new_col = mq_generate_unique (parser, cols);
9795  if (new_col != NULL)
9796  {
9797  parser_free_tree (parser, new_col->data_type);
9798  new_col->data_type = parser_copy_tree_list (parser, refs->data_type);
9799  new_col->type_enum = refs->type_enum;
9800  parser_append_node (new_col, cols);
9801 
9802  mq_push_dot_in_query (parser, spec->info.spec.derived_table, i, refs);
9803 
9804  /* not mq_lambda ... */
9805  statement = pt_lambda (parser, statement, refs, new_col);
9806 
9807  path = pt_lambda (parser, path, refs, new_col);
9808  }
9809  }
9810 
9811  refs = refs->next;
9812  }
9813  }
9814 
9815 
9816  parser_free_tree (parser, free_refs);
9817 
9818  sub_paths = path->info.spec.path_entities;
9819  for (; sub_paths != NULL; sub_paths = sub_paths->next)
9820  {
9821  statement = mq_push_path (parser, statement, spec, sub_paths);
9822  }
9823 
9824  statement = parser_walk_tree (parser, statement, mq_clean_dot, spec, NULL, NULL);
9825 
9826  return statement;
9827 }
9828 
9829 
9830 /*
9831  * mq_derived_path() -
9832  * return: derived path spec
9833  * parser(in):
9834  * statement(in): a select statement needing fixing
9835  * path(in): the path to rewrite
9836  */
9837 PT_NODE *
9838 mq_derived_path (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * path)
9839 {
9840  PT_NODE *join;
9841  PT_NODE *new_spec;
9842  PT_NODE *query;
9843  PT_NODE *temp;
9844  PT_NODE *sub_paths;
9845  PT_NODE *new_sub_path;
9846 
9847  new_spec = parser_new_node (parser, PT_SPEC);
9848  if (new_spec == NULL)
9849  {
9850  PT_INTERNAL_ERROR (parser, "allocate new node");
9851  return NULL;
9852  }
9853 
9854  query = parser_new_node (parser, PT_SELECT);
9855  if (query == NULL)
9856  {
9857  PT_INTERNAL_ERROR (parser, "allocate new node");
9858  return NULL;
9859  }
9860 
9862  if (path->info.spec.entity_name)
9863  {
9865  }
9866  sub_paths = path->info.spec.path_entities;
9867  path->info.spec.path_entities = NULL;
9868  join = path->info.spec.path_conjuncts;
9869  path->info.spec.path_conjuncts = NULL;
9870 
9871  /* move path join term */
9872  new_spec->info.spec.path_conjuncts = join;
9873  new_spec->info.spec.path_entities = sub_paths;
9875  new_spec->info.spec.id = path->info.spec.id;
9876  new_spec->info.spec.range_var = parser_copy_tree (parser, path->info.spec.range_var);
9877  statement = mq_reset_ids_and_references (parser, statement, new_spec);
9878  new_spec->info.spec.id = (UINTPTR) new_spec;
9879  new_spec->info.spec.as_attr_list = new_spec->info.spec.referenced_attrs;
9880  new_spec->info.spec.referenced_attrs = NULL;
9881 
9882  query->info.query.q.select.from = path;
9884  temp = query->info.query.q.select.list = parser_copy_tree_list (parser, new_spec->info.spec.as_attr_list);
9885 
9886  for (; temp != NULL; temp = temp->next)
9887  {
9888  temp->info.name.spec_id = path->info.spec.id;
9889  }
9890 
9891  new_spec = parser_walk_tree (parser, new_spec, mq_set_virt_object, new_spec, NULL, NULL);
9892  statement = parser_walk_tree (parser, statement, mq_set_virt_object, new_spec, NULL, NULL);
9893 
9894  new_spec->info.spec.derived_table = query;
9895 
9896  for (new_spec->info.spec.path_entities = NULL; sub_paths; sub_paths = temp)
9897  {
9898  temp = sub_paths->next;
9899  sub_paths->next = NULL;
9900  new_sub_path = mq_derived_path (parser, statement, sub_paths);
9901  new_spec->info.spec.path_entities = parser_append_node (new_sub_path, new_spec->info.spec.path_entities);
9902  }
9903 
9904  return new_spec;
9905 }
9906 
9907 
9908 /*
9909  * mq_fetch_subqueries_for_update_local() - ask the schema manager for the
9910  * cached parser containing the compiled subqueries of the class_.
9911  * If that is not already cached, the schema manager will call back to
9912  * compute the subqueries
9913  * return:
9914  * parser(in):
9915  * class(in):
9916  * fetch_as(in):
9917  * what_for(in):
9918  * qry_cache(out):
9919  */
9920 static PT_NODE *
9922  PARSER_CONTEXT ** qry_cache)
9923 {
9924  PARSER_CONTEXT *query_cache;
9925  DB_OBJECT *class_object;
9926 
9927  if (!class_ || !(class_object = class_->info.name.db_object) || !qry_cache || db_is_class (class_object))
9928  {
9929  return NULL;
9930  }
9931 
9932  *qry_cache = query_cache = sm_virtual_queries (parser, class_object);
9933 
9934  if (query_cache && query_cache->view_cache)
9935  {
9936  if (!(query_cache->view_cache->authorization & what_for))
9937  {
9940  return NULL;
9941  }
9942  if (parser != NULL && query_cache->error_msgs != NULL)
9943  {
9944  mq_copy_view_error_msgs (parser, query_cache);
9945  }
9946 
9947  if (!query_cache->view_cache->vquery_for_update
9948  && (!query_cache->view_cache->vquery_for_partial_update || (fetch_as != PT_PARTIAL_SELECT)) && parser)
9949  {
9951  /* use function to get name. class_->info.name.original is not always set. */
9952  db_get_class_name (class_object));
9953  }
9954  if (fetch_as == PT_INVERTED_ASSIGNMENTS)
9955  {
9956  return query_cache->view_cache->inverted_vquery_for_update_in_gdb;
9957  }
9958  if (fetch_as == PT_NORMAL_SELECT)
9959  {
9960  return query_cache->view_cache->vquery_for_update_in_gdb;
9961  }
9962  if (fetch_as == PT_PARTIAL_SELECT)
9963  {
9964  if (query_cache->view_cache->vquery_for_update_in_gdb != NULL)
9965  {
9966  return query_cache->view_cache->vquery_for_update_in_gdb;
9967  }
9968  else
9969  {
9970  return query_cache->view_cache->vquery_for_partial_update;
9971  }
9972  }
9973  }
9974 
9975  return NULL;
9976 }
9977 
9978 /*
9979  * mq_fetch_subqueries_for_update() - just like ..._for_update_local except
9980  * it does not have an output argument for qry_cache
9981  * return:
9982  * parser(in):
9983  * class(in):
9984  * fetch_as(in):
9985  * what_for(in):
9986  */
9987 PT_NODE *
9989 {
9990  PARSER_CONTEXT *query_cache;
9991 
9992  return mq_fetch_subqueries_for_update_local (parser, class_, fetch_as, what_for, &query_cache);
9993 }
9994 
9995 /*
9996  * mq_fetch_select_for_real_class_update() - fetch the select statement that
9997  * maps the vclass to the real class
9998  * return:
9999  * parser(in):
10000  * vclass(in):
10001  * real_class(in):
10002  * fetch_as(in):
10003  * what_for(in):
10004  */
10005 static PT_NODE *
10007  PT_FETCH_AS fetch_as, DB_AUTH what_for)
10008 {
10009  PT_NODE *select_statements = mq_fetch_subqueries_for_update (parser, vclass, fetch_as, what_for);
10010  PT_NODE *flat;
10011  DB_OBJECT *class_object = NULL;
10012  int error = NO_ERROR;
10013  if (!select_statements)
10014  {
10015  return NULL;
10016  }
10017 
10018  if (real_class)
10019  {
10020  class_object = real_class->info.name.db_object;
10021  }
10022 
10023  while (select_statements)
10024  {
10025  if (select_statements->info.query.q.select.from)
10026  {
10027  for (flat = select_statements->info.query.q.select.from->info.spec.flat_entity_list; flat; flat = flat->next)
10028  {
10029  if (class_object == flat->info.name.db_object)
10030  {
10031  return select_statements;
10032  }
10033  }
10034 
10035  /* class_object might be either a superclass of one of the classes in flat_entity_list for queries selecting
10036  * from a class hierarchy: SELECT * FROM ALL t or a partition of one of the classes in the list: SELECT *
10037  * FROM t if t is a partitioned class. */
10038  for (flat = select_statements->info.query.q.select.from->info.spec.flat_entity_list; flat; flat = flat->next)
10039  {
10040  if (db_is_superclass (class_object, flat->info.name.db_object))
10041  {
10042  return select_statements;
10043  }
10044  else
10045  {
10046  error = db_is_partition (class_object, flat->info.name.db_object);
10047  if (error < 0)
10048  {
10049  PT_ERROR (parser, vclass, er_msg ());
10050  return NULL;
10051  }
10052  else if (error > 0)
10053  {
10054  return select_statements;
10055  }
10056  }
10057  }
10058  }
10059  select_statements = select_statements->next;
10060  }
10061 
10062  return NULL;
10063 }
10064 
10065 
10066 /*
10067  * mq_fetch_expression_for_real_class_update() - fetch the expression statement
10068  * that maps the vclass attribute to the real class
10069  * return:
10070  * parser(in):
10071  * vclass_obj(in):
10072  * attr(in):
10073  * real_class(in):
10074  * fetch_as(in):
10075  * what_for(in):
10076  * spec_id(out): entity spec id of the specification owning the expression
10077  */
10078 static PT_NODE *
10080  PT_NODE * real_class, PT_FETCH_AS fetch_as, DB_AUTH what_for,
10081  UINTPTR * spec_id)
10082 {
10083  PT_NODE vclass;
10084  PT_NODE *select_statement;
10085  PT_NODE *attr_list;
10086  PT_NODE *select_list;
10087  PT_NODE *spec;
10088  const char *attr_name;
10089 
10090  parser_init_node (&vclass, PT_NAME);
10091  vclass.info.name.original = NULL;
10092  vclass.info.name.db_object = vclass_obj;
10093 
10094  attr_list = mq_fetch_attributes (parser, &vclass);
10095 
10096  select_statement = mq_fetch_select_for_real_class_update (parser, &vclass, real_class, fetch_as, what_for);
10097 
10098  if (!select_statement)
10099  {
10100  if (!pt_has_error (parser))
10101  {
10102  const char *real_class_name = "<unknown>";
10103  if (real_class && real_class->info.name.original)
10104  {
10105  real_class_name = real_class->info.name.original;
10106  }
10107 
10109  db_get_class_name (vclass_obj), real_class_name);
10110  }
10111  return NULL;
10112  }
10113 
10114  if (spec_id)
10115  {
10116  *spec_id = 0;
10117  }
10118  if (!attr || !attr_list || !(select_list = select_statement->info.query.q.select.list)
10119  || !(attr_name = attr->info.name.original))
10120  {
10121  PT_INTERNAL_ERROR (parser, "translate");
10122  return NULL;
10123  }
10124 
10125  for (; attr_list && select_list; attr_list = attr_list->next, select_list = select_list->next)
10126  {
10127  if (intl_identifier_casecmp (attr_name, attr_list->info.name.original) == 0)
10128  {
10129  if (spec_id && (spec = select_statement->info.query.q.select.from))
10130  {
10131  *spec_id = spec->info.spec.id;
10132  }
10133  return select_list;
10134  }
10135  }
10136 
10137  if (!pt_has_error (parser))
10138  {
10140  db_get_class_name (vclass_obj), attr_name);
10141  }
10142 
10143  return NULL;
10144 }
10145 
10146 /*
10147  * mq_fetch_attributes() - fetch class's subqueries
10148  * return: PT_NODE list of its attribute names, including oid attr
10149  * parser(in):
10150  * class(in):
10151  */
10152 PT_NODE *
10154 {
10155  PARSER_CONTEXT *query_cache;
10156  DB_OBJECT *class_object;
10157 
10158  if (!class_ || !(class_object = class_->info.name.db_object) || db_is_class (class_object))
10159  {
10160  return NULL;
10161  }
10162 
10163  query_cache = sm_virtual_queries (parser, class_object);
10164 
10165  if (query_cache)
10166  {
10167  if (parser != NULL && query_cache->error_msgs != NULL)
10168  {
10169  mq_copy_view_error_msgs (parser, query_cache);
10170  }
10171 
10172  if (query_cache->view_cache)
10173  {
10174  return query_cache->view_cache->attrs;
10175  }
10176  }
10177 
10178  return NULL;
10179 }
10180 
10181 /*
10182  * NAME: mq_set_names_dbobject
10183  *
10184  * This private routine re-sets PT_NAME node resolution to match
10185  * a new printable name (usually, used to resolve ambiguity)
10186  *
10187  * returns: PT_NODE
10188  *
10189  * side effects: none
10190  *
10191  */
10192 
10193 /*
10194  * mq_set_names_dbobject() - re-sets PT_NAME node resolution to match a new
10195  * printable name
10196  * return:
10197  * parser(in):
10198  * node(in):
10199  * void_arg(in):
10200  * continue_walk(in/out):
10201  */
10202 static PT_NODE *
10203 mq_set_names_dbobject (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
10204 {
10205  SET_NAMES_INFO *info = (SET_NAMES_INFO *) void_arg;
10206 
10207  if (node->node_type == PT_NAME && node->info.name.meta_class != PT_PARAMETER && node->info.name.spec_id == info->id)
10208  {
10209  node->info.name.db_object = info->object;
10210 
10211  /* don't walk entity_name_list/flat_entity_spec do walk list especially for method args list for example: set a =
10212  * func(x, y, z) <-- walk into y, z */
10213  *continue_walk = PT_LIST_WALK;
10214  }
10215  if (node->node_type == PT_DATA_TYPE || node->node_type == PT_SPEC)
10216  {
10217  *continue_walk = PT_STOP_WALK;
10218  }
10219 
10220  return node;
10221 }
10222 
10223 /*
10224  * mq_is_updatable_local() - checks if vclass is updatable
10225  * return: 0 if not, 1 if so
10226  * class_object(in):
10227  * fetch_as(in): fetch mode
10228  */
10229 static bool
10230 mq_is_updatable_local (DB_OBJECT * class_object, PT_FETCH_AS fetch_as)
10231 {
10232  PT_NODE class_;
10233  PT_NODE *subquery;
10235 
10236  parser = parser_create_parser ();
10237  if (parser == NULL)
10238  {
10239  return false;
10240  }
10241 
10242  parser_init_node (&class_, PT_NAME);
10243  class_.info.name.original = NULL;
10244  class_.info.name.db_object = class_object;
10245 
10246  subquery = mq_fetch_subqueries_for_update (parser, &class_, fetch_as, DB_AUTH_SELECT);
10247  /* clean up memory */
10248  parser_free_parser (parser);
10249 
10250  return (subquery != NULL);
10251 }
10252 
10253 /*
10254  * mq_is_updatable() - checks if vclass is at least partially updatable
10255  * return: 0 if not, 1 if so
10256  * class_object(in):
10257  */
10258 bool
10259 mq_is_updatable (DB_OBJECT * class_object)
10260 {
10261  return mq_is_updatable_local (class_object, PT_PARTIAL_SELECT);
10262 }
10263 
10264 /*
10265  * mq_is_updatable_strict() - checks if vclass is strictly updatable
10266  * return: 0 if not, 1 if so
10267  * class_object(in):
10268  */
10269 bool
10271 {
10272  return mq_is_updatable_local (class_object, PT_NORMAL_SELECT);
10273 }
10274 
10275 /*
10276  * mq_is_updatable_att() -
10277  * return: true if vmop's att_nam is updatable
10278  * parser(in): the parser context
10279  * vmop(in): vclass object
10280  * att_nam(in): one of vmop's attribute names
10281  * rmop(in): real (base) class object
10282  */
10283 bool
10284 mq_is_updatable_att (PARSER_CONTEXT * parser, DB_OBJECT * vmop, const char *att_nam, DB_OBJECT * rmop)
10285 {
10286  PT_NODE real, attr, *expr;
10287 
10288  parser_init_node (&attr, PT_NAME);
10289  attr.info.name.original = att_nam;
10290 
10291  parser_init_node (&real, PT_NAME);
10292  real.info.name.original = NULL;
10293  real.info.name.db_object = rmop;
10294 
10295  expr =
10297  NULL);
10298  if (!expr)
10299  {
10300  return false;
10301  }
10302 
10303  return expr->info.expr.arg1 && expr->info.expr.arg2;
10304 }
10305 
10306 /*
10307  * mq_is_updatable_attribute() -
10308  * return: false if not, true if so
10309  * vclass_object(in):
10310  * attr_name(in):
10311  * real_class_object(in):
10312  */
10313 bool
10314 mq_is_updatable_attribute (DB_OBJECT * vclass_object, const char *attr_name, DB_OBJECT * real_class_object)
10315 {
10317  bool rc;
10318 
10319  parser = parser_create_parser ();
10320  if (parser == NULL)
10321  {
10322  return false;
10323  }
10324 
10325  rc = mq_is_updatable_att (parser, vclass_object, attr_name, real_class_object);
10326 
10327  parser_free_parser (parser);
10328  return rc;
10329 }
10330 
10331 /*
10332  * mq_evaluate_expression() -
10333  * return: the evaluated expression value, or error
10334  * parser(in):
10335  * expr(in):
10336  * value(in):
10337  * object(in): an object to db_get all names from
10338  * spec_id(in):
10339  */
10340 int
10341 mq_evaluate_expression (PARSER_CONTEXT * parser, PT_NODE * expr, DB_VALUE * value, DB_OBJECT * object, UINTPTR spec_id)
10342 {
10343  int error = NO_ERROR;
10344  SET_NAMES_INFO info;
10345 
10346  info.object = object;
10347  info.id = spec_id;
10348  if (expr)
10349  {
10351 
10352  pt_evaluate_tree (parser, expr, value, 1);
10353  if (pt_has_error (parser))
10354  {
10355  error = PT_SEMANTIC;
10356  pt_report_to_ersys (parser, (PT_ERROR_TYPE) error);
10357  }
10358  }
10359  else
10360  {
10361  PT_NODE dummy;
10362  dummy.line_number = 0;
10363  dummy.column_number = 0;
10365  }
10366 
10367  if (pt_has_error (parser))
10368  {
10369  error = ER_PT_SEMANTIC;
10370  pt_report_to_ersys (parser, PT_SEMANTIC);
10371  }
10372 
10373  return error;
10374 }
10375 
10376 /*
10377  * mq_evaluate_expression_having_serial() -
10378  * return:
10379  * parser(in):
10380  * expr(in):
10381  * value(in):
10382  * vals_cnt(in): number of values to return in 'value' parameter
10383  * object(in):
10384  * spec_id(in):
10385  */
10386 int
10387 mq_evaluate_expression_having_serial (PARSER_CONTEXT * parser, PT_NODE * expr, DB_VALUE * values, int values_count,
10388  DB_OBJECT * object, UINTPTR spec_id)
10389 {
10390  int error = NO_ERROR;
10391  SET_NAMES_INFO info;
10392 
10393  info.object = object;
10394  info.id = spec_id;
10395  if (expr)
10396  {
10398 
10399  pt_evaluate_tree_having_serial (parser, expr, values, values_count);
10400  if (pt_has_error (parser))
10401  {
10402  error = PT_SEMANTIC;
10403  pt_report_to_ersys (parser, (PT_ERROR_TYPE) error);
10404  }
10405  }
10406  else
10407  {
10408  PT_NODE dummy;
10409  dummy.line_number = 0;
10410  dummy.column_number = 0;
10412  }
10413 
10414  if (pt_has_error (parser))
10415  {
10416  error = ER_PT_SEMANTIC;
10417  pt_report_to_ersys (parser, PT_SEMANTIC);
10418  }
10419 
10420  return error;
10421 }
10422 
10423 /*
10424  * mq_get_attribute() -
10425  * return: NO_ERROR on success, non-zero for ERROR
10426  * vclass_object(in): the "mop" of the virtual instance's vclass
10427  * attr_name(in): the attribute of the virtual instance to updat
10428  * real_class_object(in): the "mop" of the virtual instance's real class
10429  * virtual_value(out): the value gotten from the virtual instance
10430  * real_instance(out): contains real instance of virtual instance
10431  */
10432 int
10433 mq_get_attribute (DB_OBJECT * vclass_object, const char *attr_name, DB_OBJECT * real_class_object,
10434  DB_VALUE * virtual_value, DB_OBJECT * real_instance)
10435 {
10436  PT_NODE real;
10437  PT_NODE attr;
10438  PARSER_CONTEXT *parser = NULL;
10439  PT_NODE *expr;
10440  int error = NO_ERROR;
10441  UINTPTR spec_id;
10442  int save;
10443 
10444  AU_DISABLE (save);
10445 
10446  if (parser == NULL)
10447  {
10448  parser = parser_create_parser ();
10449  if (parser == NULL)
10450  {
10451  AU_ENABLE (save);
10452 
10453  assert (er_errid () != NO_ERROR);
10454  return er_errid ();
10455  }
10456  }
10457 
10458 
10459  parser->au_save = save;
10460 
10461  parser_init_node (&attr, PT_NAME);
10462  attr.info.name.original = attr_name;
10463 
10464  parser_init_node (&real, PT_NAME);
10465  real.info.name.original = NULL;
10466  real.info.name.db_object = real_class_object;
10467 
10468  expr =
10469  mq_fetch_expression_for_real_class_update (parser, vclass_object, &attr, &real, PT_NORMAL_SELECT, DB_AUTH_SELECT,
10470  &spec_id);
10471 
10472  if (pt_has_error (parser))
10473  {
10474  error = ER_PT_SEMANTIC;
10475  pt_report_to_ersys (parser, PT_SEMANTIC);
10476  }
10477  else
10478  {
10479  error = mq_evaluate_expression (parser, expr, virtual_value, real_instance, spec_id);
10480  }
10481 
10482  parser_free_parser (parser);
10483 
10484  AU_ENABLE (save);
10485 
10486  return error;
10487 }
10488 
10489 
10490 /*
10491  * mq_oid() -
10492  * return:
10493  * parser(in): the usual context
10494  * spec(in):
10495  */
10496 PT_NODE *
10498 {
10499  PT_NODE *real;
10500  PT_NODE attr;
10501  PT_NODE *expr;
10502  PT_NODE *error_msgs = parser->error_msgs;
10503  int save;
10504  DB_OBJECT *virt_class;
10505 
10506  /* DO NOT RETURN FROM WITHIN THE BODY OF THIS PROCEDURE */
10507  AU_DISABLE (save);
10508  parser->au_save = save;
10509 
10510  parser_init_node (&attr, PT_NAME);
10511  attr.info.name.original = ""; /* oid's have null string attr name */
10512 
10513  real = spec->info.spec.flat_entity_list;
10514  virt_class = real->info.name.virt_object;
10515 
10516  parser->error_msgs = NULL;
10517 
10518  expr =
10519  mq_fetch_expression_for_real_class_update (parser, virt_class, &attr, real, PT_NORMAL_SELECT, DB_AUTH_ALL, NULL);
10520 
10521  /* in case it was NOT updatable just return NULL, no error */
10522  parser_free_tree (parser, parser->error_msgs);
10523  parser->error_msgs = error_msgs;
10524 
10525  expr = parser_copy_tree (parser, expr);
10526 
10527  expr = parser_walk_tree (parser, expr, mq_set_all_ids, spec, NULL, NULL);
10528 
10529  AU_ENABLE (save);
10530 
10531  return expr;
10532 }
10533 
10534 /*
10535  * mq_update_attribute -
10536  * return: NO_ERROR on success, non-zero for ERROR
10537  * vclass_object(in): the "mop" of the virtual instance's vclass
10538  * attr_name(in): the attribute of the virtual instance to update
10539  * real_class_object(in): the "mop" of the virtual instance's real class
10540  * virtual_value(in): the value to put in the virtual instance
10541  * real_value(out): contains value to set it to
10542  * real_name(out): contains name of real instance attribute to set
10543  * db_auth(in):
10544  */
10545 int
10546 mq_update_attribute (DB_OBJECT * vclass_object, const char *attr_name, DB_OBJECT * real_class_object,
10547  DB_VALUE * virtual_value, DB_VALUE * real_value, const char **real_name, int db_auth)
10548 {
10549  PT_NODE real;
10550  PT_NODE attr;
10551  /* static */ PARSER_CONTEXT *parser = NULL;
10552  PT_NODE *value_holder;
10553  PT_NODE *expr;
10554  PT_NODE *value;
10555  int error = NO_ERROR;
10556  if (parser == NULL)
10557  {
10558  parser = parser_create_parser ();
10559  if (parser == NULL)
10560  {
10561  assert (er_errid () != NO_ERROR);
10562  return er_errid ();
10563  }
10564  }
10565 
10566  parser_init_node (&attr, PT_NAME);
10567  attr.info.name.original = attr_name;
10568 
10569  parser_init_node (&real, PT_NAME);
10570  real.info.name.original = NULL;
10571  real.info.name.db_object = real_class_object;
10572 
10573  expr =
10574  mq_fetch_expression_for_real_class_update (parser, vclass_object, &attr, &real, PT_INVERTED_ASSIGNMENTS,
10575  (DB_AUTH) db_auth, NULL);
10576 
10577  if (!expr /* SM_NOT_UPDATBLE_ATTRIBUTE */
10578  || !expr->info.expr.arg1 || !expr->info.expr.arg2 || !expr->etc)
10579  {
10580  error = ER_GENERIC_ERROR;
10581  }
10582 
10583  if (error == NO_ERROR && virtual_value != NULL)
10584  {
10585  (*real_name) = expr->info.expr.arg1->info.name.original;
10586  value_holder = (PT_NODE *) expr->etc;
10587  value = pt_dbval_to_value (parser, virtual_value);
10588 
10589  if (value)
10590  {
10591  value_holder->info.value.data_value = value->info.value.data_value;
10592  value_holder->info.value.db_value = *virtual_value;
10593  value_holder->info.value.db_value_is_initialized = true;
10594  pt_evaluate_tree (parser, expr->info.expr.arg2, real_value, 1);
10595  parser_free_tree (parser, value);
10596  db_make_null (&value_holder->info.value.db_value);
10597  value_holder->info.value.db_value_is_initialized = false;
10598  /*
10599  * This is a bit of a kludge since there is no way to clean up
10600  * the data_value portion of the info structure. The value_holder
10601  * node now points into the parse tree, but has been allocated by
10602  * a different parser (mq_fetch_expression_for_real_class_update).
10603  * We need to set this pointer to NULL so we won't try to free
10604  * it when cleaning up the parse tree. Setting the "set" pointer
10605  * should be safe for the union.
10606  */
10607  value_holder->info.value.data_value.set = NULL;
10608  }
10609  }
10610  else if (!pt_has_error (parser))
10611  {
10612  PT_INTERNAL_ERROR (parser, "translate");
10613  }
10614 
10615  if (pt_has_error (parser))
10616  {
10617  error = ER_PT_SEMANTIC;
10618  pt_report_to_ersys (parser, PT_SEMANTIC);
10619  }
10620 
10621  /* clean up memory */
10622 
10623  parser_free_parser (parser);
10624 
10625  return error;
10626 }
10627 
10628 /*
10629  * mq_fetch_one_real_class_get_cache() -
10630  * return: a convienient real class DB_OBJECT* of an updatable virtual class
10631  * NULL for non-updatable
10632  * vclass_object(in): the "mop" of the virtual class
10633  * query_cache(out): parser holding cached parse trees
10634  */
10635 static PT_NODE *
10637 {
10638  PARSER_CONTEXT *parser = NULL;
10639  PT_NODE vclass;
10640  PT_NODE *subquery, *flat = NULL;
10641 
10642  if (parser == NULL)
10643  {
10644  parser = parser_create_parser ();
10645  if (parser == NULL)
10646  {
10647  return NULL;
10648  }
10649  }
10650 
10651  parser_init_node (&vclass, PT_NAME);
10652  vclass.info.name.original = NULL;
10653  vclass.info.name.db_object = vclass_object;
10654 
10655  subquery = mq_fetch_subqueries_for_update_local (parser, &vclass, PT_NORMAL_SELECT, DB_AUTH_SELECT, query_cache);
10656 
10657  if (subquery && subquery->info.query.q.select.from)
10658  {
10659  flat = subquery->info.query.q.select.from->info.spec.flat_entity_list;
10660  }
10661 
10662  if (flat == NULL && !pt_has_error (parser))
10663  {
10664  PT_NODE dummy;
10665  dummy.line_number = 0;
10666  dummy.column_number = 0;
10668  db_get_class_name (vclass_object));
10669  }
10670 
10671  if (pt_has_error (parser))
10672  {
10673  pt_report_to_ersys (parser, PT_SEMANTIC);
10674  }
10675  /* clean up memory */
10676 
10677  parser_free_parser (parser);
10678 
10679  return flat;
10680 }
10681 
10682 /*
10683  * mq_fetch_one_real_class() -
10684  * return: a convienient real class DB_OBJECT* of an updatable virtual class
10685  * NULL for non-updatable
10686  * vclass_object(in): the "mop" of the virtual class
10687  */
10688 DB_OBJECT *
10690 {
10691  PARSER_CONTEXT *query_cache;
10692  PT_NODE *flat;
10693  flat = mq_fetch_one_real_class_get_cache (vclass_object, &query_cache);
10694  if (flat)
10695  {
10696  return flat->info.name.db_object;
10697  }
10698  return NULL;
10699 }
10700 
10701 
10702 /*
10703  * mq_get_expression() -
10704  * return: NO_ERROR on success, non-zero for ERROR
10705  * object(in): an object to db_get all names from
10706  * expr(in): expression tree
10707  * value(in/out): the evaluated expression value
10708  */
10709 int
10710 mq_get_expression (DB_OBJECT * object, const char *expr, DB_VALUE * value)
10711 {
10712  PARSER_CONTEXT *parser = NULL;
10713  int error = NO_ERROR;
10714  PT_NODE **statements;
10715  PT_NODE *statement = NULL;
10716  char *buffer;
10717 
10718  if (parser == NULL)
10719  {
10720  parser = parser_create_parser ();
10721  if (parser == NULL)
10722  {
10723  assert (er_errid () != NO_ERROR);
10724  return er_errid ();
10725  }
10726  }
10727 
10728  buffer = pt_append_string (parser, NULL, "select ");
10729  buffer = pt_append_string (parser, buffer, expr);
10730  buffer = pt_append_string (parser, buffer, " from ");
10731  buffer = pt_append_string (parser, buffer, db_get_class_name (object));
10732 
10733  statements = parser_parse_string_with_escapes (parser, buffer, false);
10734 
10735  if (statements)
10736  {
10737  /* exclude from auditing statement */
10738  statement = statements[0];
10739  statement = pt_compile (parser, statement);
10740  }
10741 
10742  if (statement && !pt_has_error (parser))
10743  {
10744  error =
10745  mq_evaluate_expression (parser, statement->info.query.q.select.list, value, object,
10746  statement->info.query.q.select.from->info.spec.id);
10747  }
10748  else
10749  {
10750  error = ER_PT_SEMANTIC;
10751  pt_report_to_ersys (parser, PT_SEMANTIC);
10752  }
10753 
10754  /* clean up memory */
10755 
10756  parser_free_parser (parser);
10757 
10758  return error;
10759 }
10760 
10761 #if defined(ENABLE_UNUSED_FUNCTION)
10762 /*
10763  * mq_mget_exprs() - bulk db_get_expression of a list of attribute exprs
10764  * for a given set of instances of a class
10765  * return: number of rows evaluated if all OK, -1 otherwise
10766  * objects(in): an array of object instances of a class
10767  * rows(in): number of instances in objects array
10768  * exprs(in): an array of attribute expressions
10769  * cols(in): number of items in exprs array
10770  * qOnErr(in): true if caller wants us to quit on first error
10771  * values(out): destination db_values for attribute expressions
10772  * results(out): array of result codes
10773  * emsg(out): a diagnostic message if an error occurred
10774  */
10775 static int
10776 mq_mget_exprs (DB_OBJECT ** objects, int rows, char **exprs, int cols, int qOnErr, DB_VALUE * values, int *results,
10777  char *emsg)
10778 {
10779  char *buffer;
10780  DB_ATTDESC **attdesc;
10781  int c, count, err = NO_ERROR, r;
10782  DB_OBJECT *cls;
10783  DB_VALUE *v;
10784  UINTPTR specid;
10785  int siz;
10786  PT_NODE **stmts, *stmt = NULL, *xpr;
10788 
10789  /* make sure we have reasonable arguments */
10790  if (!objects || !(*objects) || (cls = db_get_class (*objects)) == NULL || !exprs || !values || rows <= 0 || cols <= 0)
10791  {
10792  strcpy (emsg, "invalid argument(s) to mq_mget_exprs");
10793  return -1; /* failure */
10794  }
10795 
10796  /* create a new parser context */
10797  parser = parser_create_parser ();
10798  if (parser == NULL)
10799  {
10800  return -1;
10801  }
10802 
10803  emsg[0] = 0;
10804 
10805  /* compose a "select exprs from target_class" */
10806  buffer = pt_append_string (parser, NULL, "select ");
10807  buffer = pt_append_string (parser, buffer, exprs[0]);
10808  for (c = 1; c < cols; c++)
10809  {
10810  buffer = pt_append_string (parser, buffer, ",");
10811  buffer = pt_append_string (parser, buffer, exprs[c]);
10812  }
10813  buffer = pt_append_string (parser, buffer, " from ");
10814  buffer = pt_append_string (parser, buffer, db_get_class_name (cls));
10815 
10816  /* compile it */
10817  stmts = parser_parse_string (parser, buffer);
10818  if (stmts)
10819  {
10820  /* exclude from auditing statement */
10821  stmt = stmts[0];
10822  stmt = pt_compile (parser, stmt);
10823  }
10824 
10825  if (stmt == NULL || pt_has_error (parser))
10826  {
10827  err = ER_PT_SEMANTIC;
10828  pt_report_to_ersys (parser, PT_SEMANTIC);
10829  count = -1; /* failure */
10830  for (r = 0; r < rows; r++)
10831  {
10832  results[r] = 0;
10833  }
10834  }
10835  else
10836  {
10837  /* partition attribute expressions into names and expressions: simple names will be evaluated via db_dget (fast)
10838  * and expressions will be evaluated via mq_evaluate_expression (slow). */
10839  siz = cols * sizeof (DB_ATTDESC *);
10840  attdesc = (DB_ATTDESC **) parser_alloc (parser, siz);
10841  for (c = 0, xpr = stmt->info.query.q.select.list; c < cols && xpr && (err == NO_ERROR || !qOnErr);
10842  c++, xpr = xpr->next)
10843  {
10844  /* get attribute descriptors for simple names */
10845  if (xpr->node_type == PT_NAME)
10846  {
10847  err = db_get_attribute_descriptor (cls, xpr->info.name.original, 0, 0, &attdesc[c]);
10848  }
10849  }
10850  if (!attdesc || err != NO_ERROR)
10851  {
10852  strcpy (emsg, "mq_mget_exprs fails in getting attribute descriptors");
10853  count = -1; /* failure */
10854  for (r = 0; r < rows; r++)
10855  {
10856  results[r] = 0;
10857  }
10858  }
10859  else
10860  {
10861  /* evaluate attribute expressions and deposit results into values */
10862  count = 0;
10863  specid = stmt->info.query.q.select.from->info.spec.id;
10864  for (r = 0, v = values; r < rows && (err == NO_ERROR || !qOnErr); r++, v = values + (r * cols))
10865  {
10866  for (c = 0, xpr = stmt->info.query.q.select.list; c < cols && xpr && (err == NO_ERROR || !qOnErr);
10867  c++, v++, xpr = xpr->next)
10868  {
10869  /* evaluate using the faster db_dget for simple names and the slower mq_evaluate_expression for
10870  * expressions. */
10871  err =
10872  xpr->node_type == PT_NAME ? db_dget (objects[r], attdesc[c], v) : mq_evaluate_expression (parser,
10873  xpr, v,
10874  objects
10875  [r],
10876  specid);
10877  }
10878  if (err != NO_ERROR)
10879  {
10880  results[r] = 0;
10881  }
10882  else
10883  {
10884  count++;
10885  results[r] = 1;
10886  }
10887  }
10888  }
10889  }
10890  /* deposit any error message into emsg */
10891  if (err != NO_ERROR && !strlen (emsg))
10892  {
10893  strcpy (emsg, db_error_string (3));
10894  }
10895 
10896  /* clean up memory */
10897  parser_free_parser (parser);
10898 
10899  return count;
10900 }
10901 #endif /* ENABLE_UNUSED_FUNCTION */
10902 
10903 /*
10904  * mq_is_real_class_of_vclass() - determine if s_class is one of the real
10905  * classes of the virtual class d_class
10906  * return: 1 if s_class is a real class of the view d_class
10907  * parser(in): the parser context
10908  * s_class(in): a PT_NAME node representing a class_, vclass
10909  * d_class(in): a PT_NAME node representing a view
10910  */
10911 int
10912 mq_is_real_class_of_vclass (PARSER_CONTEXT * parser, const PT_NODE * s_class, const PT_NODE * d_class)
10913 {
10914  PT_NODE *saved_msgs;
10915  int result;
10916 
10917  if (!parser)
10918  {
10919  return 0;
10920  }
10921 
10922  saved_msgs = parser->error_msgs;
10923  parser->error_msgs = NULL;
10924 
10925  result = (mq_fetch_select_for_real_class_update (parser, (PT_NODE *) d_class, (PT_NODE *) s_class, PT_NORMAL_SELECT,
10926  DB_AUTH_SELECT) != NULL);
10927  if (pt_has_error (parser))
10928  {
10929  parser_free_tree (parser, parser->error_msgs);
10930  }
10931 
10932  parser->error_msgs = saved_msgs;
10933  return result;
10934 }
10935 
10936 
10937 /*
10938  * mq_evaluate_check_option() -
10939  * return: NO_ERROR on success, non-zero for ERROR
10940  * parser(in):
10941  * check_where(in):
10942  * object(in): an object to db_get all names from
10943  * view_class(in):
10944  */
10945 int
10946 mq_evaluate_check_option (PARSER_CONTEXT * parser, PT_NODE * check_where, DB_OBJECT * object, PT_NODE * view_class)
10947 {
10948  DB_VALUE bool_val;
10949  int error;
10950 
10951  db_make_null (&bool_val);
10952 
10953  /* evaluate check option */
10954  if (check_where != NULL)
10955  {
10956  for (; check_where != NULL; check_where = check_where->next)
10957  {
10958  error = mq_evaluate_expression (parser, check_where, &bool_val, object, view_class->info.name.spec_id);
10959  if (error < 0)
10960  {
10961  return error;
10962  }
10963 
10964  if (db_value_is_null (&bool_val) || db_get_int (&bool_val) == 0)
10965  {
10967  view_class->info.name.virt_object ? db_get_class_name (view_class->info.name.virt_object) : ""
10968  /* an internal error */ );
10969 
10970  /* Report check option error to sys error. */
10971  pt_report_to_ersys (parser, PT_EXECUTION);
10972  return er_errid ();
10973  }
10974  }
10975  }
10976 
10977  return NO_ERROR;
10978 }
10979 
10980 
10981 static const char *
10983 {
10984  switch (auth)
10985  {
10986  case DB_AUTH_NONE:
10987  return "";
10988 
10989  case DB_AUTH_SELECT:
10990  return "SELECT";
10991 
10992  case DB_AUTH_INSERT:
10993  return "INSERT";
10994 
10995  case DB_AUTH_UPDATE:
10996  return "UPDATE";
10997 
10998  case DB_AUTH_DELETE:
10999  return "DELETE";
11000 
11001  case DB_AUTH_ALTER:
11002  return "ALTER";
11003 
11004  case DB_AUTH_INDEX:
11005  return "INDEX";
11006 
11007  case DB_AUTH_EXECUTE:
11008  return "EXECUTE";
11009 
11010  case DB_AUTH_REPLACE:
11011  return "REPLACE";
11012 
11013  case DB_AUTH_INSERT_UPDATE:
11014  return "INSERT/UPDATE";
11015 
11016  case DB_AUTH_UPDATE_DELETE:
11017  return "UPDATE/DELETE";
11018 
11020  return "INSERT/UPDATE/DELETE";
11021 
11022  default:
11023  return "";
11024  }
11025 }
11026 
11027 /*
11028  * mq_is_order_dependent_node - determine if node's evaluation result depends
11029  * on tuple order
11030  * return: true if result is dependent of order, false otherwise
11031  * node(in): node to check
11032  *
11033  * NOTE: a node is said to be order dependent if at least one of it's descendant
11034  * nodes is a session variable assignment (eg. @a := expr).
11035  */
11036 static bool
11038 {
11039  bool res = false;
11040 
11041  if (node == NULL)
11042  {
11043  return false;
11044  }
11045 
11046  /* check expression node */
11047  if (PT_IS_EXPR_NODE (node))
11048  {
11049  if (node->info.expr.op == PT_DEFINE_VARIABLE)
11050  {
11051  /* we found an assignment, no need to look further */
11052  return true;
11053  }
11054 
11055  /* recurse arguments */
11056  if (node->info.expr.arg1 != NULL)
11057  {
11058  res = mq_is_order_dependent_node (node->info.expr.arg1) || res;
11059  }
11060 
11061  if (node->info.expr.arg2 != NULL)
11062  {
11063  res = mq_is_order_dependent_node (node->info.expr.arg2) || res;
11064  }
11065 
11066  if (node->info.expr.arg3 != NULL)
11067  {
11068  res = mq_is_order_dependent_node (node->info.expr.arg3) || res;
11069  }
11070  }
11071 
11072  /* check function node */
11073  if (PT_IS_FUNCTION (node))
11074  {
11075  PT_NODE *arg = node->info.function.arg_list;
11076 
11077  /* recurse arguments */
11078  while (arg != NULL)
11079  {
11080  res = mq_is_order_dependent_node (arg) || res;
11081 
11082  arg = arg->next;
11083  }
11084  }
11085 
11086  return res;
11087 }
11088 
11089 /*
11090  * mq_mark_order_dependent_nodes - in an order dependent node tree, mark nodes
11091  * that are order dependent
11092  * returns: true if node or one of it's children were marked as order
11093  * dependent, false otherwise
11094  *
11095  * NOTE: this function is called recursively. it will mark session variable
11096  * nodes and all their ancestors up to the root.
11097  */
11098 static bool
11100 {
11101  bool res = false;
11102 
11103  if (node == NULL)
11104  {
11105  return false;
11106  }
11107 
11108  /* check expression */
11109  if (PT_IS_EXPR_NODE (node))
11110  {
11111  if (node->info.expr.op == PT_DEFINE_VARIABLE || node->info.expr.op == PT_EVALUATE_VARIABLE)
11112  {
11113  /* session variable found */
11114  res = true;
11115  }
11116 
11117  /* recurse arguments */
11118  if (node->info.expr.arg1 != NULL)
11119  {
11120  res = mq_mark_order_dependent_nodes (node->info.expr.arg1) || res;
11121  }
11122 
11123  if (node->info.expr.arg2 != NULL)
11124  {
11125  res = mq_mark_order_dependent_nodes (node->info.expr.arg2) || res;
11126  }
11127 
11128  if (node->info.expr.arg3 != NULL)
11129  {
11130  res = mq_mark_order_dependent_nodes (node->info.expr.arg3) || res;
11131  }
11132  }
11133 
11134  /* check functions */
11135  if (PT_IS_FUNCTION (node))
11136  {
11137  PT_NODE *arg = node->info.function.arg_list;
11138 
11139  /* recurse arguments */
11140  while (arg != NULL)
11141  {
11142  res = mq_mark_order_dependent_nodes (arg) || res;
11143 
11144  arg = arg->next;
11145  }
11146  }
11147 
11148  /* set flag */
11149  PT_SET_ORDER_DEPENDENT_FLAG (node, res);
11150 
11151  return res;
11152 }
11153 
11154 /*
11155  * mq_rewrite_order_dependent_nodes - rewrite order dependent nodes in a tree
11156  * returns: rewritten node or tree
11157  * parser(in): parser context
11158  * node(in): node to rewrite
11159  * select(in): parent SELECT query
11160  * unique(in/out): pointer to an int counter, used for unique name generation
11161  *
11162  * NOTE: this function will take all order independent subtrees and add them to
11163  * the derived table select list, thus making sure the expressions are
11164  * evaluated in the correct context.
11165  */
11166 static PT_NODE *
11167 mq_rewrite_order_dependent_nodes (PARSER_CONTEXT * parser, PT_NODE * node, PT_NODE * select, int *unique)
11168 {
11169  PT_NODE *attr = NULL, *as_attr = NULL;
11170  PT_NODE *spec = NULL, *dt_query = NULL;
11171  char *name = NULL;
11172  PT_NODE *pt_cur = NULL;
11173 
11174  if (node == NULL || select == NULL)
11175  {
11176  /* nothing to do */
11177  return node;
11178  }
11179 
11180  if (select->node_type != PT_SELECT)
11181  {
11182  PT_INTERNAL_ERROR (parser, "invalid parent query");
11183  return NULL;
11184  }
11185 
11186  /* retrieve derived table spec */
11187  spec = select->info.query.q.select.from;
11188  if (spec == NULL || spec->info.spec.range_var == NULL)
11189  {
11190  PT_INTERNAL_ERROR (parser, "invalid spec");
11191  return NULL;
11192  }
11193 
11194  /* retrieve derived table query */
11195  dt_query = spec->info.spec.derived_table;
11196  if (dt_query == NULL || dt_query->node_type != PT_SELECT)
11197  {
11198  PT_INTERNAL_ERROR (parser, "invalid derived table");
11199  return NULL;
11200  }
11201 
11202  if (PT_IS_ORDER_DEPENDENT (node))
11203  {
11204  /* node is order dependent */
11205  if (PT_IS_EXPR_NODE (node))
11206  {
11207  /* walk expression arguments */
11208  if (node->info.expr.arg1 != NULL)
11209  {
11210  node->info.expr.arg1 = mq_rewrite_order_dependent_nodes (parser, node->info.expr.arg1, select, unique);
11211  }
11212 
11213  if (node->info.expr.arg2 != NULL)
11214  {
11215  node->info.expr.arg2 = mq_rewrite_order_dependent_nodes (parser, node->info.expr.arg2, select, unique);
11216  }
11217 
11218  if (node->info.expr.arg3 != NULL)
11219  {
11220  node->info.expr.arg3 = mq_rewrite_order_dependent_nodes (parser, node->info.expr.arg3, select, unique);
11221  }
11222  }
11223  else if (PT_IS_FUNCTION (node))
11224  {
11225  PT_NODE *list = node->info.function.arg_list;
11226  PT_NODE *saved_next = NULL, *prev = NULL, *ret_node;
11227 
11228  /* walk function arguments */
11229  while (list != NULL)
11230  {
11231  /* unlink */
11232  saved_next = list->next;
11233  list->next = NULL;
11234 
11235  /* rewrite tree */
11236  ret_node = mq_rewrite_order_dependent_nodes (parser, list, select, unique);
11237 
11238  if (ret_node == NULL)
11239  {
11240  if (!pt_has_error (parser))
11241  {
11242  /* error should have been set, but making sure */
11243  PT_INTERNAL_ERROR (parser, "node rewrite failed");
11244  }
11245  return NULL;
11246  }
11247 
11248  /* relink */
11249  ret_node->next = saved_next;
11250  if (prev != NULL)
11251  {
11252  prev->next = ret_node;
11253  }
11254 
11255  /* advance */
11256  prev = ret_node;
11257  list = list->next;
11258  }
11259  }
11260 
11261  /* done */
11262  return node;
11263  }
11264 
11265  /* we now have an order independent node */
11266 
11267  if (node->node_type == PT_VALUE)
11268  {
11269  /* ignore values, no need to move them around */
11270  return node;
11271  }
11272 
11273  /* check if the node is in the subquey's select_list. */
11274  if (node->node_type == PT_NAME)
11275  {
11276  for (pt_cur = dt_query->info.query.q.select.list; pt_cur != NULL; pt_cur = pt_cur->next)
11277  {
11278  if (pt_cur->node_type == PT_NAME && pt_name_equal (parser, pt_cur, node) == true)
11279  {
11280  /* the node is in subquery's select_list! Just use it. */
11281  node->info.name.meta_class = PT_MISC_NONE;
11283  node->info.name.spec_id = spec->info.spec.id;
11284  node->type_enum = pt_cur->type_enum;
11285  node->data_type = parser_copy_tree (parser, pt_cur->data_type);
11286  node->etc = pt_cur->etc;
11287 
11288  /* Whatever it was, now it is visible. */
11289  pt_cur->flag.is_hidden_column = 0;
11290  return node;
11291  }
11292  }
11293  }
11294 
11295  /* add node to select list of derived table */
11296  dt_query->info.query.q.select.list = parser_append_node (node, dt_query->info.query.q.select.list);
11297 
11298  /* generate unique name for subexpression */
11299  name = (char *) mq_generate_name (parser, "sx", unique);
11300  if (name == NULL)
11301  {
11302  PT_INTERNAL_ERROR (parser, "name generation failed");
11303  return NULL;
11304  }
11305 
11306  /* add to as_attr_list of derived table's spec */
11307  as_attr = pt_name (parser, name);
11308  if (as_attr == NULL)
11309  {
11310  PT_INTERNAL_ERROR (parser, "allocate new node");
11311  return NULL;
11312  }
11313  as_attr->info.name.spec_id = spec->info.spec.id;
11314  as_attr->type_enum = node->type_enum;
11315  as_attr->data_type = parser_copy_tree (parser, node->data_type);
11316  as_attr->etc = node->etc;
11317 
11318  spec->info.spec.as_attr_list = parser_append_node (as_attr, spec->info.spec.as_attr_list);
11319 
11320  /* replace node with reference to derived table field */
11321  attr = pt_name (parser, name);
11322  if (as_attr == NULL)
11323  {
11324  PT_INTERNAL_ERROR (parser, "allocate new node");
11325  return NULL;
11326  }
11328  attr->info.name.spec_id = spec->info.spec.id;
11329  attr->type_enum = node->type_enum;
11330  attr->data_type = parser_copy_tree (parser, node->data_type);
11331  attr->etc = node->etc;
11332 
11333  return attr;
11334 }
11335 
11336 /*
11337  * mq_rewrite_order_dependent_query - rewrite a query that has order dependent
11338  * nodes in the select list
11339  * returns: rewritten query
11340  * parser(in): parser context
11341  * select(in): SELECT statement node
11342  * unique(in/out): pointer to an int counter, used for unique name generation
11343  *
11344  * EXAMPLE: the function will rewrite the query:
11345  *
11346  * SELECT a, b, @a := @a + (c * 3)
11347  * FROM t ORDER BY a
11348  *
11349  * to the following:
11350  *
11351  * SELECT a, b, @a := @a + expr
11352  * FROM (
11353  * SELECT a, b, (c * 3) AS expr
11354  * FROM t ORDER BY a
11355  * ) dt
11356  *
11357  * thus ensuring that @a is correctly evaluated after sorting
11358  */
11359 static PT_NODE *
11361 {
11362  PT_NODE *parent = NULL;
11363  PT_NODE *dt = NULL, *dt_range_var = NULL;
11364  PT_NODE *list = NULL, *list_prev = NULL, *list_next = NULL;
11365  PT_NODE *as_attr = NULL;
11366  PT_NODE *attr = NULL;
11367  int list_pos = 1;
11368 
11369  if (select == NULL)
11370  {
11371  /* nothing to do */
11372  return NULL;
11373  }
11374 
11375  /* allocate new SELECT node */
11376  parent = parser_new_node (parser, PT_SELECT);
11377  if (parent == NULL)
11378  {
11379  PT_INTERNAL_ERROR (parser, "allocate new node");
11380  return NULL;
11381  }
11382 
11383  /* allocate derived table spec node */
11384  dt = parser_new_node (parser, PT_SPEC);
11385  if (dt == NULL)
11386  {
11387  PT_INTERNAL_ERROR (parser, "allocate new node");
11388  return NULL;
11389  }
11390 
11391  /* allocate spec's range var (using static name, should not be ambiguous) */
11392  dt_range_var = pt_name (parser, "dt_sort");
11393  if (dt_range_var == NULL)
11394  {
11395  PT_INTERNAL_ERROR (parser, "allocate new node");
11396  return NULL;
11397  }
11398 
11399  /* original select will now be a subquery */
11400  parent->info.query.is_subquery = select->info.query.is_subquery;
11402 
11403  /* set up spec */
11404  dt->info.spec.id = (UINTPTR) dt;
11405  dt->info.spec.derived_table = select;
11407  dt->info.spec.range_var = dt_range_var;
11409 
11410  /* new SELECT will query a derived table */
11411  parent->info.query.q.select.from = dt;
11413  parent->info.query.scan_op_type = select->info.query.scan_op_type;
11414  parent->info.query.oids_included = select->info.query.oids_included;
11415 
11416  /*
11417  * we now have the original SELECT (with both order dependent and order
11418  * independent nodes in the select list) written as a derived table of an
11419  * empty parent SELECT. first step is to:
11420  * a. add an entry in the spec's as_attr_list for the order independent nodes
11421  * b. add an entry in the parent select list for the order independent nodes
11422  * c. move the order dependent nodes in the parent select list
11423  */
11424 
11425  list = select->info.query.q.select.list;
11426  list_prev = NULL;
11427  list_next = list->next;
11428  list_pos = 1; /* ORDER BY clause indexes position from 1 */
11429  while (list != NULL)
11430  {
11431  if (!PT_IS_ORDER_DEPENDENT (list))
11432  {
11433  char *name = NULL;
11434 
11435  /* this node is order independent so it stays in the derived table's select list */
11436 
11437  /* generate name */
11438  if (list->node_type == PT_NAME)
11439  {
11440  name = (char *) list->info.name.original;
11441  }
11442  else
11443  {
11444  name = (char *) mq_generate_name (parser, (const char *) "ex", unique);
11445  }
11446 
11447  /* add entry in spec's as_attr_list */
11448  as_attr = pt_name (parser, name);
11449  if (as_attr == NULL)
11450  {
11452  return NULL;
11453  }
11454 
11455  as_attr->info.name.spec_id = dt->info.spec.id;
11456  as_attr->type_enum = list->type_enum;
11457  as_attr->data_type = parser_copy_tree (parser, list->data_type);
11458  as_attr->etc = list->etc;
11459 
11461 
11462  if (list->flag.is_hidden_column == 0)
11463  {
11464  /* add entry in new select list */
11465  attr = pt_name (parser, name);
11466  if (attr == NULL)
11467  {
11469  return NULL;
11470  }
11471 
11472  attr->info.name.resolved = dt_range_var->info.name.original;
11473  attr->info.name.spec_id = dt->info.spec.id;
11474  attr->type_enum = list->type_enum;
11475  attr->data_type = parser_copy_tree (parser, list->data_type);
11476  attr->etc = list->etc;
11477 
11478  parent->info.query.q.select.list = parser_append_node (attr, parent->info.query.q.select.list);
11479  }
11480 
11481  /* advance in list */
11482  list_prev = list;
11483  list = list_next;
11484  if (list)
11485  {
11486  list_next = list->next;
11487  }
11488 
11489  /* advance position in list */
11490  list_pos++;
11491  }
11492  else
11493  {
11494  PT_NODE *sort_spec = select->info.query.order_by;
11495 
11496  /* this node is order dependent so it goes in the parent select list */
11497 
11498  /* link PREV to NEXT */
11499  if (list_prev != NULL)
11500  {
11501  list_prev->next = list_next;
11502  }
11503  else
11504  {
11505  select->info.query.q.select.list = list_next;
11506  }
11507 
11508  /* destroy NEXT link of node */
11509  list->next = NULL;
11510 
11511  /* append node to parent select list */
11512  parent->info.query.q.select.list = parser_append_node (list, parent->info.query.q.select.list);
11513 
11514  /* adjust ORDER BY nodes */
11515  while (sort_spec && sort_spec->node_type == PT_SORT_SPEC)
11516  {
11517  if (sort_spec->info.sort_spec.pos_descr.pos_no > list_pos)
11518  {
11519  sort_spec->info.sort_spec.pos_descr.pos_no--;
11520  sort_spec->info.sort_spec.expr->info.value.data_value.i--;
11521  }
11522 
11523  sort_spec = sort_spec->next;
11524  }
11525 
11526  /* advance list and NEXT; prev stays the same */
11527  list = list_next;
11528  if (list)
11529  {
11530  list_next = list->next;
11531  }
11532  }
11533  }
11534 
11535  /* second step is to iterate trough the order dependent nodes (which are now in the parent select list) and, for each
11536  * of them, add nodes in the derived table consisting of all order independent subexpressions */
11537  list = parent->info.query.q.select.list;
11538  while (list != NULL)
11539  {
11540  if (PT_IS_ORDER_DEPENDENT (list))
11541  {
11542  /* process subexpressions */
11543  (void) mq_rewrite_order_dependent_nodes (parser, list, parent, unique);
11544  }
11545 
11546  /* advance list */
11547  list = list->next;
11548  }
11549 
11550  /* mark new SELECT as order dependent so we can bump it's correlation level later on */
11551  PT_SET_ORDER_DEPENDENT_FLAG (parent, true);
11552 
11553  return parent;
11554 }
11555 
11556 /*
11557  * mq_bump_order_dep_corr_lvl_pre - walk_tree function for bumping correlation
11558  * levels of order dependent SELECTs
11559  * parser(in): parser context
11560  * node(in): node
11561  * arg(in/out): parent node stack
11562  * continue_walk(in/out): walk type
11563  *
11564  * NOTE: for the sake of simplicity, the stack is implemented as a double
11565  * linked list of "PT_EXPR" PT_NODEs, with the following topology:
11566  * n->next: will hold a pointer to the next item in the list
11567  * n->info.expr.arg2: will hold a pointer to the previous item in the list
11568  * n->info.expr.arg1: will hold a pointer to the actual node
11569  *
11570  * NOTE: nodes are pushed in the pre function and popped in the post function
11571  */
11572 static PT_NODE *
11573 mq_bump_order_dep_corr_lvl_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
11574 {
11575  PT_NODE **stack = (PT_NODE **) arg;
11576  PT_NODE *stack_head = NULL, *stack_end = NULL;
11577  PT_NODE *stack_item = NULL, *stack_prev = NULL;
11578 
11579  if (node == NULL || parser == NULL || stack == NULL || !PT_IS_QUERY (node))
11580  {
11581  return node;
11582  }
11583 
11584  /* set up stack pointers */
11585  stack_head = stack_end = *stack;
11586  while (stack_end != NULL && stack_end->next != NULL)
11587  {
11588  stack_end = stack_end->next;
11589  }
11590 
11591  /* push node in stack */
11592  stack_item = parser_new_node (parser, PT_EXPR);
11593  if (stack_item == NULL)
11594  {
11595  PT_INTERNAL_ERROR (parser, "allocate new node");
11596  return node;
11597  }
11598 
11599  stack_item->next = NULL;
11600  stack_item->info.expr.arg1 = node;
11601  stack_item->info.expr.arg2 = stack_end;
11602 
11603  if (stack_end != NULL)
11604  {
11605  /* link to last item */
11606  stack_end->next = stack_item;
11607  stack_end = stack_item;
11608  }
11609  else
11610  {
11611  /* first item */
11612  stack_head = stack_end = stack_item;
11613  *stack = stack_item;
11614  }
11615 
11616  /* process node */
11617  if (PT_IS_ORDER_DEPENDENT (node))
11618  {
11619  PT_NODE *item = NULL, *prev = NULL;
11620  int corr_diff = 0;
11621 
11622  stack_item = stack_end;
11623  while (stack_item != NULL && stack_item->info.expr.arg2 != NULL)
11624  {
11625  /* due to the walk_tree function, all items in lists are pushed in the stack before any of them is popped;
11626  * here, we skip same-level nodes */
11627  stack_prev = stack_item->info.expr.arg2;
11628  while (stack_prev && stack_prev->info.expr.arg1->next == stack_prev->next->info.expr.arg1)
11629  {
11630  stack_prev = stack_prev->info.expr.arg2;
11631  }
11632 
11633  if (stack_prev == NULL)
11634  {
11635  /* stack_item is in top level list; should never get here ... */
11636  assert (false);
11637  break;
11638  }
11639 
11640  /* get node and previous node */
11641  item = stack_item->info.expr.arg1;
11642  prev = stack_prev->info.expr.arg1;
11643  corr_diff = item->info.query.correlation_level - prev->info.query.correlation_level;
11644 
11645  /* check correlation levels */
11646  if (item != NULL && prev != NULL && corr_diff <= 0)
11647  {
11648  /* same correlation level or parent has greater correlation level; not acceptable */
11649  corr_diff = -corr_diff + 1;
11650 
11651  (void) mq_bump_correlation_level (parser, item, corr_diff, item->info.query.correlation_level);
11652 
11653  item->info.query.correlation_level += corr_diff;
11654  }
11655 
11656  /* peek back in stack list */
11657  stack_item = stack_prev;
11658  }
11659  }
11660 
11661  return node;
11662 }
11663 
11664 /*
11665  * mq_bump_order_dep_corr_lvl_post - walk_tree post function for bumping
11666  * correlation levels of order dependent
11667  * SELECTs
11668  * parser(in): parser context
11669  * node(in): node
11670  * arg(in/out): parent node stack
11671  * continue_walk(in/out): walk type
11672  *
11673  * NOTE: this function only pops nodes from the stack
11674  */
11675 static PT_NODE *
11676 mq_bump_order_dep_corr_lvl_post (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
11677 {
11678  PT_NODE **stack = (PT_NODE **) arg;
11679  PT_NODE *stack_item = NULL;
11680 
11681  if (node == NULL || parser == NULL || stack == NULL || !PT_IS_QUERY (node))
11682  {
11683  return node;
11684  }
11685 
11686  /* node is query, pop from stack */
11687  stack_item = *stack;
11688  while (stack_item != NULL && stack_item->next != NULL)
11689  {
11690  stack_item = stack_item->next;
11691  }
11692 
11693  if (stack_item != NULL && stack_item->info.expr.arg2)
11694  {
11695  stack_item->info.expr.arg2->next = NULL;
11696  }
11697  else
11698  {
11699  *stack = NULL;
11700  }
11701 
11702  if (stack_item != NULL)
11703  {
11704  parser_free_node (parser, stack_item);
11705  }
11706 
11707  return node;
11708 }
11709 
11710 /*
11711  * mq_bump_order_dep_corr_lvl - bump correlation levels for order dependent
11712  * SELECTs
11713  * parser(in): parser context
11714  * node(in): root node
11715  */
11716 static void
11718 {
11719  PT_NODE *stack = NULL;
11720 
11721  /* bump order dependent SELECTs */
11722  (void) parser_walk_tree (parser, node, mq_bump_order_dep_corr_lvl_pre, (void *) &stack,
11723  mq_bump_order_dep_corr_lvl_post, (void *) &stack);
11724 }
11725 
11726 /*
11727  * mq_reset_references_to_query_string () - reset references to the position
11728  * in the original query string
11729  * parser(in): parser context
11730  * node(in): node
11731  * arg(in/out): parent node stack
11732  * continue_walk(in/out): walk type
11733  *
11734  * NOTE: This function resets the value of line_number, column_number and
11735  * buffer_pos for each node. This is called on the parse trees of translated
11736  * views. Since these values point to the view query and not to the actual
11737  * query that is being executed, they will not hold useful information
11738  */
11739 static PT_NODE *
11740 mq_reset_references_to_query_string (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
11741 {
11742  if (node == NULL || parser == NULL)
11743  {
11744  return node;
11745  }
11746 
11747  node->line_number = 0;
11748  node->column_number = 0;
11749  node->buffer_pos = -1;
11750 
11751  return node;
11752 }
11753 
11754 /*
11755  * mq_auto_param_merge_clauses () - auto-parameterize update assignments
11756  * and insert values clause
11757  * return:
11758  * parser(in):
11759  * stmt(in):
11760  */
11761 static void
11763 {
11764  PT_NODE *values_list, *first, *prev, *p, *save_next;
11765  int i;
11766 
11767  /* auto-parameterize update assignments */
11769 
11770  /* auto-parameterize insert values clause */
11771  if (stmt->info.merge.insert.value_clauses)
11772  {
11773  p = values_list = stmt->info.merge.insert.value_clauses->info.node_list.list;
11774  first = prev = NULL;
11775  for (i = 0; p != NULL; i++)
11776  {
11777  save_next = p->next;
11778  p->next = NULL;
11779  if (pt_is_const_not_hostvar (p) && !PT_IS_NULL_NODE (p))
11780  {
11781  p = pt_rewrite_to_auto_param (parser, p);
11782  }
11783  if (i == 0)
11784  {
11785  first = p;
11786  }
11787  else
11788  {
11789  prev->next = p;
11790  }
11791  p->next = save_next;
11792  prev = p;
11793  p = p->next;
11794  }
11795  stmt->info.merge.insert.value_clauses->info.node_list.list = first;
11796  }
11797 }
11798 
11799 /*
11800  * mq_copy_view_error_msgs () - copy error message from a parser to another
11801  *
11802  * return: void
11803  * parser(in):
11804  * query_cache(in):
11805  *
11806  * Note that view parser will be freed for error cases.
11807  * This means that error message of a view parser should be allocated and copied by the nesting parser.
11808  */
11809 static void
11811 {
11812  PT_NODE *error_msg;
11813  int stmt_no, line_no, col_no;
11814  const char *msg = NULL;
11815 
11816  error_msg = pt_get_errors (query_cache);
11817 
11818  /* expect callers already confirms it has an error */
11819  assert (error_msg != NULL && error_msg->node_type == PT_ZZ_ERROR_MSG);
11820 
11821  error_msg = pt_get_next_error (error_msg, &stmt_no, &line_no, &col_no, &msg);
11822 
11823  pt_record_error (parser, stmt_no, line_no, col_no, msg, NULL);
11824 }
#define MSGCAT_RUNTIME_CYCLIC_QUERY_SPEC
PT_NODE * except_list
Definition: parse_tree.h:2133
PT_NODE * mq_clear_ids(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *spec)
#define PT_NAME_INFO_SET_FLAG(e, f)
Definition: parse_tree.h:2575
PT_NODE * pt_name(PARSER_CONTEXT *parser_ptr, const char *name)
PT_NODE * order_by
Definition: parse_tree.h:2769
PT_NODE * pt_resolve_using_index(PARSER_CONTEXT *parser, PT_NODE *index, PT_NODE *from)
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
PT_NODE * pt_find_aggregate_names(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: parse_tree.h:2829
static PT_NODE * mq_bump_corr_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define MSGCAT_SEMANTIC_MULTIPLE_INSERT_TARGETS
#define PT_EXPR_INFO_COPYPUSH
Definition: parse_tree.h:2220
PT_NODE * mq_rewrite_aggregate_as_derived(PARSER_CONTEXT *parser, PT_NODE *agg_sel)
#define PT_IS_QUERY(n)
Definition: parse_tree.h:296
static PT_NODE * mq_substitute_select_in_statement(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *query_spec, PT_NODE *class_)
PT_NODE * target_classes
Definition: parse_tree.h:2060
static PT_NODE * mq_path_spec_lambda(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *root_spec, PT_NODE **prev_ptr, PT_NODE *old_spec, PT_NODE *new_spec)
static bool mq_conditionally_add_objects(PARSER_CONTEXT *parser, PT_NODE *flat, DB_OBJECT ***classes, int *index, int *max)
unsigned vspec_as_derived
Definition: parse_tree.h:2761
PT_NODE * arg_list
Definition: parse_tree.h:2258
static PT_NODE * mq_union_bump_correlation(PARSER_CONTEXT *parser, PT_NODE *left, PT_NODE *right)
static PT_NODE * mq_translate_tree(PARSER_CONTEXT *parser, PT_NODE *tree, PT_NODE *spec_list, PT_NODE *order_by, int what_for)
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_NODE * pt_insert_entity(PARSER_CONTEXT *parser, PT_NODE *path, PT_NODE *prev_entity, PT_NODE *correlation_entity)
#define AU_DISABLE(save)
Definition: authenticate.h:106
struct check_pushable_info CHECK_PUSHABLE_INFO
static void mq_set_non_updatable_oid(PARSER_CONTEXT *parser, PT_NODE *stmt, PT_NODE *virt_entity)
void mq_free_virtual_query_cache(PARSER_CONTEXT *parser)
PT_METHOD_CALL_INFO method_call
Definition: parse_tree.h:3316
#define PT_SELECT_INFO_IS_FLAGED(s, f)
Definition: parse_tree.h:2735
bool pt_is_aggregate_function(PARSER_CONTEXT *parser, const PT_NODE *node)
PT_UPDATE_INFO update
Definition: parse_tree.h:3353
PT_MERGE_INFO merge
Definition: parse_tree.h:3315
UINTPTR id
Definition: parse_tree.h:2144
int sm_is_system_class(MOP op)
static PT_NODE * pt_find_only_name_id(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
#define PT_SELECT_INFO_NO_STRICT_OID_CHECK
Definition: parse_tree.h:2726
PT_CHECK_OPTION_INFO check_option
Definition: parse_tree.h:3276
struct find_id_info::@138 in
PT_NODE ** parser_parse_string_use_sys_charset(PARSER_CONTEXT *parser, const char *buffer)
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
#define PT_ERRORm(parser, node, setNo, msgNo)
Definition: parse_tree.h:63
static bool mq_has_class_methods_corr_subqueries(PARSER_CONTEXT *parser, PT_NODE *node)
#define MSGCAT_RUNTIME_QSPEC_INCOMP_W_ATTR
static PT_NODE * mq_translate_value(PARSER_CONTEXT *parser, PT_NODE *value)
PT_NODE * using_index
Definition: parse_tree.h:2693
PT_NODE * into_list
Definition: parse_tree.h:2771
static PT_NODE * mq_bump_corr_post(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
const char * db_get_class_name(DB_OBJECT *class_)
Definition: db_info.c:608
#define MSGCAT_RUNTIME_NO_VID_FOR_NON_UPDATABLE_VIEW
static PT_NODE * mq_new_spec(PARSER_CONTEXT *parser, const char *class_name)
void * parser_alloc(const PARSER_CONTEXT *parser, const int length)
Definition: parse_tree.c:951
PT_NODE * assignment
Definition: parse_tree.h:2861
static PT_NODE * mq_rewrite_order_dependent_query(PARSER_CONTEXT *parser, PT_NODE *select, int *unique)
void pt_mark_spec_list_for_delete(PARSER_CONTEXT *parser, PT_NODE *statement)
DB_OBJECT * db_get_owner(DB_OBJECT *class_obj)
Definition: db_admin.c:1892
short location
Definition: parse_tree.h:2577
DB_OBJECT * db_real_instance(DB_OBJECT *obj)
Definition: db_virt.c:247
static PT_NODE * mq_update_order_by(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *query_spec, PT_NODE *class_)
static PT_NODE * mq_set_all_ids(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define MSGCAT_SEMANTIC_DUPLICATE_CLASS_OR_ALIAS
#define PT_PUSHABLE_TERM(p)
static void mq_invert_insert_select(PARSER_CONTEXT *parser, PT_NODE *attr, PT_NODE *subquery)
PT_NODE * statement
PT_MISC_TYPE
Definition: parse_tree.h:983
static PT_NODE * mq_translate_select(PARSER_CONTEXT *parser, PT_NODE *select_statement)
static DB_AUTH mq_compute_query_authorization(PT_NODE *statement)
#define PT_ERROR(parser, node, msg)
Definition: parse_tree.h:54
PT_NODE * mq_translate(PARSER_CONTEXT *parser, PT_NODE *volatile node)
int db_get_int(const DB_VALUE *value)
static void mq_invert_subqueries(PARSER_CONTEXT *parser, PT_NODE *select_statements, PT_NODE *attributes)
static PT_NODE * mq_add_dummy_from_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
PT_NODE * where
Definition: parse_tree.h:2337
int db_is_vclass(DB_OBJECT *op)
Definition: db_virt.c:681
static PT_NODE * mq_fix_derived(PARSER_CONTEXT *parser, PT_NODE *select_statement, PT_NODE *spec)
PT_NODE * assignment
Definition: parse_tree.h:2928
#define ER_FAILED
Definition: error_code.h:47
#define MSGCAT_RUNTIME_ATTRS_GT_QSPEC_COLS
static bool mq_check_vclass_for_insert(PARSER_CONTEXT *parser, PT_NODE *stmt)
int mq_update_attribute(DB_OBJECT *vclass_object, const char *attr_name, DB_OBJECT *real_class_object, DB_VALUE *virtual_value, DB_VALUE *real_value, const char **real_name, int db_auth)
static PT_NODE * mq_substitute_spec_in_method_names(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define MSGCAT_SEMANTIC_OUT_OF_MEMORY
struct find_id_info::@139 out
static bool pt_pushable_query_in_pos(PARSER_CONTEXT *parser, PT_NODE *query, int pos)
short location
Definition: parse_tree.h:2152
#define PT_EXPR_INFO_SET_FLAG(e, f)
Definition: parse_tree.h:2239
static const char * get_authorization_name(DB_AUTH auth)
PT_NODE * search_cond
Definition: parse_tree.h:2925
PT_NODE * arg3
Definition: parse_tree.h:2202
void pt_no_double_updates(PARSER_CONTEXT *parser, PT_NODE *stmt)
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
DB_AUTH auth_bypass_mask
Definition: parse_tree.h:2154
struct extra_specs_frame * next
PT_NODE * arg2
Definition: parse_tree.h:2664
int correlation_level
Definition: parse_tree.h:2745
enum pt_type_enum PT_TYPE_ENUM
Definition: parse_tree.h:962
#define DB_AUTH_ALL
Definition: dbtype_def.h:157
VIEW_CACHE_INFO * view_cache
Definition: parse_tree.h:3571
void pt_record_error(PARSER_CONTEXT *parser, int stmt_no, int line_no, int col_no, const char *msg, const char *context)
static PT_NODE * mq_reset_spec_in_method_names(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define pt_is_query(n)
Definition: parse_tree.h:258
int db_make_object(DB_VALUE *value, DB_C_OBJECT *obj)
PT_NODE * attr_list
PT_NODE * spec
Definition: parse_tree.h:2859
static PT_NODE * mq_push_paths(PARSER_CONTEXT *parser, PT_NODE *statement, void *void_arg, int *continue_walk)
PT_NODE * pt_get_next_error(PT_NODE *errors, int *stmt_no, int *line_no, int *col_no, const char **msg)
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
PT_NODE * pt_check_odku_assignments(PARSER_CONTEXT *parser, PT_NODE *insert)
PT_NODE * mq_rewrite_query_as_derived(PARSER_CONTEXT *parser, PT_NODE *query)
PARSER_CONTEXT * parser_create_parser(void)
Definition: parse_tree.c:1169
PT_NODE * pt_entity(PARSER_CONTEXT *parser, const PT_NODE *entity_name, const PT_NODE *range_var, const PT_NODE *flat_list)
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2552
static PT_NODE * mq_lookup_symbol(PARSER_CONTEXT *parser, PT_NODE *attr_list, PT_NODE *attr)
static PT_NODE * mq_clear_other_ids(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * mq_reset_select_spec_node(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
struct pt_query_info::@123 flag
PT_NODE * mq_get_references_helper(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec, bool get_spec_referenced_attr)
int mq_is_real_class_of_vclass(PARSER_CONTEXT *parser, const PT_NODE *s_class, const PT_NODE *d_class)
static PT_NODE * mq_replace_name_with_path(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static unsigned int top_cycle
NESTED_VIEW_VERSION_INFO * nested_views
Definition: parse_tree.h:1738
unsigned int custom_print
Definition: parse_tree.h:2554
PT_SPEC_FLAG
Definition: parse_tree.h:1517
union pt_query_info::@124 q
static PT_NODE * mq_set_types(PARSER_CONTEXT *parser, PT_NODE *query_spec, PT_NODE *attributes, DB_OBJECT *vclass_object, int cascaded_check)
PT_NODE * path_entities
Definition: parse_tree.h:2138
int mq_evaluate_expression_having_serial(PARSER_CONTEXT *parser, PT_NODE *expr, DB_VALUE *values, int values_count, DB_OBJECT *object, UINTPTR spec_id)
int mq_evaluate_check_option(PARSER_CONTEXT *parser, PT_NODE *check_where, DB_OBJECT *object, PT_NODE *view_class)
PT_NODE * vquery_for_partial_update
Definition: parse_tree.h:1732
static int pt_check_copypush_subquery(PARSER_CONTEXT *parser, PT_NODE *query)
struct pt_merge_info::@125 update
static PT_NODE * mq_rewrite_vclass_spec_as_derived(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec, PT_NODE *query_spec)
#define PT_IS_NULL_NODE(e)
Definition: parse_tree.h:122
PT_NODE * select_stack
Definition: parse_tree.h:3395
PT_NODE * group_by
Definition: parse_tree.h:2688
#define MSGCAT_SEMANTIC_CLASS_DOES_NOT_HAVE
PT_NODE * pt_flat_spec_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static PT_NODE * mq_set_references_local(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
PT_ERROR_TYPE
Definition: parse_tree.h:1503
int er_errid(void)
FIND_ID_TYPE type
static PT_NODE * mq_rewrite_agg_names_post(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE_LIST_INFO node_list
Definition: parse_tree.h:3320
bool correlated_found
static PT_NODE * mq_clean_dot(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
SCAN_OPERATION_TYPE scan_op_type
Definition: parse_tree.h:2751
static bool pt_sargable_term(PARSER_CONTEXT *parser, PT_NODE *term, FIND_ID_INFO *infop)
#define PT_SET_JMP_ENV(parser)
Definition: parse_tree.h:89
#define AU_SET_USER
Definition: authenticate.h:141
PT_NODE * lambda_expr
#define MSGCAT_RUNTIME_NO_REALCLASS_4_VCLAS
static DB_OBJECT * cycle_buffer[MAX_CYCLE]
static PT_NODE * mq_fix_derived_in_union(PARSER_CONTEXT *parser, PT_NODE *statement, UINTPTR spec_id)
bool mq_is_outer_join_spec(PARSER_CONTEXT *parser, PT_NODE *spec)
static void mq_copy_view_error_msgs(PARSER_CONTEXT *parser, PARSER_CONTEXT *query_cache)
PT_NODE * attr_list
Definition: parse_tree.h:2333
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 ws_is_same_object(MOP mop1, MOP mop2)
Definition: work_space.c:5065
static PT_NODE * mq_clear_all_ids(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * data_type
Definition: parse_tree.h:3453
unsigned single_table_opt
Definition: parse_tree.h:2711
static PT_NODE * mq_translate_subqueries(PARSER_CONTEXT *parser, DB_OBJECT *class_object, PT_NODE *attributes, DB_AUTH *authorization)
#define PT_IS_OID_NAME(n)
Definition: parse_tree.h:323
static PT_NODE * mq_reset_spec_distr_subpath_pre(PARSER_CONTEXT *parser, PT_NODE *spec, void *void_arg, int *continue_walk)
#define MAX_STACK_OBJECTS
static int mq_translatable_class(PARSER_CONTEXT *parser, PT_NODE *class_)
static PT_NODE * mq_rewrite_upd_del_top_level_specs(PARSER_CONTEXT *parser, PT_NODE *statement, void *void_arg, int *continue_walk)
PT_DOT_INFO dot
Definition: parse_tree.h:3287
PT_NODE * arg2
Definition: parse_tree.h:2086
static PT_NODE * pt_check_for_update_subquery(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static PT_NODE * mq_translate_merge(PARSER_CONTEXT *parser, PT_NODE *merge_statement)
PT_NODE * pt_lambda(PARSER_CONTEXT *parser, PT_NODE *tree_with_names, PT_NODE *name_node, PT_NODE *corresponding_tree)
PT_NODE * index_ss
Definition: parse_tree.h:2698
PT_NODE * mq_reset_paths(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *root_spec)
#define PT_NODE_COPY_NUMBER_OUTERLINK(t, s)
Definition: parse_tree.h:560
void parser_free_parser(PARSER_CONTEXT *parser)
Definition: parse_tree.c:1240
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
void pt_report_to_ersys(const PARSER_CONTEXT *parser, const PT_ERROR_TYPE error_type)
Definition: query_result.c:287
PT_NODE * derived_select
Definition: parse_tree.h:3380
PT_NODE * pt_resolve_star(PARSER_CONTEXT *parser, PT_NODE *from, PT_NODE *attr)
#define MSGCAT_RUNTIME_SEL_NOT_AUTHORIZED
bool found
Definition: cnf.c:46
int db_make_string(DB_VALUE *value, DB_CONST_C_CHAR str)
static PT_NODE * mq_fetch_subqueries_for_update(PARSER_CONTEXT *parser, PT_NODE *class_, PT_FETCH_AS fetch_as, DB_AUTH what_for)
PT_NODE * class_where
Definition: parse_tree.h:2940
static PT_NODE * mq_substitute_path(PARSER_CONTEXT *parser, PT_NODE *node, PATH_LAMBDA_INFO *path_info)
#define ER_PT_SEMANTIC
Definition: error_code.h:581
char oids_included
Definition: parse_tree.h:2750
int db_is_superclass(MOP supermop, MOP classmop)
Definition: db_info.c:466
static void mq_invert_assign(PARSER_CONTEXT *parser, PT_NODE *attr, PT_NODE *&expr, PT_NODE *inverted)
PT_NODE * limit
Definition: parse_tree.h:2773
static bool mq_is_order_dependent_node(PT_NODE *node)
DB_DATA data
Definition: dbtype_def.h:1083
PT_MISC_TYPE class_or_inst
Definition: parse_tree.h:2368
PARSER_CONTEXT * mq_virtual_queries(DB_OBJECT *class_object)
PT_NODE * tree_list
PT_MISC_TYPE derived_table_type
Definition: parse_tree.h:2147
PT_NODE * arg1
Definition: parse_tree.h:2663
void qo_do_auto_parameterize(PARSER_CONTEXT *parser, PT_NODE *where)
#define PT_IS_SELECT(n)
Definition: parse_tree.h:284
PT_NODE * vquery_for_update
Definition: parse_tree.h:1730
PT_HINT_ENUM
Definition: parse_tree.h:1161
PT_NODE * arg2
Definition: parse_tree.h:2198
PT_FUNCTION_INFO function
Definition: parse_tree.h:3301
PT_CONNECT_BY_CHECK_CYCLES check_cycles
Definition: parse_tree.h:2710
bool mq_is_updatable_attribute(DB_OBJECT *vclass_object, const char *attr_name, DB_OBJECT *real_class_object)
DB_OBJECT * db_object
Definition: parse_tree.h:2546
static PT_NODE * mq_lambda_node(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
FIND_ID_TYPE
#define PT_ERRORmf2(parser, node, setNo, msgNo, arg1, arg2)
Definition: parse_tree.h:65
#define MSGCAT_RUNTIME_OUT_OF_MEMORY
#define assert(x)
int db_is_partition(DB_OBJECT *classobj, DB_OBJECT *superobj)
Definition: db_info.c:483
PT_NODE * pt_find_spec(PARSER_CONTEXT *parser, const PT_NODE *from, const PT_NODE *name)
#define PT_IS_QUERY_NODE_TYPE(x)
Definition: parse_tree.h:115
PT_NODE * parser_walk_leaves(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE_WALK_FUNCTION pre_function, void *pre_argument, PT_NODE_WALK_FUNCTION post_function, void *post_argument)
#define MSGCAT_RUNTIME_QSPEC_COLS_GT_ATTRS
PT_SPEC_FLAG flag
Definition: parse_tree.h:2155
unsigned order_siblings
Definition: parse_tree.h:2765
static void mq_bump_order_dep_corr_lvl(PARSER_CONTEXT *parser, PT_NODE *node)
void pt_evaluate_tree(PARSER_CONTEXT *parser, PT_NODE *tree, DB_VALUE *db_values, int values_count)
PT_NODE * pt_rewrite_to_auto_param(PARSER_CONTEXT *parser, PT_NODE *value)
static PT_NODE * mq_reset_all_ids(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
DB_OBJECT * op
Definition: parse_tree.h:3039
static PT_NODE * mq_substitute_path_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static int mq_copypush_sargable_terms_helper(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec, PT_NODE *new_query, FIND_ID_INFO *infop)
static PT_NODE * mq_path_name_lambda(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *lambda_name, PT_NODE *lambda_expr, UINTPTR spec_id)
PT_TYPE_ENUM virt_type_enum
Definition: parse_tree.h:2042
static PT_NODE * mq_reset_references_to_query_string(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define MSGCAT_RUNTIME_VC_COMP_NOT_UPDATABL
bool mq_is_updatable_strict(DB_OBJECT *class_object)
DB_VALUE db_value
Definition: parse_tree.h:3059
PT_NODE * odku_assignments
Definition: parse_tree.h:2341
#define MSGCAT_RUNTIME_CHECK_OPTION_EXCEPT
PT_EXTRA_SPECS_FRAME * spec_frames
PT_NODE * vquery_for_query_in_gdb
Definition: parse_tree.h:1729
static PT_NODE * mq_get_references_node(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * on_cond
Definition: parse_tree.h:2149
PT_NODE * entity
Definition: parse_tree.h:2038
#define MSGCAT_SET_PARSER_RUNTIME
PT_INCLUDE_OID_TYPE oid_included
Definition: parse_tree.h:3586
void insert_rewrite_names_in_value_clauses(PARSER_CONTEXT *parser, PT_NODE *insert_statement)
PT_NODE * mq_class_lambda(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *class_, PT_NODE *corresponding_spec, PT_NODE *class_where_part, PT_NODE *class_check_part, PT_NODE *class_group_by_part, PT_NODE *class_having_part)
PT_DATA_VALUE data_value
Definition: parse_tree.h:3058
static PT_NODE * mq_translate_update(PARSER_CONTEXT *parser, PT_NODE *update_statement)
PT_NODE * flat_entity_list
Definition: parse_tree.h:2140
PT_NODE ** parser_parse_string(PARSER_CONTEXT *parser, const char *buffer)
static PT_NODE * mq_translate_local(PARSER_CONTEXT *parser, PT_NODE *statement, void *void_arg, int *continue_walk)
PT_NODE * top_node
Definition: parse_tree.h:1707
PT_MISC_TYPE all_distinct
Definition: parse_tree.h:2746
bool pt_has_analytic(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE * method_name
Definition: parse_tree.h:2363
PT_NODE * query_list
const char * original
Definition: parse_tree.h:2544
PT_NODE * using_index
Definition: parse_tree.h:2064
static PT_NODE * mq_check_rewrite_select(PARSER_CONTEXT *parser, PT_NODE *select_statement)
PT_NODE * old_next
PT_HINT_ENUM hint
Definition: parse_tree.h:2707
int intl_identifier_casecmp(const char *str1, const char *str2)
void pt_evaluate_tree_having_serial(PARSER_CONTEXT *parser, PT_NODE *tree, DB_VALUE *db_value, int vals_cnt)
int pt_name_occurs_in_from_list(PARSER_CONTEXT *parser, const char *name, PT_NODE *from_list)
Definition: compile.c:1545
DB_OBJECT * mq_fetch_one_real_class(DB_OBJECT *vclass_object)
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
static PT_NODE * mq_set_virt_object(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * mq_push_path(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec, PT_NODE *path)
const char * db_error_string(int level)
Definition: db_admin.c:2116
PT_NODE * parser_copy_tree(PARSER_CONTEXT *parser, const PT_NODE *tree)
static PT_NODE * mq_generate_unique(PARSER_CONTEXT *parser, PT_NODE *name_list)
#define PT_IS_VALUE_QUERY(n)
Definition: parse_tree.h:476
static PT_NODE * mq_resolve_insert_statement(PARSER_CONTEXT *parser, PT_NODE *insert_statement)
PT_NODE * pt_semantic_type(PARSER_CONTEXT *parser, PT_NODE *tree, SEMANTIC_CHK_INFO *sc_info)
static void mq_insert_symbol(PARSER_CONTEXT *parser, PT_NODE **listhead, PT_NODE *attr)
static int mq_is_referenced(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
const char * db_query_spec_string(DB_QUERY_SPEC *query_spec)
Definition: db_virt.c:651
PT_NODE * having
Definition: parse_tree.h:2692
DB_OBJECT * db_get_object(const DB_VALUE *value)
PT_NODE * from
Definition: parse_tree.h:2686
#define PT_SELECT_INFO_HAS_AGG
Definition: parse_tree.h:2717
#define PT_SELECT_INFO_COLS_SCHEMA
Definition: parse_tree.h:2721
static PT_NODE * mq_replace_virtual_oid_with_real_oid(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
UINTPTR spec_id
Definition: parse_tree.h:2543
static PT_NODE * mq_reset_select_specs(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define PT_SELECT_INFO_IS_MERGE_QUERY
Definition: parse_tree.h:2723
PT_NODE * value_clauses
Definition: parse_tree.h:2938
static int mq_check_using_index(PARSER_CONTEXT *parser, PT_NODE *using_index)
PT_NODE * inverted_vquery_for_update
Definition: parse_tree.h:1733
static PT_NODE * mq_translate_insert(PARSER_CONTEXT *parser, PT_NODE *insert_statement)
PT_DATA_TYPE_INFO data_type
Definition: parse_tree.h:3284
static bool mq_is_updatable_local(DB_OBJECT *class_object, PT_FETCH_AS fetch_as)
int db_get_attribute_descriptor(DB_OBJECT *obj, const char *attname, int class_attribute, int for_update, DB_ATTDESC **descriptor)
Definition: db_obj.c:763
static PT_NODE * mq_class_meth_corr_subq_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
int pt_str_compare(const char *p, const char *q, CASE_SENSITIVENESS case_flag)
SP_PARSER_CTX * parser
bool mq_is_updatable(DB_OBJECT *class_object)
PT_NODE * arg1
Definition: parse_tree.h:2197
PT_NODE * pt_find_entity(PARSER_CONTEXT *parser, const PT_NODE *scope, UINTPTR id)
unsigned rewrite_limit
Definition: parse_tree.h:2766
#define NULL
Definition: freelistheap.h:34
static PT_NODE * mq_bump_order_dep_corr_lvl_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
PT_NODE * pt_pointer_stack_pop(PARSER_CONTEXT *parser, PT_NODE *stack, PT_NODE **node)
PT_NODE * as_attr_list
Definition: parse_tree.h:2136
static void mq_check_delete(PARSER_CONTEXT *parser, PT_NODE *delete_stmt)
#define pt_is_const_not_hostvar(n)
Definition: parse_tree.h:274
const char * er_msg(void)
PT_NODE * referenced_attrs
Definition: parse_tree.h:2137
int db_is_class(MOP obj)
Definition: db_info.c:310
static PT_UPDATABILITY mq_updatable_local(PARSER_CONTEXT *parser, PT_NODE *statement, DB_OBJECT ***classes, int *i, int *max)
DB_OBJECT * db_get_class(MOP obj)
Definition: db_info.c:589
PT_NODE * value_clauses
Definition: parse_tree.h:2334
unsigned recompile
Definition: parse_tree.h:3461
PT_MISC_TYPE is_subquery
Definition: parse_tree.h:2747
if(extra_options)
Definition: dynamic_load.c:958
static PT_NODE * mq_fetch_expression_for_real_class_update(PARSER_CONTEXT *parser, DB_OBJECT *vclass_obj, PT_NODE *attr, PT_NODE *real_class, PT_FETCH_AS fetch_as, DB_AUTH what_for, UINTPTR *spec_id)
static PT_NODE * mq_substitute_subquery_list_in_statement(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *query_spec_list, PT_NODE *class_, PT_NODE *order_by, int what_for)
static PT_NODE * mq_referenced_post(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
int sm_get_class_flag(MOP op, SM_CLASS_FLAG flag)
#define PT_SPEC_IS_DERIVED(spec_)
Definition: parse_tree.h:690
char * parser_print_tree_list(PARSER_CONTEXT *parser, const PT_NODE *node)
char * pt_append_string(const PARSER_CONTEXT *parser, const char *old_string, const char *new_tail)
Definition: parse_tree.c:980
static PT_NODE * mq_reset_ids_and_references(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
#define err(fd,...)
Definition: porting.h:431
PT_NODE * mq_make_derived_spec(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *subquery, int *idx, PT_NODE **spec_ptr, PT_NODE **attr_list_ptr)
#define PT_ERRORc(parser, node, msg)
Definition: parse_tree.h:55
int pt_find_var(PT_NODE *p, PT_NODE **result)
PT_NODE ** parser_parse_string_with_escapes(PARSER_CONTEXT *parser, const char *buffer, const bool strings_have_no_escapes)
struct find_id_info FIND_ID_INFO
PT_NODE * mq_bump_correlation_level(PARSER_CONTEXT *parser, PT_NODE *node, int increment, int match)
static int mq_check_authorization_path_entities(PARSER_CONTEXT *parser, PT_NODE *class_spec, int what_for)
DB_AUTH authorization
Definition: parse_tree.h:1737
#define PT_SPEC_IS_CTE(spec_)
Definition: parse_tree.h:694
PT_NODE * pt_continue_walk(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
#define MAX_CYCLE
int pt_find_attribute(PARSER_CONTEXT *parser, const PT_NODE *name, const PT_NODE *attributes)
PT_NODE * arg1
Definition: parse_tree.h:2085
PT_NODE * where
Definition: parse_tree.h:2687
PT_QUERY_INFO query
Definition: parse_tree.h:3325
short location
Definition: parse_tree.h:2243
PT_NODE * mq_fetch_attributes(PARSER_CONTEXT *parser, PT_NODE *class_)
static PT_NODE * mq_substitute_subquery_in_statement(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *query_spec, PT_NODE *class_, PT_NODE *order_by, int what_for)
PT_NODE * use_idx
Definition: parse_tree.h:2697
bool pt_has_aggregate(PARSER_CONTEXT *parser, PT_NODE *node)
static DB_AUTH mq_compute_authorization(DB_OBJECT *class_object)
DB_OBJECT * object
PT_UPDATABILITY mq_updatable(PARSER_CONTEXT *parser, PT_NODE *statement)
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
int pr_clear_value(DB_VALUE *value)
PT_NODE * spec
Definition: parse_tree.h:2331
const char * text
Definition: parse_tree.h:3056
DB_OBJECT * db_get_user(void)
Definition: db_admin.c:1974
int vid_vobj_to_object(const DB_VALUE *vobj, DB_OBJECT **mop)
static PT_NODE * mq_translate_helper(PARSER_CONTEXT *parser, PT_NODE *node)
static void mq_check_update(PARSER_CONTEXT *parser, PT_NODE *update_statement)
enum pt_updatability PT_UPDATABILITY
#define MSGCAT_RUNTIME_VCLASS_NOT_UPDATABLE
PT_NODE * set
Definition: parse_tree.h:3047
#define max(a, b)
static void mq_auto_param_merge_clauses(PARSER_CONTEXT *parser, PT_NODE *stmt)
PT_NODE * inverted_vquery_for_update_in_gdb
Definition: parse_tree.h:1734
PT_NODE * qo_check_nullable_expr(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define MSGCAT_SEMANTIC_INVALID_USE_FOR_UPDATE_CLAUSE
PT_NODE * parser_append_node(PT_NODE *node, PT_NODE *list)
PT_NODE * check_where
Definition: parse_tree.h:2943
char * pt_short_print(PARSER_CONTEXT *parser, const PT_NODE *node)
#define MSGCAT_RUNTIME_DELETE_EMPTY
#define MSGCAT_RUNTIME_NO_EXPR_TO_EVALUATE
PT_NODE * parser_init_node(PT_NODE *node, PT_NODE_TYPE node_type)
PT_NODE * vquery_for_update_in_gdb
Definition: parse_tree.h:1731
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
static void error(const char *msg)
Definition: gencat.c:331
#define PT_NODE_MOVE_NUMBER_OUTERLINK(t, s)
Definition: parse_tree.h:572
void parser_free_node(const PARSER_CONTEXT *parser, PT_NODE *node)
Definition: parse_tree.c:869
static int rc
Definition: serial.c:50
#define MSGCAT_SEMANTIC_INDEX_HINT_CONFLICT
PT_NODE * pt_union(PARSER_CONTEXT *parser_ptr, PT_NODE *expression1, PT_NODE *expression2)
PT_NODE * check_where
Definition: parse_tree.h:2867
static PT_NODE * mq_reset_specs_from_column(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *column)
bool db_value_is_null(const DB_VALUE *value)
short db_value_is_initialized
Definition: parse_tree.h:3060
PT_SORT_SPEC_INFO sort_spec
Definition: parse_tree.h:3343
DB_AUTH
Definition: dbtype_def.h:239
static PT_NODE * mq_rewrite_order_dependent_nodes(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *select, int *unique)
struct parser_context * sm_virtual_queries(PARSER_CONTEXT *parser, DB_OBJECT *class_object)
static bool mq_check_cycle(DB_OBJECT *class_object)
PT_NODE * index_ls
Definition: parse_tree.h:2699
bool er_has_error(void)
bool pt_name_equal(PARSER_CONTEXT *parser, const PT_NODE *name1, const PT_NODE *name2)
static void mq_invert_insert_subquery(PARSER_CONTEXT *parser, PT_NODE **attr, PT_NODE *subquery)
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
#define AU_ENABLE(save)
Definition: authenticate.h:113
#define pt_is_distinct(n)
Definition: parse_tree.h:279
static PT_NODE * mq_translate_paths(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *root_spec)
void pt_no_attr_and_meta_attr_updates(PARSER_CONTEXT *parser, PT_NODE *stmt)
PT_NODE * pt_resolve_names(PARSER_CONTEXT *parser, PT_NODE *statement, SEMANTIC_CHK_INFO *sc_info)
PT_NODE * into
Definition: parse_tree.h:2923
#define MSGCAT_SET_PARSER_SEMANTIC
PT_NODE * spec
void pt_try_remove_order_by(PARSER_CONTEXT *parser, PT_NODE *query)
PT_NODE * pt_set_is_view_spec(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
int er_errid_if_has_error(void)
PT_NODE * using_index
Definition: parse_tree.h:2863
#define free_and_init(ptr)
Definition: memory_alloc.h:147
int mq_evaluate_expression(PARSER_CONTEXT *parser, PT_NODE *expr, DB_VALUE *value, DB_OBJECT *object, UINTPTR spec_id)
struct pt_merge_info::@126 insert
#define PT_IS_EXPR_NODE(n)
Definition: parse_tree.h:305
#define strlen(s1)
Definition: intl_support.c:43
#define MSGCAT_RUNTIME_INSERT_EMPTY
void pt_no_double_insert_assignments(PARSER_CONTEXT *parser, PT_NODE *stmt)
bool sm_is_reuse_oid_class(MOP op)
static PT_NODE * mq_push_arg2(PARSER_CONTEXT *parser, PT_NODE *query, PT_NODE *dot_arg2)
PT_NODE * attr_list
Definition: parse_tree.h:2937
UINTPTR pt_find_id(PARSER_CONTEXT *parser, PT_NODE *tree_with_names, UINTPTR id)
#define PT_SELECT_INFO_READ_ONLY
Definition: parse_tree.h:2733
#define PT_SELECT_INFO_SET_FLAG(s, f)
Definition: parse_tree.h:2737
PT_NODE * connect_by
Definition: parse_tree.h:2689
static void mq_set_union_query(PARSER_CONTEXT *parser, PT_NODE *statement, PT_MISC_TYPE is_union)
#define PT_SELECT_FULL_INFO_COLS_SCHEMA
Definition: parse_tree.h:2722
static PT_NODE * mq_fetch_subqueries_for_update_local(PARSER_CONTEXT *parser, PT_NODE *class_, PT_FETCH_AS fetch_as, DB_AUTH what_for, PARSER_CONTEXT **qry_cache)
DB_OBJECT * virt_object
Definition: parse_tree.h:2040
#define PT_IS_FUNCTION(n)
Definition: parse_tree.h:311
struct pt_function_info::@122 analytic
static PT_NODE * mq_check_non_updatable_vclass_oid(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static void pt_copypush_terms(PARSER_CONTEXT *parser, PT_NODE *spec, PT_NODE *query, PT_NODE *term_list, FIND_ID_TYPE type)
PT_NODE * search_cond
Definition: parse_tree.h:2063
PT_NODE * pt_pointer_stack_push(PARSER_CONTEXT *parser, PT_NODE *stack, PT_NODE *node)
PT_NODE * start_with
Definition: parse_tree.h:2690
int db_dget(DB_OBJECT *obj, DB_ATTDESC *attribute, DB_VALUE *value)
Definition: db_obj.c:889
PT_NODE * select_stack
Definition: parse_tree.h:3377
PT_NODE * attrs
Definition: parse_tree.h:1727
PT_NODE * after_cb_filter
Definition: parse_tree.h:2691
PT_MISC_TYPE only_all
Definition: parse_tree.h:2145
#define MSGCAT_RUNTIME_VASG_TGT_UNINVERTBL
PT_MISC_TYPE list_type
Definition: parse_tree.h:2324
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2146
#define PT_IS_N_COLUMN_UPDATE_EXPR(n)
Definition: parse_tree.h:422
static PT_NODE * mq_mark_location(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
unsigned cannot_prepare
Definition: parse_tree.h:3462
PT_DELETE_INFO delete_
Definition: parse_tree.h:3285
static PT_NODE * mq_set_names_dbobject(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * mq_oid(PARSER_CONTEXT *parser, PT_NODE *spec)
void * etc
Definition: parse_tree.h:3450
PT_NODE * mq_regenerate_if_ambiguous(PARSER_CONTEXT *parser, PT_NODE *spec, PT_NODE *statement, PT_NODE *from)
PT_NODE * pt_get_subquery_of_insert_select(const PT_NODE *insert_statement)
PT_NODE * error_msgs
Definition: parse_tree.h:3550
#define PT_IS_ORDER_DEPENDENT(n)
Definition: parse_tree.h:482
char * parser_print_tree(PARSER_CONTEXT *parser, const PT_NODE *node)
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
PT_NODE * spec
Definition: parse_tree.h:2061
PT_NODE * ordered
Definition: parse_tree.h:2695
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
static PT_NODE * mq_reset_spec_distr_subpath_post(PARSER_CONTEXT *parser, PT_NODE *spec, void *void_arg, int *continue_walk)
#define PT_SELECT_INFO_CLEAR_FLAG(s, f)
Definition: parse_tree.h:2739
int pt_length_of_select_list(PT_NODE *list, int hidden_col)
int db_make_null(DB_VALUE *value)
PT_NODE * others_spec_list
PT_NODE * list
Definition: parse_tree.h:2685
PT_NODE * use_merge
Definition: parse_tree.h:2700
DB_QUERY_SPEC * db_get_query_specs(DB_OBJECT *obj)
Definition: db_virt.c:608
PT_OP_TYPE op
Definition: parse_tree.h:2200
#define pt_is_set_type(n)
Definition: parse_tree.h:267
#define MSGCAT_RUNTIME_UPDATE_EMPTY
PT_NODE * path_conjuncts
Definition: parse_tree.h:2139
static int mq_copypush_sargable_terms(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
PT_NODE * orderby_for
Definition: parse_tree.h:2770
static int pt_for_update_prepare_query_internal(PARSER_CONTEXT *parser, PT_NODE *query)
#define MSGCAT_RUNTIME_IS_NOT_AUTHORIZED_ON
unsigned is_value_query
Definition: parse_tree.h:3478
#define PT_INTERNAL_ERROR(parser, what)
Definition: parse_tree.h:112
int mq_get_expression(DB_OBJECT *object, const char *expr, DB_VALUE *value)
static int mq_check_subqueries_for_prepare(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *subquery)
static PT_NODE * pt_check_pushable(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
PT_NODE * pt_cnf(PARSER_CONTEXT *parser, PT_NODE *node)
Definition: cnf.c:941
int pt_coerce_value(PARSER_CONTEXT *parser, PT_NODE *src, PT_NODE *dest, PT_TYPE_ENUM desired_type, PT_NODE *elem_type_list)
#define pt_has_error(parser)
Definition: parser.h:507
static int pt_for_update_prepare_query(PARSER_CONTEXT *parser, PT_NODE *query)
static PT_NODE * mq_lambda_node_pre(PARSER_CONTEXT *parser, PT_NODE *tree, void *void_arg, int *continue_walk)
PT_NODE * vquery_for_query
Definition: parse_tree.h:1728
PT_NODE * mq_reset_ids_in_methods(PARSER_CONTEXT *parser, PT_NODE *statement)
const char * alias_print
Definition: parse_tree.h:3455
PT_NODE * pt_add_table_name_to_from_list(PARSER_CONTEXT *parser, PT_NODE *select, const char *table_name, const char *table_alias, const DB_AUTH auth_bypass)
void pt_mark_spec_list_for_update(PARSER_CONTEXT *parser, PT_NODE *statement)
const char * resolved
Definition: parse_tree.h:2545
#define PT_CLEAR_JMP_ENV(parser)
Definition: parse_tree.h:107
PT_NODE * mq_get_references(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
#define PT_SELECT_INFO_FOR_UPDATE
Definition: parse_tree.h:2730
PT_NODE * check_where
Definition: parse_tree.h:2704
static PT_NODE * mq_coerce_resolved(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * mq_reset_ids_in_statement(PARSER_CONTEXT *parser, PT_NODE *statement)
PT_NODE * using_clause
Definition: parse_tree.h:2924
const char * mq_generate_name(PARSER_CONTEXT *parser, const char *root, int *version)
static PT_NODE * mq_flatten_union(PARSER_CONTEXT *parser, PT_NODE *statement)
PT_NODE * use_nl
Definition: parse_tree.h:2696
static PT_NODE * mq_rename_resolved(PARSER_CONTEXT *parser, PT_NODE *spec, PT_NODE *statement, const char *newname)
static PT_NODE * mq_bump_order_dep_corr_lvl_post(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static void mq_push_dot_in_query(PARSER_CONTEXT *parser, PT_NODE *query, int i, PT_NODE *name)
#define PT_EXPR_INFO_CLEAR_FLAG(e, f)
Definition: parse_tree.h:2240
int mq_get_attribute(DB_OBJECT *vclass_object, const char *attr_name, DB_OBJECT *real_class_object, DB_VALUE *virtual_value, DB_OBJECT *real_instance)
PT_NODE * name_list
PT_NODE * pt_dbval_to_value(PARSER_CONTEXT *parser, const DB_VALUE *val)
Definition: parse_dbi.c:574
PT_NODE * mq_optimize(PARSER_CONTEXT *parser, PT_NODE *statement)
static bool mq_mark_order_dependent_nodes(PT_NODE *node)
UINTPTR spec_ident
Definition: parse_tree.h:3451
struct mq_bump_core_info MQ_BUMP_CORR_INFO
PT_NODE * pt_invert(PARSER_CONTEXT *parser, PT_NODE *name_expr, PT_NODE *result)
PT_MISC_TYPE is_subinsert
Definition: parse_tree.h:2336
static PT_NODE * mq_translate_delete(PARSER_CONTEXT *parser, PT_NODE *delete_statement)
int column_number
Definition: parse_tree.h:3442
struct parser_node::@132 flag
PT_NODE * entity_name
Definition: parse_tree.h:2130
static void mq_push_paths_select(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
static int pt_check_for_update_clause(PARSER_CONTEXT *parser, PT_NODE *query, bool root)
PT_NODE * mq_reset_ids(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
PT_NODE * mq_set_references(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
static void mq_check_merge(PARSER_CONTEXT *parser, PT_NODE *merge_statement)
PT_SELECT_INFO select
Definition: parse_tree.h:2781
DB_VALUE * pt_value_to_db(PARSER_CONTEXT *parser, PT_NODE *value)
Definition: parse_dbi.c:1088
int db_check_authorization(MOP op, DB_AUTH auth)
Definition: db_admin.c:1848
PT_FETCH_AS
static PT_NODE * mq_rewrite_agg_names(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_INSERT_INFO insert
Definition: parse_tree.h:3309
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)
static PT_NODE * mq_reset_ids_and_references_helper(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec, bool get_spec_referenced_attr)
static PT_NODE * mq_reset_spec_ids(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * spec_parent
Definition: parse_tree.h:3421
static int mq_is_union_translation(PARSER_CONTEXT *parser, PT_NODE *spec)
PT_NODE * pt_type_cast_vclass_query_spec_column(PARSER_CONTEXT *parser, PT_NODE *attr, PT_NODE *col)
PT_NODE * parser_copy_tree_list(PARSER_CONTEXT *parser, PT_NODE *tree)
static bool mq_is_pushable_subquery(PARSER_CONTEXT *parser, PT_NODE *query, bool is_only_spec)
#define MSGCAT_RUNTIME_REL_RESTRICTS_AGG_2
const char ** p
Definition: dynamic_load.c:945
PT_NODE * mq_lambda(PARSER_CONTEXT *parser, PT_NODE *tree_with_names, PT_NODE *name_node, PT_NODE *corresponding_tree)
static PT_NODE * mq_fetch_select_for_real_class_update(PARSER_CONTEXT *parser, PT_NODE *vclass, PT_NODE *real_class, PT_FETCH_AS fetch_as, DB_AUTH what_for)
#define PT_ERRORmf(parser, node, setNo, msgNo, arg1)
Definition: parse_tree.h:64
#define PT_SET_ORDER_DEPENDENT_FLAG(n, f)
Definition: parse_tree.h:500
static PT_NODE * mq_derived_path(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *path)
unsigned is_hidden_column
Definition: parse_tree.h:3470
PT_JOIN_TYPE join_type
Definition: parse_tree.h:2151
PT_NODE ** sub_paths
#define PT_NAME_GENERATED_DERIVED_SPEC
Definition: parse_tree.h:2569
static PT_NODE * mq_fetch_one_real_class_get_cache(DB_OBJECT *vclass_object, PARSER_CONTEXT **query_cache)
PT_NODE * spec
int search(int &result, const cub_regex_object &reg, const std::string &src, const INTL_CODESET codeset)
PT_NODE * derived_table
Definition: parse_tree.h:2134
PT_NODE * search_cond
Definition: parse_tree.h:2862
PT_NODE * range_var
Definition: parse_tree.h:2135
static PT_NODE * mq_referenced_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * mq_fetch_subqueries(PARSER_CONTEXT *parser, PT_NODE *class_)
bool mq_is_updatable_att(PARSER_CONTEXT *parser, DB_OBJECT *vmop, const char *att_nam, DB_OBJECT *rmop)
DB_QUERY_SPEC * db_query_spec_next(DB_QUERY_SPEC *query_spec)
Definition: db_virt.c:632