CUBRID Engine  latest
method_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  * method_transform.c - Rewrite queries that contain method calls
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include "authenticate.h"
28 #include "porting.h"
29 #include "error_manager.h"
30 #include "parser.h"
31 #include "parser_message.h"
32 #include "view_transform.h"
33 #include "dbtype.h"
34 
35 typedef struct meth_lambda METH_LAMBDA;
37 {
38  UINTPTR method_id; /* method id of calls to replace */
39  PT_NODE *replacement; /* node to replace method calls with */
40  PT_NODE *new_spec; /* the new spec that was generated for the call */
41 };
42 
45 {
46  PT_NODE *root; /* ptr to original statement */
47  PT_NODE *select_statement; /* ptr to current statement */
48 };
49 
52 {
53  UINTPTR spec_id; /* spec id of spec we are expanding/collapsing */
54  int corr_step; /* amount to bump correlation */
55  int corr_threshold; /* correlation threshold which defines which correlations need to be bumped. */
56 };
57 
58 typedef struct meth_info METH_INFO;
59 struct meth_info
60 {
61  PT_NODE *method; /* method we are finding the entity of */
62  PT_NODE *entity_for_method; /* the entity where we'll hang the method */
63  int nesting_depth; /* depth of current nesting level */
64  int entities_nesting_depth; /* depth of the entity */
65 };
66 
67 typedef struct meth_info1 METH_INFO1;
68 struct meth_info1
69 {
70  UINTPTR id; /* spec_id or method_id we're looking for */
71  int found; /* whether we've found it */
72 };
73 
74 typedef struct meth_info2 METH_INFO2;
75 struct meth_info2
76 {
77  PT_NODE *root; /* top node for the statement */
78  int methods_to_translate; /* whether there are methods to translate */
79 };
80 
81 typedef struct meth_info3 METH_INFO3;
82 struct meth_info3
83 {
84  PT_NODE *entity; /* ptr to entity if found, NULL otherwise */
85  UINTPTR id; /* id of entity to find */
86 };
87 
88 typedef struct meth_info4 METH_INFO4;
89 struct meth_info4
90 {
91  PT_NODE *spec_list; /* specs at current level */
92  UINTPTR id; /* id of entity we're interested in */
93  int found; /* whether we've found it */
94 };
95 
96 typedef struct meth_info5 METH_INFO5;
97 struct meth_info5
98 {
99  PT_NODE *new_where; /* where clause we are building */
100  UINTPTR spec_id; /* id of conjuncts we are interested in */
101 };
102 
103 typedef struct meth_info6 METH_INFO6;
105 {
106  UINTPTR old_id; /* id to replace */
107  UINTPTR new_id; /* id to replace it with */
108 };
109 
110 typedef struct meth_info7 METH_INFO7;
112 {
113  UINTPTR id; /* spec_id or method_id we're looking for */
114  int found; /* whether we've found it */
115  int check_method_calls; /* dive into method calls to look? */
116 };
117 
118 static int meth_table_number = 0; /* for unique table names */
119 static int meth_attr_number = 0; /* for unique attribute names */
120 
122 static PT_NODE *meth_translate_local (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk);
123 static PT_NODE *meth_create_method_list (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
124 static PT_NODE *meth_translate_select (PARSER_CONTEXT * parser, PT_NODE * select_statement, PT_NODE * root);
125 static PT_NODE *meth_translate_spec (PARSER_CONTEXT * parser, PT_NODE * spec, void *void_arg, int *continue_walk);
126 static PT_NODE *meth_collapse_nodes (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
127 static PT_NODE *meth_get_method_params (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE * method_list, int *num);
129 static PT_NODE *meth_gen_as_attr_list (PARSER_CONTEXT * parser, PT_NODE * range_var, UINTPTR spec_id,
130  PT_NODE * attr_list);
131 static void meth_replace_method_params (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE * method_list,
132  PT_NODE * as_attr_list);
133 static void meth_replace_method_calls (PARSER_CONTEXT * parser, PT_NODE * root, PT_NODE * method_list,
134  PT_NODE * as_attr_list, PT_NODE * new_spec, int num_methods);
135 static PT_NODE *meth_replace_call (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
136 static void meth_replace_referenced_attrs (PARSER_CONTEXT * parser, PT_NODE * root, PT_NODE * attr_list,
137  PT_NODE * as_attr_list, int num);
138 static PT_NODE *meth_find_last_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
139 static PT_NODE *meth_find_last_entity_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg,
140  int *continue_walk);
141 static PT_NODE *meth_match_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
142 static PT_NODE *meth_find_outside_refs (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
143 static void meth_bump_correlation_level (PARSER_CONTEXT * parser, PT_NODE * node, int increment, int threshold,
144  UINTPTR spec_id);
145 static PT_NODE *meth_bump_corr_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
146 static PT_NODE *meth_bump_corr_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
147 static PT_NODE *meth_find_merge (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
148 static PT_NODE *meth_is_method (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
151 static PT_NODE *meth_find_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
152 static PT_NODE *meth_find_method (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
153 static PT_NODE *meth_find_outside_refs_subquery (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg,
154  int *continue_walk);
155 static PT_NODE *meth_push_conjuncts (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE ** where);
156 static PT_NODE *meth_grab_conj (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk);
157 static void meth_grab_cnf_conj (PARSER_CONTEXT * parser, PT_NODE ** where, METH_INFO5 * info5);
158 static PT_NODE *meth_add_conj (PARSER_CONTEXT * parser, PT_NODE * where, PT_NODE * new_conj);
159 static PT_NODE *meth_replace_id_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg,
160  int *continue_walk);
161 static int meth_refs_to_scope (PARSER_CONTEXT * parser, PT_NODE * scope, PT_NODE * tree);
162 static PT_NODE *meth_have_methods (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
163 static PT_NODE *meth_find_hierarchical_op (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
165  bool * has_hierarchical_expr);
166 static void meth_copy_hierarchical_expr_to_list (PARSER_CONTEXT * parser, PT_NODE * src_list, PT_NODE ** dst_list_p,
167  int *copy_count);
169  PT_SELECT_INFO * derived_info);
170 static void meth_replace_hierarchical_exprs (PARSER_CONTEXT * parser, PT_NODE ** select_list_p, PT_NODE * ref_attrs,
171  int num_methods);
172 
173 /*
174  * meth_have_methods() -
175  * return:
176  * parser(in):
177  * node(in):
178  * arg(in/out):
179  * continue_walk(in/out):
180  */
181 static PT_NODE *
182 meth_have_methods (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
183 {
184  int *have_method = (int *) arg;
185 
186  *continue_walk = PT_CONTINUE_WALK;
187  if (node->node_type == PT_METHOD_CALL)
188  {
189  *have_method = 1;
190  *continue_walk = PT_STOP_WALK;
191  }
192 
193  return node;
194 }
195 
196 
197 /*
198  * pt_statement_have_methods() -
199  * return: 1 on methods exists
200  * parser(in):
201  * statement(in):
202  */
203 int
205 {
206  int have_method = 0;
207 
208  if (!statement)
209  {
210  return 0;
211  }
212 
213  parser_walk_tree (parser, statement, NULL, NULL, meth_have_methods, &have_method);
214 
215  return have_method;
216 }
217 
218 /*
219  * meth_translate() - Recursively translates queries with methods
220  * return:
221  * parser(in):
222  * node(in/out): Query to translate
223  */
224 PT_NODE *
226 {
227  int hand_rewritten;
228  PT_NODE *next;
229 
230  if (!node)
231  {
232  return NULL;
233  }
234 
235  /* set spec_ident for terms */
236  node = parser_walk_tree (parser, node, NULL, NULL, pt_do_cnf, NULL);
237 
238  /* don't translate if it is a hand re-written query using our exposed syntax for debugging purposes. */
239  hand_rewritten = 0;
240  (void) parser_walk_tree (parser, node, meth_find_merge, &hand_rewritten, NULL, NULL);
241 
242  if (hand_rewritten)
243  {
244  goto exit_on_done;
245  }
246 
247  /* set up an environment for longjump to return to if there is an out of memory error in pt_memory.c. DO NOT RETURN
248  * unless PT_CLEAR_JMP_ENV is called to clear the environment. */
249  PT_SET_JMP_ENV (parser);
250 
251  /* save next link */
252  next = node->next;
253  node->next = NULL;
254 
255  node = meth_translate_helper (parser, node);
256  if (node)
257  {
258  if (pt_has_error (parser))
259  {
260  node = NULL;
261  }
262  else
263  {
264  node->next = next; /* restore link */
265  }
266  }
267 
268  PT_CLEAR_JMP_ENV (parser);
269 
270 exit_on_done:
271 
272  return node;
273 }
274 
275 /*
276  * meth_translate_helper() -
277  * return:
278  * parser(in):
279  * node(in/out):
280  */
281 static PT_NODE *
283 {
284  PT_NODE *spec, *derived_table, *elm;
285  METH_INFO2 info2;
286 
287  if (!node)
288  {
289  return NULL;
290  }
291 
292  /* only translate translatable statements */
293  switch (node->node_type)
294  {
295  case PT_UNION:
296  case PT_DIFFERENCE:
297  case PT_INTERSECTION:
298  node->info.query.q.union_.arg1 = meth_translate_helper (parser, node->info.query.q.union_.arg1);
299  node->info.query.q.union_.arg2 = meth_translate_helper (parser, node->info.query.q.union_.arg2);
300  break;
301 
302  case PT_SELECT:
303  /* get entity list */
304  for (spec = node->info.query.q.select.from; spec; spec = spec->next)
305  {
306  derived_table = spec->info.spec.derived_table;
307  if (derived_table)
308  {
309  switch (spec->info.spec.derived_table_type)
310  {
311  case PT_IS_SUBQUERY:
312  elm = derived_table;
313  break;
314 
315  case PT_IS_SET_EXPR:
316  if (pt_is_query (derived_table))
317  {
318  elm = derived_table;
319  }
320  else if (derived_table->node_type == PT_VALUE)
321  {
322  elm = derived_table->info.value.data_value.set;
323  }
324  else if (derived_table->node_type == PT_FUNCTION)
325  {
326  elm = derived_table->info.function.arg_list;
327  }
328  else
329  {
330  /* skip and go ahead for example: use parameter case create class x; -- set audit all on x;
331  * create class z (i int, xs sequence(x)); select xs into p from z where i = 312; select s from
332  * table(p) as t(s); ---> at here, the second select statement is in here */
333  elm = NULL;
334  }
335  break;
336 
337  default:
338  elm = NULL;
339  break;
340  } /* switch (spec->info.spec.derived_table_type) */
341 
342  /* dive into the derived-subquery */
343  for (; elm; elm = elm->next)
344  {
345  elm = meth_translate_helper (parser, elm);
346  if (!elm || pt_has_error (parser))
347  {
348  /* exit immediately */
349  goto exit_on_error;
350  }
351  }
352  }
353  }
354 
355  /* METHOD TRANSLATE */
356  /* put methods on the target entity spec's method list */
357  info2.methods_to_translate = 0;
358  info2.root = node;
359  (void) parser_walk_tree (parser, node, NULL, NULL, meth_create_method_list, &info2);
360 
361  if (!info2.methods_to_translate)
362  { /* not found method, do nothing */
363  break;
364  }
365 
366  while (info2.methods_to_translate)
367  {
368  /* translate statement */
369  node = parser_walk_tree (parser, node, NULL, NULL, meth_translate_local, node);
370  /* error check */
371  if (pt_has_error (parser))
372  { /* exit immediately */
373  goto exit_on_error;
374  }
375 
376  /* Recalculate method_lists for nested method calls */
377  info2.methods_to_translate = 0;
378  info2.root = node;
379  (void) parser_walk_tree (parser, node, NULL, NULL, meth_create_method_list, &info2);
380  } /* while (info2.methods_to_translate) */
381 
382  /* collapse unnecessary SELECT/MERGE combinations */
383  node = parser_walk_tree (parser, node, NULL, NULL, meth_collapse_nodes, NULL);
384 
385  break;
386 
387  default:
388  break;
389  } /* switch (node->node_type) */
390 
391  return node;
392 
393 exit_on_error:
394 
395  return NULL;
396 }
397 
398 
399 /*
400  * meth_translate_local() -
401  * return:
402  * parser(in):
403  * statement(in/out): statement to translate
404  * void_arg(in): a PT_NODE that is the root of the whole statement
405  * continue_walk(in/out):
406  */
407 static PT_NODE *
408 meth_translate_local (PARSER_CONTEXT * parser, PT_NODE * statement, void *void_arg, int *continue_walk)
409 {
410  PT_NODE *root = (PT_NODE *) void_arg;
411  int line, column;
412  PT_NODE *save_statement;
413 
414  /* we only translate SELECTS */
415  if (!statement || (statement->node_type != PT_SELECT))
416  {
417  return statement;
418  }
419 
420  /* try to track original source line and column */
421  line = statement->line_number;
422  column = statement->column_number;
423  save_statement = statement;
424 
425  statement = meth_translate_select (parser, statement, root);
426 
427  if (statement == NULL || pt_has_error (parser))
428  {
429  statement = save_statement; /* restore to old parse tree */
430  *continue_walk = PT_STOP_WALK;
431  }
432  else
433  {
434  statement->line_number = line;
435  statement->column_number = column;
436  }
437 
438  return statement;
439 }
440 
441 
442 /*
443  * meth_create_method_list() - Put method calls on the method_list for
444  * the entity their target resolved to
445  * return:
446  * parser(in):
447  * node(in/out):
448  * void_arg(in):
449  * continue_walk(in/out):
450  */
451 static PT_NODE *
452 meth_create_method_list (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
453 {
454  METH_INFO2 *info2 = (METH_INFO2 *) void_arg;
455  PT_NODE *new_method;
456  PT_NODE *arg1;
457  METH_INFO info;
458  int nested_methods;
459  METH_INFO3 info3;
460 
461  *continue_walk = PT_CONTINUE_WALK;
462 
463  /* don't walk CSELECT lists */
464  if (node->node_type == PT_SPEC && node->info.spec.derived_table
466  {
467  *continue_walk = PT_LIST_WALK;
468  }
469 
470  if (node->node_type == PT_DOT_ && (arg1 = node->info.dot.arg1) && arg1->node_type == PT_METHOD_CALL
471  && arg1->info.method_call.call_or_expr == PT_PARAMETER && node->info.dot.arg2)
472  {
473  /* this is a path expression rooted in a constant method call. We need to tag it as such for xasl generation */
475  }
476 
477  if ((node->node_type != PT_METHOD_CALL) || (node->info.method_call.method_name->info.name.spec_id == 0))
478  {
479  return node;
480  }
481 
482 
483  /* check for nested method calls */
484  nested_methods = 0;
485  parser_walk_leaves (parser, node, meth_is_method, &nested_methods, NULL, NULL);
486 
487  if (nested_methods)
488  {
489  return node;
490  }
491 
492  new_method = parser_copy_tree (parser, node);
493  if (new_method == NULL)
494  {
495  return NULL;
496  }
497 
498  /* don't keep finding this method, since we are copying it */
499  new_method->info.method_call.method_name->info.name.spec_id = 0;
500 
501  info3.entity = NULL;
502  info3.id = node->info.method_call.method_name->info.name.spec_id;
503  (void) parser_walk_tree (parser, info2->root, meth_find_entity, &info3, NULL, NULL);
504 
505  info.method = new_method;
506  info.entity_for_method = NULL;
507  info.nesting_depth = 0;
508  info.entities_nesting_depth = 0;
509  (void) parser_walk_tree (parser, info2->root, meth_find_last_entity, &info, meth_find_last_entity_post, &info);
510 
511  if (!info.entity_for_method)
512  {
513  /* This case can arise when the target of the method call is a parameter and the arg_list contains PT_VALUE
514  * and/or parameter nodes. In this case use the entity the method name resolves to for the method. */
515  info.entity_for_method = info3.entity;
516  }
517 
518  if (!info.entity_for_method)
519  {
521  if (new_method)
522  {
523  parser_free_tree (parser, new_method);
524  }
525  }
526  else
527  {
528  info2->methods_to_translate = 1; /* we found at least one */
529 
532  }
533 
534  return node;
535 }
536 
537 
538 /*
539  * meth_translate_select() - Translate the select statement with method calls
540  * return:
541  * parser(in):
542  * select_statement(in/out): select statement to translate
543  * root(in): top node of the whole statement
544  */
545 static PT_NODE *
547 {
548  METH_STMT_INFO info;
549  PT_NODE *save_from;
550 
551  info.root = root;
552  info.select_statement = select_statement;
553 
554  /* translate any entity spec with method calls to a MERGE */
555  save_from = select_statement->info.query.q.select.from; /* save */
556  select_statement->info.query.q.select.from =
557  parser_walk_tree (parser, select_statement->info.query.q.select.from, NULL, NULL, meth_translate_spec, &info);
558 
559  if (pt_has_error (parser))
560  {
561  /* restore to old parse tree */
562  select_statement->info.query.q.select.from = save_from;
563  return NULL;
564  }
565  return select_statement;
566 }
567 
568 
569 /*
570  * meth_translate_spec() - Replaces entity specs whose objects are the
571  * targets for method calls with a MERGE statement
572  * return:
573  * parser(in):
574  * spec(in/out): entity spec to translate
575  * void_arg(in): root of the whole statement to allow us to replace
576  * method calls with their new derived table attributes
577  * continue_walk(in/out): flag to control tree walking
578  */
579 static PT_NODE *
580 meth_translate_spec (PARSER_CONTEXT * parser, PT_NODE * spec, void *void_arg, int *continue_walk)
581 {
582  METH_STMT_INFO *info = (METH_STMT_INFO *) void_arg;
583  PT_NODE *merge;
584  PT_NODE *table1, *table2;
585  PT_NODE *derived1;
586  PT_NODE *new_spec;
587  PT_NODE *tmp;
588  PT_NODE *save_referenced_attrs;
589  int i;
590  int num_methods;
591  int num_method_params = 0;
592  int num_referenced_attrs;
593  int num_hierarchical_exprs = 0;
594  METH_INFO1 info1;
595  METH_INFO6 info6;
596  unsigned short derived1_correlation_level;
597  unsigned short merge_correlation_level;
598  unsigned short correlation_level;
599  PT_NODE *dummy_set_tbl;
600  PT_NODE *spec_list, **where;
601  bool has_hierarchical_expr = false;
602 
603  info1.found = 0;
604  *continue_walk = PT_LIST_WALK;
605 
606  if ((info->select_statement == NULL) || (spec->node_type != PT_SPEC) || (spec->info.spec.method_list == NULL))
607  {
608  return spec; /* nothing to translate */
609  }
610  correlation_level = info->select_statement->info.query.correlation_level;
611  spec_list = info->select_statement->info.query.q.select.from;
612  where = &info->select_statement->info.query.q.select.where;
613 
614  /* squirrel away the referenced_attrs from the original tree */
615  save_referenced_attrs = mq_get_references (parser, info->root, spec);
616 
617  /* check method calls for hierarchical expressions in arguments */
618  meth_find_hierarchical_in_method_list (parser, spec->info.spec.method_list, &has_hierarchical_expr);
619 
620  num_methods = pt_length_of_list (spec->info.spec.method_list);
621  num_referenced_attrs = pt_length_of_list (save_referenced_attrs);
622 
623  dummy_set_tbl = NULL; /* init */
624 
625  /* newly create additional dummy_set_tbl as derived1 for instance method and stored precdure. check for path-expr. */
626  if (spec->info.spec.meta_class == PT_CLASS && spec->info.spec.path_entities == NULL && !has_hierarchical_expr)
627  { /* can't handle path-expr */
628  DB_VALUE val;
629  PT_NODE *arg, *set;
630 
631  /* not derived-table spec and not meta class spec */
632  db_make_int (&val, true);
633  arg = pt_dbval_to_value (parser, &val);
634 
635  set = parser_new_node (parser, PT_FUNCTION);
636  if (set == NULL)
637  {
638  PT_INTERNAL_ERROR (parser, "allocate new node");
639  return NULL;
640  }
641 
642  set->info.function.function_type = F_SEQUENCE;
643  set->info.function.arg_list = arg;
645 
646  dummy_set_tbl = parser_new_node (parser, PT_SPEC);
647  if (dummy_set_tbl == NULL)
648  {
649  PT_INTERNAL_ERROR (parser, "allocate new node");
650  return NULL;
651  }
652 
653  dummy_set_tbl->info.spec.id = (UINTPTR) dummy_set_tbl; /* set id */
654  dummy_set_tbl->info.spec.derived_table = set;
655  dummy_set_tbl->info.spec.derived_table_type = PT_IS_SET_EXPR;
656  dummy_set_tbl->info.spec.range_var = meth_make_unique_range_var (parser, dummy_set_tbl);
657  dummy_set_tbl->info.spec.as_attr_list =
658  meth_gen_as_attr_list (parser, dummy_set_tbl->info.spec.range_var, dummy_set_tbl->info.spec.id, arg);
659  }
660  else
661  {
662  /* check for outside references for correlation level determination */
663  info1.id = spec->info.spec.id;
664  info1.found = 0;
665  for (tmp = spec->info.spec.method_list; tmp != NULL; tmp = tmp->next)
666  {
667  (void) parser_walk_tree (parser, tmp->info.method_call.arg_list, meth_find_outside_refs, &info1, NULL, NULL);
668  if (info1.found)
669  {
670  break;
671  }
673  NULL);
674  if (info1.found)
675  {
676  break;
677  }
678  }
679  }
680 
681  /* create and fill in table2 of the merge */
682  table2 = parser_new_node (parser, PT_SPEC);
683  if (table2 == NULL)
684  {
685  PT_INTERNAL_ERROR (parser, "allocate new node");
686  return NULL;
687  }
688 
689  table2->info.spec.id = (UINTPTR) table2;
690  table2->info.spec.derived_table = spec->info.spec.method_list;
691  spec->info.spec.method_list = NULL; /* take it out of main tree */
692  table2->info.spec.range_var = meth_make_unique_range_var (parser, table2);
693  table2->info.spec.as_attr_list =
694  meth_gen_as_attr_list (parser, table2->info.spec.range_var, table2->info.spec.id, table2->info.spec.derived_table);
696  for (tmp = table2->info.spec.as_attr_list; tmp != NULL; tmp = tmp->next)
697  {
698  tmp->info.name.resolved = NULL;
699  }
701 
702  /* create and fill in the innermost derived statement */
703  derived1 = parser_new_node (parser, PT_SELECT);
704  if (derived1 == NULL)
705  {
706  PT_INTERNAL_ERROR (parser, "allocate new node");
707  return NULL;
708  }
709 
710  derived1->info.query.q.select.flavor = PT_USER_SELECT;
711  derived1->info.query.is_subquery = PT_IS_SUBQUERY;
712 
713  if (dummy_set_tbl)
714  { /* now, generate new spec */
715  derived1->info.query.q.select.from = dummy_set_tbl;
716 
717  derived1_correlation_level = 2;
718  }
719  else
720  {
721  derived1->info.query.q.select.from = parser_copy_tree (parser, spec);
722 
723  if (info1.found)
724  { /* found outside references */
725  derived1_correlation_level = 2;
726  }
727  else
728  {
729  PT_NODE *sub_der;
730  unsigned short sub_corr_level = 0; /* init */
731 
732  sub_der = spec->info.spec.derived_table;
733  if (sub_der != NULL)
734  {
735  switch (spec->info.spec.derived_table_type)
736  {
737  case PT_IS_SUBQUERY:
738  sub_corr_level = sub_der->info.query.correlation_level;
739  break;
740  case PT_IS_SET_EXPR:
741  /* KLUDGE ALERT!!! Until we have correlation level info for set expression derived tables, we can
742  * check for no correlation, and correlation to this level. Correlation to outer scopes we can't
743  * handle. */
744  if (sub_der->node_type == PT_SELECT)
745  {
746  sub_corr_level = sub_der->info.query.correlation_level;
747  }
748  else if (meth_refs_to_scope (parser, spec_list, sub_der))
749  {
750  sub_corr_level = 1;
751  }
752  else
753  { /* check for outside refs */
754  METH_INFO4 info4;
755 
756  info4.found = 0;
757  info4.id = spec->info.spec.id;
758  info4.spec_list = spec_list;
759  (void) parser_walk_tree (parser, sub_der, meth_find_outside_refs_subquery, &info4, NULL, NULL);
760  if (info4.found)
761  {
762  /* raise error -- can't currently deal with this */
764 
765  parser_free_tree (parser, derived1);
766  parser_free_tree (parser, table2);
767  parser_free_tree (parser, save_referenced_attrs);
768 
769  *continue_walk = PT_STOP_WALK;
770  return spec;
771  }
772  }
773  break;
774  default:
775  break;
776  }
777  }
778 
779  if (sub_corr_level)
780  {
781  derived1_correlation_level = sub_corr_level + 1;
782  }
783  else
784  {
785  derived1_correlation_level = correlation_level;
786  }
787  }
788  }
789  merge_correlation_level = MAX (derived1_correlation_level - 1, 0);
790 
791  /* remove un-replaced outer join relation; recover later */
793  if (derived1->info.query.q.select.from->info.spec.on_cond)
794  {
795  parser_free_tree (parser, derived1->info.query.q.select.from->info.spec.on_cond);
796  derived1->info.query.q.select.from->info.spec.on_cond = NULL;
797  }
798  derived1->info.query.q.select.from->info.spec.method_list = NULL;
799  derived1->info.query.q.select.list =
800  meth_get_method_params (parser, spec->info.spec.id, table2->info.spec.derived_table, &num_method_params);
801  if (has_hierarchical_expr)
802  {
803  /* copy all hierarchical expressions from select list to derived */
805  &derived1->info.query.q.select.list, &num_hierarchical_exprs);
806  }
807  derived1->info.query.q.select.list =
808  parser_append_node (parser_copy_tree_list (parser, save_referenced_attrs), derived1->info.query.q.select.list);
811  derived1->info.query.correlation_level = derived1_correlation_level;
812  if (has_hierarchical_expr)
813  {
814  /* move hierarchical query to derived */
816  &derived1->info.query.q.select);
817  }
818 
819  /* create and fill in table1 of the merge */
820  table1 = parser_new_node (parser, PT_SPEC);
821  if (table1 == NULL)
822  {
823  PT_INTERNAL_ERROR (parser, "allocate new node");
824  return NULL;
825  }
826 
827  table1->next = table2;
828  table1->info.spec.id = (UINTPTR) table1;
829  table1->info.spec.derived_table = derived1;
830  table1->info.spec.range_var = meth_make_unique_range_var (parser, table1);
831  table1->info.spec.as_attr_list =
832  meth_gen_as_attr_list (parser, table1->info.spec.range_var, table1->info.spec.id,
833  derived1->info.query.q.select.list);
835  for (tmp = table1->info.spec.as_attr_list; tmp != NULL; tmp = tmp->next)
836  {
837  tmp->info.name.resolved = NULL;
838  }
840 
841  /* If original spec was a derived table, we need to adjust correlations of nested queries. Also need to adjust
842  * correlations of queries that were subqueries of the method. These are found on the select list of derived1. */
843  if (dummy_set_tbl == NULL && derived1_correlation_level)
844  {
846  derived1_correlation_level - correlation_level, 1, spec->info.spec.id);
847  meth_bump_correlation_level (parser, derived1->info.query.q.select.list,
848  derived1_correlation_level - correlation_level, 1, spec->info.spec.id);
849  }
850 
851  /* create and fill in the merge node */
852  merge = parser_new_node (parser, PT_SELECT);
853  if (merge == NULL)
854  {
855  PT_INTERNAL_ERROR (parser, "allocate new node");
856  return NULL;
857  }
858 
860  merge->info.query.correlation_level = merge_correlation_level;
862  merge->info.query.q.select.from = table1;
863 
865  tmp = table1->info.spec.referenced_attrs;
866  for (i = 0; i < num_method_params; i++)
867  {
868  tmp = tmp->next; /* skip params */
869  }
870 
871  merge->info.query.q.select.list =
873  merge->type_enum = merge->info.query.q.select.list->type_enum;
874  if (merge->info.query.q.select.list->data_type)
875  {
876  merge->data_type = parser_copy_tree_list (parser, merge->info.query.q.select.list->data_type);
877  }
878 
879  /* create and fill in the new_spec */
880  new_spec = parser_new_node (parser, PT_SPEC);
881  if (new_spec == NULL)
882  {
883  PT_INTERNAL_ERROR (parser, "allocate new node");
884  return NULL;
885  }
886 
887  new_spec->next = spec->next; /* don't loose the list */
888  new_spec->info.spec.id = (UINTPTR) new_spec;
889  new_spec->info.spec.derived_table = merge;
890  new_spec->info.spec.range_var = meth_make_unique_range_var (parser, new_spec);
891  new_spec->info.spec.as_attr_list =
892  meth_gen_as_attr_list (parser, new_spec->info.spec.range_var, new_spec->info.spec.id,
893  merge->info.query.q.select.list);
894  new_spec->info.spec.referenced_attrs = parser_copy_tree_list (parser, new_spec->info.spec.as_attr_list);
895  for (tmp = new_spec->info.spec.as_attr_list; tmp != NULL; tmp = tmp->next)
896  {
897  tmp->info.name.resolved = NULL;
898  }
901  new_spec->info.spec.path_entities =
903  new_spec->info.spec.path_entities);
904 
905  /* replace the non-PT_NAME parameters of the method calls with the derived attributes from the first table of the
906  * merge. We use the referenced_attrs list instead of the as_attr_list because it has the resolved field filled in. */
907  meth_replace_method_params (parser, spec->info.spec.id, table2->info.spec.derived_table,
908  table1->info.spec.referenced_attrs);
909 
910  /* replace the PT_NAME parameters of the method calls with the derived attributes from the first table of the merge.
911  * We use the referenced attrs list instead of the as_attr_list because it has the resolved field filled in. We must
912  * first skip over the non-PT_NAME parameters. */
913  tmp = table1->info.spec.referenced_attrs;
914  for (i = 0; i < num_method_params + num_hierarchical_exprs; i++)
915  {
916  tmp = tmp->next;
917  }
918  meth_replace_referenced_attrs (parser, table2->info.spec.derived_table, save_referenced_attrs, tmp,
919  num_referenced_attrs);
920 
921  /* replace all method calls from this spec in the original statement with their new derived attributes which are
922  * first on the new_spec's as_attr_list. We use the referenced_attrs list instead of the as_attr_list because it has
923  * the resolved field filled in.
924  *
925  * * Since new_spec->info.spec.path_entities is a copy of the original spec's, we also need to replace any method
926  * calls in this tree. */
927  meth_replace_method_calls (parser, info->root, table2->info.spec.derived_table, new_spec->info.spec.referenced_attrs,
928  new_spec, num_methods);
929  /* replace hierarchical exprs in select list with derived attrs */
930  if (has_hierarchical_expr)
931  {
933  new_spec->info.spec.referenced_attrs, num_methods);
934  }
936  new_spec->info.spec.referenced_attrs, new_spec, num_methods);
937 
938  if (dummy_set_tbl == NULL)
939  {
940  /* after all methods are replaced, but before we replace references to the old spec, push the conjuncts for this
941  * spec down. */
942  derived1->info.query.q.select.where = meth_push_conjuncts (parser, spec->info.spec.id, where);
943  }
944 
945  /* now that we've finished copy stuff to the derived table, reset ids */
946  derived1 = mq_reset_paths (parser, derived1, derived1->info.query.q.select.from);
947 
948  /* replace references to the old spec's referenced_attr list with derived attrs from the new_spec's as_attr_list. We
949  * need to skip over derived attrs for the method calls. Again, we use the referenced_attrs list instead of the
950  * as_attr_list because it has the resolved field filled in.
951  *
952  * * Since table2 and new_spec path_entities are a copy of the original spec's, we also need to replace any
953  * referenced attrs in these trees. */
954  tmp = new_spec->info.spec.referenced_attrs;
955  for (i = 0; i < num_methods + num_hierarchical_exprs; i++)
956  {
957  tmp = tmp->next;
958  }
959  if (dummy_set_tbl == NULL)
960  {
961  meth_replace_referenced_attrs (parser, info->root, save_referenced_attrs, tmp, num_referenced_attrs);
962  }
963  meth_replace_referenced_attrs (parser, table2->info.spec.path_entities, save_referenced_attrs, tmp,
964  num_referenced_attrs);
965  meth_replace_referenced_attrs (parser, new_spec->info.spec.path_entities, save_referenced_attrs, tmp,
966  num_referenced_attrs);
967 
968  /* By convention, references are now computed as needed, to allow transformations and optimizations to proceed
969  * without the restriction of constantly maintaining the referenced attributes lists. */
970  parser_free_tree (parser, new_spec->info.spec.referenced_attrs);
971  new_spec->info.spec.referenced_attrs = NULL;
972  parser_free_tree (parser, table1->info.spec.referenced_attrs);
973  table1->info.spec.referenced_attrs = NULL;
974  parser_free_tree (parser, table2->info.spec.referenced_attrs);
975  table2->info.spec.referenced_attrs = NULL;
976 
977  /* re-resolve methods whose method name node resolves to the translated spec, but which didn't get translated this
978  * time. The only case where this can happen is when there is a method that doesn't reference any spec (it is a
979  * constant for the query), that has nested method calls. These methods should now be resolved to new_spec. */
980  info6.old_id = spec->info.spec.id;
981  info6.new_id = new_spec->info.spec.id;
983 
984  if (dummy_set_tbl)
985  {
986  /* We attach the new_spec to the end of the from list. */
987  new_spec->next = NULL;
988  for (tmp = spec; tmp->next != NULL; tmp = tmp->next)
989  {
990  /* No body. */
991  }
992 
993  tmp->next = new_spec;
994  new_spec = spec;
995  }
996  else
997  {
998  /* recover replaced outer join relation */
999  new_spec->info.spec.join_type = spec->info.spec.join_type;
1000  spec->info.spec.join_type = PT_JOIN_NONE;
1001  new_spec->info.spec.on_cond = spec->info.spec.on_cond;
1002  spec->info.spec.on_cond = NULL;
1003  new_spec->info.spec.location = spec->info.spec.location;
1004  }
1005 
1006  parser_free_tree (parser, save_referenced_attrs);
1007 
1008  return new_spec; /* replace the spec with the new_spec */
1009 }
1010 
1011 
1012 /*
1013  * meth_collapse_nodes() -
1014  * return:
1015  * parser(in):
1016  * node(in/out):
1017  * void_arg(in):
1018  * continue_walk(in):
1019  */
1020 static PT_NODE *
1021 meth_collapse_nodes (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1022 {
1023  PT_NODE *merge;
1024  PT_NODE *as_attrs, *sel_attrs;
1025  int num;
1026 
1027  if ((node->node_type != PT_SELECT) || !node->info.query.q.select.from
1028  || !(merge = node->info.query.q.select.from->info.spec.derived_table)
1030  || (merge->info.query.q.select.flavor != PT_MERGE_SELECT) || node->info.query.q.select.from->next)
1031  {
1032  return node;
1033  }
1034 
1035  /* if we get here its a collapsible node, so collapse it reduce the correlation level of subqueries */
1036  meth_bump_correlation_level (parser, merge->info.query.q.select.from, -1, 1,
1037  node->info.query.q.select.from->info.spec.id);
1038 
1039  /* move any path entity from the MERGE spec to the CSELECT spec */
1043 
1044  /* Replace attributes that reference the derived table with the corresponding derived table's select list attribute.
1045  * Don't forget about the path conjuncts in the path entities. */
1046  as_attrs = node->info.query.q.select.from->info.spec.as_attr_list;
1047  sel_attrs = merge->info.query.q.select.list;
1048  num = pt_length_of_list (as_attrs);
1049  node->info.query.q.select.from = NULL;
1050  meth_replace_referenced_attrs (parser, node, as_attrs, sel_attrs, num);
1052  sel_attrs, num);
1053 
1054  node->info.query.q.select.from = merge->info.query.q.select.from;
1055  node->info.query.q.select.where =
1056  meth_add_conj (parser, node->info.query.q.select.where, merge->info.query.q.select.where);
1058 
1059  /* redo cnf, since collapsing may have munged the conjunct tags */
1060  node = pt_do_cnf (parser, node, void_arg, continue_walk);
1061 
1062  return node;
1063 }
1064 
1065 
1066 /*
1067  * meth_get_method_params() - return a list of their parameters and targets
1068  * return:
1069  * parser(in):
1070  * spec_id(in): entity spec id of the entity we're replacing
1071  * method_list(out): list of methods from which to get their parameters
1072  * num(out): number of method parameters that we are adding to the list
1073  */
1074 static PT_NODE *
1075 meth_get_method_params (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE * method_list, int *num)
1076 {
1077  PT_NODE *params = NULL;
1078  PT_NODE *arg = NULL;
1079  PT_NODE *method;
1080 
1081  if (!method_list)
1082  {
1083  return NULL;
1084  }
1085 
1086  for (method = method_list; method != NULL; method = method->next)
1087  {
1088  if (method->node_type != PT_METHOD_CALL)
1089  {
1090  PT_INTERNAL_ERROR (parser, "translate");
1091  return NULL;
1092  }
1093  for (arg = method->info.method_call.arg_list; arg != NULL; arg = arg->next)
1094  {
1095  if ((arg->node_type != PT_NAME) || (arg->info.name.spec_id != spec_id))
1096  {
1097  params = parser_append_node (parser_copy_tree (parser, arg), params);
1098  }
1099  }
1100 
1101  /* don't forget the method's target */
1102  if (method->info.method_call.on_call_target != NULL
1103  && ((method->info.method_call.on_call_target->node_type != PT_NAME)
1104  || (method->info.method_call.on_call_target->info.name.spec_id != spec_id)))
1105  {
1106  params = parser_append_node (parser_copy_tree (parser, method->info.method_call.on_call_target), params);
1107  }
1108  }
1109 
1110  *num = pt_length_of_list (params); /* set this for calling routine */
1111  return params;
1112 }
1113 
1114 
1115 /*
1116  * meth_make_unique_range_var() - Create a new range variable with a unique name
1117  * return:
1118  * parser(in):
1119  * spec(in): corresponding spec node
1120  */
1121 static PT_NODE *
1123 {
1124  PT_NODE *node = parser_new_node (parser, PT_NAME);
1125  if (node == NULL)
1126  {
1127  PT_INTERNAL_ERROR (parser, "allocate new node");
1128  return NULL;
1129  }
1130 
1131  node->info.name.original = mq_generate_name (parser, "t", &meth_table_number);
1132  node->info.name.meta_class = PT_CLASS;
1133  node->info.name.spec_id = spec->info.spec.id;
1134 
1135  return node;
1136 }
1137 
1138 
1139 /*
1140  * meth_gen_as_attr_list() - Create an as_attr_list from the list of
1141  * attributes for the given spec_id and range_var
1142  * return:
1143  * parser(in):
1144  * range_var(in): range var of the entity for the resolution of the node
1145  * spec_id(in): entity spec id for the resolution of the node
1146  * attr_list(in): list of attributes for the as_attr_list
1147  */
1148 static PT_NODE *
1149 meth_gen_as_attr_list (PARSER_CONTEXT * parser, PT_NODE * range_var, UINTPTR spec_id, PT_NODE * attr_list)
1150 {
1151  PT_NODE *node_list = NULL;
1152  PT_NODE *attr, *new_attr;
1153 
1154  for (attr = attr_list; attr != NULL; attr = attr->next)
1155  {
1156  new_attr = parser_new_node (parser, PT_NAME);
1157  if (new_attr == NULL)
1158  {
1159  PT_INTERNAL_ERROR (parser, "allocate new node");
1160  return NULL;
1161  }
1162 
1163  new_attr->type_enum = attr->type_enum;
1164  if (attr->data_type)
1165  {
1166  new_attr->data_type = parser_copy_tree (parser, attr->data_type);
1167  }
1168  new_attr->info.name.original = mq_generate_name (parser, "c", &meth_attr_number);
1169  new_attr->info.name.resolved = range_var->info.name.original;
1170  new_attr->info.name.spec_id = spec_id;
1171  new_attr->info.name.meta_class = PT_NORMAL;
1172  node_list = parser_append_node (new_attr, node_list);
1173  }
1174 
1175  return node_list;
1176 }
1177 
1178 
1179 /*
1180  * meth_replace_method_params() -
1181  * return:
1182  * parser(in):
1183  * spec_id(in): current spec_id
1184  * method_list(in): methods whose parameters need to be replaced
1185  * as_attr_list(in): list of replacement nodes for the parameters
1186  */
1187 static void
1188 meth_replace_method_params (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE * method_list, PT_NODE * as_attr_list)
1189 {
1190  PT_NODE *arg;
1191  PT_NODE *method;
1192  PT_NODE *prev_node, *node_next, *tmp;
1193  PT_NODE *attr_list;
1194 
1195  if (!method_list)
1196  {
1197  PT_INTERNAL_ERROR (parser, "translate"); /* life is really screwed up */
1198  return;
1199  }
1200 
1201  attr_list = as_attr_list;
1202  for (method = method_list; method != NULL; method = method->next)
1203  {
1204  if (method->node_type != PT_METHOD_CALL)
1205  {
1206  PT_INTERNAL_ERROR (parser, "translate");
1207  return;
1208  }
1209  prev_node = NULL;
1210  for (arg = method->info.method_call.arg_list, node_next = arg ? arg->next : NULL; arg != NULL;
1211  arg = node_next, node_next = arg ? arg->next : NULL)
1212  {
1213  if ((arg->node_type != PT_NAME) || (arg->info.name.spec_id != spec_id))
1214  {
1215  /* replace with copy of next node on as_attr_list */
1216  tmp = parser_copy_tree (parser, attr_list);
1217  if (tmp == NULL)
1218  {
1219  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
1220  return;
1221  }
1222 
1223  tmp->next = arg->next;
1224  if (!prev_node)
1225  {
1226  /* this is the first parameter */
1227  method->info.method_call.arg_list = tmp;
1228  }
1229  else
1230  {
1231  prev_node->next = tmp;
1232  }
1233  attr_list = attr_list->next;
1234  /* could (should?) recover param here */
1235 
1236  prev_node = tmp;
1237  }
1238  else
1239  {
1240  prev_node = arg;
1241  }
1242  }
1243 
1244  /* don't forget the method's target */
1245  if (method->info.method_call.on_call_target != NULL
1246  && ((method->info.method_call.on_call_target->node_type != PT_NAME)
1247  || (method->info.method_call.on_call_target->info.name.spec_id != spec_id)))
1248  {
1249  /* replace with copy of next node on as_attr_list */
1250  tmp = parser_copy_tree (parser, attr_list);
1251  method->info.method_call.on_call_target = tmp;
1252  attr_list = attr_list->next;
1253  /* could (should?) recover old target here */
1254  }
1255  }
1256 }
1257 
1258 
1259 /*
1260  * meth_replace_method_calls() - Replace all method calls to methods in the
1261  * method_list in the root statement with their derived table attribute
1262  * return: none
1263  * parser(in):
1264  * root(in): root statement containing method calls
1265  * method_list(in): list of method calls to replace in the root statement
1266  * as_attr_list(in): list of replacement nodes (PT_NAME) to replace the
1267  * method calls with
1268  * new_spec(in): the spec that was generated for the method call
1269  * num_methods(in): number of original method calls used as a sanity check
1270  */
1271 static void
1272 meth_replace_method_calls (PARSER_CONTEXT * parser, PT_NODE * root, PT_NODE * method_list, PT_NODE * as_attr_list,
1273  PT_NODE * new_spec, int num_methods)
1274 {
1275  PT_NODE *method;
1276  PT_NODE *attr_list;
1277  METH_LAMBDA lambda;
1278 
1279  if (num_methods != pt_length_of_list (method_list))
1280  {
1281  PT_INTERNAL_ERROR (parser, "translate"); /* life is really screwed up */
1282  return;
1283  }
1284 
1285  lambda.new_spec = new_spec;
1286 
1287  attr_list = as_attr_list;
1288  for (method = method_list; method != NULL; method = method->next)
1289  {
1290  if (method->node_type != PT_METHOD_CALL)
1291  {
1292  PT_INTERNAL_ERROR (parser, "translate");
1293  return;
1294  }
1295  lambda.method_id = method->info.method_call.method_id;
1296  lambda.replacement = attr_list;
1297  (void) parser_walk_tree (parser, root, meth_replace_call, &lambda, NULL, NULL);
1298  attr_list = attr_list->next;
1299  }
1300 }
1301 
1302 
1303 /*
1304  * meth_replace_call() - replaces a method call with the correct method id
1305  * with the replacement node
1306  * return:
1307  * parser(in):
1308  * node(in):
1309  * void_arg(in):
1310  * continue_walk(in):
1311  */
1312 static PT_NODE *
1313 meth_replace_call (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1314 {
1315  METH_LAMBDA *lambda = (METH_LAMBDA *) void_arg;
1316  PT_NODE *new_node;
1317  METH_INFO1 info;
1318 
1319  if (node->node_type != PT_METHOD_CALL)
1320  {
1321  return node;
1322  }
1323 
1324  if (node->info.method_call.method_id == lambda->method_id)
1325  {
1326  /* now we have a method call to replace */
1327  new_node = parser_copy_tree (parser, lambda->replacement);
1328  if (new_node == NULL)
1329  {
1330  PT_INTERNAL_ERROR (parser, "parser_copy_tree");
1331  return NULL;
1332  }
1333 
1334  new_node->next = node->next; /* don't loose the list */
1335  return new_node;
1336  }
1337  else
1338  {
1339  /* Check if the method we are replacing is a nested method call for the node. If so, set the resolution of the
1340  * enclosing method call to the merge of the nested method_call. */
1341  info.id = lambda->method_id;
1342  info.found = 0;
1343  parser_walk_leaves (parser, node, meth_find_method, &info, NULL, NULL);
1344 
1345  if (info.found)
1346  {
1348  }
1349 
1350  return node;
1351  }
1352 }
1353 
1354 
1355 /*
1356  * meth_replace_referenced_attrs() - Replace all attribute references in the
1357  * attr_list in the root statement with their derived table attribute
1358  * return: none
1359  * parser(in):
1360  * root(in): root statement which has referenced attrs to be replaced
1361  * attr_list(in): list of attributes to be replaced
1362  * as_attr_list(in): list of replacement nodes for the attrs
1363  * num(in): number of original referenced attrs used as a sanity check
1364  */
1365 static void
1367  int num)
1368 {
1369  PT_NODE *attr;
1370  PT_NODE *as_attr;
1371  PT_NODE *next, *node_next;
1372 
1373  if ((num != pt_length_of_list (attr_list)) || (num != pt_length_of_list (as_attr_list)))
1374  {
1375  PT_INTERNAL_ERROR (parser, "translate"); /* life is really screwed up */
1376  return;
1377  }
1378 
1379  as_attr = as_attr_list;
1380  for (attr = attr_list, node_next = attr ? attr->next : NULL; attr != NULL;
1381  attr = node_next, node_next = attr ? attr->next : NULL)
1382  {
1383  if (attr->node_type != PT_NAME)
1384  {
1385  PT_INTERNAL_ERROR (parser, "translate");
1386  return;
1387  }
1388 
1389  /* save next link, pt_lambda will replace with whole as_attr list if we don't NULL the current next link. */
1390  next = as_attr->next;
1391  as_attr->next = NULL;
1392 
1393  root = pt_lambda (parser, root, attr, as_attr);
1394 
1395  /* restore next link */
1396  as_attr->next = next;
1397  as_attr = as_attr->next;
1398  }
1399 }
1400 
1401 
1402 /*
1403  * meth_find_last_entity() - See if entity is the resolution for any parameter
1404  * in the method
1405  * return:
1406  * parser(in):
1407  * node(in):
1408  * void_arg(in): METH_INFO
1409  * continue_walk(in/out):
1410  */
1411 static PT_NODE *
1412 meth_find_last_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1413 {
1414  METH_INFO *info = (METH_INFO *) void_arg;
1415  METH_INFO7 info7;
1416  PT_NODE *method = info->method;
1417 
1418  *continue_walk = PT_CONTINUE_WALK;
1419 
1420  if (node->node_type == PT_SELECT)
1421  {
1422  info->nesting_depth++; /* going down */
1423  }
1424 
1425  /* don't walk into the method you're checking with */
1426  if (node->node_type == PT_METHOD_CALL
1427  && (node->info.method_call.method_id == info->method->info.method_call.method_id))
1428  {
1429  *continue_walk = PT_LIST_WALK;
1430  }
1431 
1432  if (node->node_type != PT_SPEC)
1433  {
1434  return node;
1435  }
1436 
1437  /* don't check if the nesting depth is less that the best entity so far */
1438  if (info->nesting_depth < info->entities_nesting_depth)
1439  {
1440  return node;
1441  }
1442 
1443  info7.id = node->info.spec.id;
1444  info7.found = 0;
1445  info7.check_method_calls = 0;
1446  parser_walk_leaves (parser, method, meth_match_entity, &info7, NULL, NULL);
1447 
1448  if (info7.found)
1449  {
1450  info->entity_for_method = node;
1451  info->entities_nesting_depth = info->nesting_depth;
1452  }
1453 
1454  /* don't walk down if this is a translated method call spec (a MERGE) */
1457  {
1458  *continue_walk = PT_LIST_WALK;
1459  }
1460 
1461  return node;
1462 }
1463 
1464 
1465 /*
1466  * meth_find_last_entity_post() - Maintain nesting depth level on the
1467  * way back up the walk
1468  * return:
1469  * parser(in):
1470  * node(in):
1471  * void_arg(in):
1472  * continue_walk(in):
1473  */
1474 static PT_NODE *
1475 meth_find_last_entity_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1476 {
1477  METH_INFO *info = (METH_INFO *) void_arg;
1478 
1479  if (node->node_type == PT_SELECT)
1480  {
1481  info->nesting_depth--; /* going up */
1482  }
1483 
1484  return node;
1485 }
1486 
1487 
1488 /*
1489  * meth_match_entity() - See if this node resolves to the given entity spec id
1490  * return:
1491  * parser(in):
1492  * node(in):
1493  * void_arg(in): METH_INFO1
1494  * continue_walk(in/out):
1495  */
1496 static PT_NODE *
1497 meth_match_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1498 {
1499  METH_INFO7 *info7 = (METH_INFO7 *) void_arg;
1500  PT_NODE *root;
1501 
1502  *continue_walk = PT_CONTINUE_WALK;
1503 
1504 
1505  /* check to see if we want to dive into nested method calls. don't dive into data type nodes */
1506  if ((!info7->check_method_calls && (node->node_type == PT_METHOD_CALL)) || (node->node_type == PT_DATA_TYPE))
1507  {
1508  *continue_walk = PT_LIST_WALK;
1509  return node;
1510  }
1511 
1512  if (node->node_type == PT_DOT_)
1513  {
1514  for (root = node->info.dot.arg1; root->node_type == PT_DOT_; root = root->info.dot.arg1)
1515  {
1516  ; /* purposely blank */
1517  }
1518  if (root->info.name.spec_id == info7->id)
1519  {
1520  info7->found = 1;
1521  }
1522  *continue_walk = PT_LIST_WALK;
1523  }
1524 
1525  if ((node->node_type == PT_NAME) && (node->info.name.spec_id == info7->id))
1526  {
1527  info7->found = 1;
1528  }
1529 
1530  return node;
1531 }
1532 
1533 
1534 /*
1535  * meth_find_outside_refs() - See if this node resolves to an entity spec
1536  * different than the one given
1537  * return:
1538  * parser(in):
1539  * node(in):
1540  * void_arg(in):
1541  * continue_walk(in/out):
1542  */
1543 static PT_NODE *
1544 meth_find_outside_refs (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1545 {
1546  METH_INFO1 *info1 = (METH_INFO1 *) void_arg;
1547  PT_NODE *root;
1548  METH_INFO4 info4;
1549 
1550  *continue_walk = PT_CONTINUE_WALK;
1551 
1552  /* don't walk data_types */
1553  if (node->node_type == PT_DATA_TYPE)
1554  {
1555  *continue_walk = PT_LIST_WALK;
1556  return node;
1557  }
1558 
1559  /* check path expressions */
1560  if (node->node_type == PT_DOT_)
1561  {
1562  for (root = node->info.dot.arg1; root->node_type == PT_DOT_; root = root->info.dot.arg1)
1563  {
1564  ; /* purposely blank */
1565  }
1566  *continue_walk = PT_LIST_WALK;
1567  if (root->node_type != PT_NAME || root->info.name.meta_class == PT_PARAMETER
1569  || root->info.name.meta_class == PT_METHOD)
1570  {
1571  /* do nothing */
1572  }
1573  else if (root->info.name.spec_id != info1->id)
1574  {
1575  info1->found = 1;
1576  /* immediately, stop walking */
1577  *continue_walk = PT_STOP_WALK;
1578  }
1579  }
1580 
1581  /* watch out for sub queries--we're only interested in references outside the scope of the sub query. */
1582  if (node->node_type == PT_SELECT)
1583  {
1584  if (node->info.query.correlation_level == 1)
1585  {
1586  /* it may only be correlated to the current spec--check */
1587  info4.found = 0;
1588  info4.id = info1->id;
1589  info4.spec_list = node->info.query.q.select.from;
1590  parser_walk_leaves (parser, node, meth_find_outside_refs_subquery, &info4, NULL, NULL);
1591  if (info4.found)
1592  {
1593  info1->found = 1;
1594  /* immediately, stop walking */
1595  *continue_walk = PT_STOP_WALK;
1596  }
1597  }
1598  else if (node->info.query.correlation_level != 0)
1599  {
1600  info1->found = 1;
1601  /* immediately, stop walking */
1602  *continue_walk = PT_STOP_WALK;
1603  }
1604  *continue_walk = PT_LIST_WALK;
1605  }
1606 
1607  /* watch out for parameters of type PT_OBJECT, we don't want to look at their datatype nodes. */
1608  if (node->node_type == PT_VALUE)
1609  {
1610  *continue_walk = PT_LIST_WALK;
1611  }
1612 
1613  /* watch out ROWNUM predicate */
1614  if (node->node_type == PT_EXPR)
1615  {
1616  switch (node->info.expr.op)
1617  {
1618  case PT_ROWNUM:
1619  case PT_INST_NUM:
1620  info1->found = 1;
1621  /* immediately, stop walking */
1622  *continue_walk = PT_STOP_WALK;
1623  break;
1624 
1625  default:
1626  break;
1627  } /* switch */
1628  } /* if (node->node_type == PT_EXPR) */
1629 
1630  if (node->node_type != PT_NAME)
1631  {
1632  return node;
1633  }
1634 
1635  *continue_walk = PT_LIST_WALK;
1636 
1637  /* Parameters are no longer bound at compilation time (they're not PT_VALUES they're still PT_NAME nodes. Also
1638  * parameters are not correlated to any outside scope so we can skip them. Also method names, or meta class
1639  * attributes are not correllated names. */
1641  || node->info.name.meta_class == PT_META_ATTR || node->info.name.meta_class == PT_METHOD)
1642  {
1643  return node;
1644  }
1645 
1646  if (node->info.name.spec_id != info1->id)
1647  {
1648  info1->found = 1;
1649  /* immediately, stop walking */
1650  *continue_walk = PT_STOP_WALK;
1651  }
1652 
1653  return node;
1654 }
1655 
1656 
1657 /*
1658  * meth_bump_correlation_level() - Bump the correlation level of all
1659  * correlated queries
1660  * return:
1661  * parser(in):
1662  * node(in):
1663  * increment(in): amount to bump correlation
1664  * threshold(in): used to determine which correlations to bump
1665  * spec_id(in): used to determine which correlations to bump
1666  */
1667 static void
1668 meth_bump_correlation_level (PARSER_CONTEXT * parser, PT_NODE * node, int increment, int threshold, UINTPTR spec_id)
1669 {
1670  METH_CORR_INFO info;
1671  info.corr_step = increment;
1672  info.corr_threshold = threshold;
1673  info.spec_id = spec_id;
1674 
1675  (void) parser_walk_tree (parser, node, meth_bump_corr_pre, &info, meth_bump_corr_post, &info);
1676 }
1677 
1678 
1679 /*
1680  * meth_bump_corr_pre() - Bump the correlation level of all queries
1681  * return:
1682  * parser(in):
1683  * node(in):
1684  * void_arg(in):
1685  * continue_walk(in/out):
1686  */
1687 static PT_NODE *
1688 meth_bump_corr_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1689 {
1690  METH_CORR_INFO *corr_info = (METH_CORR_INFO *) void_arg;
1691  METH_INFO1 info1;
1692  METH_INFO7 info7;
1693  PT_NODE *next;
1694 
1695  *continue_walk = PT_CONTINUE_WALK;
1696 
1697  if (!PT_IS_QUERY_NODE_TYPE (node->node_type))
1698  {
1699  return node;
1700  }
1701 
1702  /* Can not increment threshold for list portion of walk. Since those queries are not sub-queries of this query.
1703  * Consequently, we recurse separately for the list leading from a query. */
1704  if (node->next)
1705  {
1706  meth_bump_correlation_level (parser, node->next, corr_info->corr_step, corr_info->corr_threshold,
1707  corr_info->spec_id);
1708  }
1709 
1710  *continue_walk = PT_LEAF_WALK;
1711 
1712  if (node->info.query.correlation_level != 0)
1713  {
1714  if (node->info.query.correlation_level == corr_info->corr_threshold)
1715  {
1716  if (corr_info->corr_step < 0)
1717  {
1718  /* always bump correlation_level if this is a collapse */
1719  node->info.query.correlation_level += corr_info->corr_step;
1720  }
1721  else
1722  {
1723  next = node->next;
1724  node->next = NULL;
1725 
1726  /* check for outside refs */
1727  info1.id = corr_info->spec_id;
1728  info1.found = 0;
1729  parser_walk_leaves (parser, node, meth_find_outside_refs, &info1, NULL, NULL);
1730 
1731  /* check if there are refs to the spec we are expanding */
1732  info7.id = corr_info->spec_id;
1733  info7.found = 0;
1734  info7.check_method_calls = 0;
1735  parser_walk_leaves (parser, node, meth_match_entity, &info7, NULL, NULL);
1736 
1737  /* bump correlation_level if there are outside refs and there are no refs to our spec. */
1738  if (info1.found && !info7.found)
1739  {
1740  node->info.query.correlation_level += corr_info->corr_step;
1741  }
1742  node->next = next;
1743  }
1744  }
1745  else if (node->info.query.correlation_level > corr_info->corr_threshold)
1746  node->info.query.correlation_level += corr_info->corr_step;
1747  }
1748  else
1749  {
1750  /* if the correlation level is 0, there cannot be correlated subqueries crossing this level */
1751  *continue_walk = PT_STOP_WALK;
1752  }
1753 
1754  /* increment threshold as we dive into subqueries */
1755  corr_info->corr_threshold++;
1756 
1757  return node;
1758 }
1759 
1760 
1761 /*
1762  * meth_bump_corr_post() - Decrement the corr_threshold on the way up
1763  * return:
1764  * parser(in):
1765  * node(in):
1766  * void_arg(in):
1767  * continue_walk(in):
1768  */
1769 static PT_NODE *
1770 meth_bump_corr_post (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1771 {
1772  METH_CORR_INFO *corr_info = (METH_CORR_INFO *) void_arg;
1773 
1774  if (!PT_IS_QUERY_NODE_TYPE (node->node_type))
1775  {
1776  return node;
1777  }
1778 
1779  corr_info->corr_threshold--;
1780 
1781  return node;
1782 }
1783 
1784 
1785 /*
1786  * meth_find_merge() - Check if the node is a MERGE node
1787  * return:
1788  * parser(in):
1789  * node(in):
1790  * void_arg(out):
1791  * continue_walk(in):
1792  */
1793 static PT_NODE *
1794 meth_find_merge (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1795 {
1796  int *hand_rewritten = (int *) void_arg;
1797 
1798  if (node->node_type == PT_SELECT && node->info.query.q.select.flavor == PT_MERGE_SELECT)
1799  {
1800  *hand_rewritten = 1;
1801  }
1802 
1803  return node;
1804 }
1805 
1806 
1807 /*
1808  * meth_is_method() - Is this node a method call
1809  * return:
1810  * parser(in):
1811  * node(in):
1812  * void_arg(out):
1813  * continue_walk(in/out):
1814  */
1815 static PT_NODE *
1816 meth_is_method (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1817 {
1818  int *is_a_method = (int *) void_arg;
1819 
1820  *continue_walk = PT_CONTINUE_WALK;
1821 
1823  {
1824  *is_a_method = 1;
1825  }
1826 
1827  /* we don't want to look for methods that have already been translated. they will be found in the leaves of merge
1828  * nodes. */
1829  if (node->node_type == PT_SELECT && node->info.query.q.select.flavor == PT_MERGE_SELECT)
1830  {
1831  *continue_walk = PT_LIST_WALK;
1832  }
1833 
1834  return node;
1835 }
1836 
1837 
1838 /*
1839  * meth_method_path_entities() - return a list of all special method path
1840  * entities in paths
1841  * return:
1842  * parser(in):
1843  * paths(out): a list of path entities
1844  */
1845 static PT_NODE *
1847 {
1848  PT_NODE *path;
1849  PT_NODE *spec;
1850  PT_NODE *list = NULL;
1851 
1852  for (path = paths; path != NULL; path = path->next)
1853  {
1854  if (path->info.spec.flavor == PT_METHOD_ENTITY)
1855  {
1856  spec = parser_copy_tree (parser, path);
1857 
1858  /* as we move it up, it becomes a regular path entity */
1859  spec->info.spec.flavor = (PT_MISC_TYPE) 0;
1860  list = parser_append_node (spec, list);
1861  }
1862  }
1863 
1864  return list;
1865 }
1866 
1867 /*
1868  * meth_non_method_path_entities() - return a list of all path enties which
1869  * are not special method path entities in paths
1870  * return:
1871  * parser(in):
1872  * paths(out): a list of path entities
1873  */
1874 static PT_NODE *
1876 {
1877  PT_NODE *path;
1878  PT_NODE *spec;
1879  PT_NODE *list = NULL;
1880 
1881  for (path = paths; path != NULL; path = path->next)
1882  {
1883  if (path->info.spec.flavor != PT_METHOD_ENTITY)
1884  {
1885  spec = parser_copy_tree (parser, path);
1886  list = parser_append_node (spec, list);
1887  }
1888  }
1889 
1890  return list;
1891 }
1892 
1893 
1894 /*
1895  * meth_find_entity() - find entity that matches the given id
1896  * return:
1897  * parser(in):
1898  * node(in):
1899  * void_arg(in):
1900  * continue_walk(in):
1901  */
1902 static PT_NODE *
1903 meth_find_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1904 {
1905  METH_INFO3 *info3 = (METH_INFO3 *) void_arg;
1906 
1907  if (node->node_type == PT_SPEC && node->info.spec.id == info3->id)
1908  {
1909  info3->entity = node;
1910  }
1911 
1912  return node;
1913 }
1914 
1915 
1916 /*
1917  * meth_find_method() - Check if the given method is found
1918  * return:
1919  * parser(in):
1920  * node(in):
1921  * void_arg(in/out):
1922  * continue_walk(in/out):
1923  *
1924  * Note:
1925  * If the method_id == 0, match any method and look for methods in subqueries.
1926  * If method_id != 0, we are looking for a specific method and do not look
1927  * for that method in subqueries
1928  */
1929 static PT_NODE *
1930 meth_find_method (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1931 {
1932  METH_INFO1 *info = (METH_INFO1 *) void_arg;
1933 
1934  *continue_walk = PT_CONTINUE_WALK;
1935 
1936  if (node->node_type == PT_METHOD_CALL && (info->id == 0 || node->info.method_call.method_id == info->id))
1937  {
1938  info->found = 1;
1939  }
1940 
1941  /* prune walk at selects */
1942  if (node->node_type == PT_SELECT && info->id != 0)
1943  {
1944  *continue_walk = PT_LIST_WALK;
1945  }
1946 
1947  return node;
1948 }
1949 
1950 
1951 /*
1952  * meth_find_outside_refs_subquery() - Check if outside refs match given
1953  * entity spec id
1954  * return:
1955  * parser(in):
1956  * node(in):
1957  * void_arg(in/out):
1958  * continue_walk(in/out):
1959  */
1960 static PT_NODE *
1961 meth_find_outside_refs_subquery (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
1962 {
1963  METH_INFO4 *info4 = (METH_INFO4 *) void_arg;
1964  PT_NODE *root;
1965 
1966  *continue_walk = PT_CONTINUE_WALK;
1967 
1968  /* don't walk data_types */
1969  if (node->node_type == PT_DATA_TYPE)
1970  {
1971  *continue_walk = PT_LIST_WALK;
1972  return node;
1973  }
1974 
1975  /* check path expressions */
1976  if (node->node_type == PT_DOT_)
1977  {
1978  for (root = node->info.dot.arg1; root->node_type == PT_DOT_; root = root->info.dot.arg1)
1979  {
1980  ; /* purposely blank */
1981  }
1982  *continue_walk = PT_LIST_WALK;
1983  if (!pt_find_entity (parser, info4->spec_list, root->info.name.spec_id) && root->info.name.spec_id != info4->id)
1984  {
1985  info4->found = 1;
1986  /* immediately, stop walking */
1987  *continue_walk = PT_STOP_WALK;
1988  }
1989  }
1990 
1991  if ((node->node_type == PT_SELECT) || (node->node_type == PT_VALUE))
1992  {
1993  *continue_walk = PT_LIST_WALK;
1994  }
1995 
1996  if (node->node_type != PT_NAME)
1997  {
1998  return node;
1999  }
2000  /* Parameters are no longer bound at compilation time (they're not PT_VALUES they're still PT_NAME nodes. Also
2001  * parameters are not correlated to any outside scope so we can skip them. */
2002  if (node->info.name.meta_class == PT_PARAMETER)
2003  {
2004  *continue_walk = PT_LIST_WALK;
2005  return node;
2006  }
2007  /* don't look at class attributes, their spec ids are not real */
2009  && !pt_find_entity (parser, info4->spec_list, node->info.name.spec_id) && node->info.name.spec_id != info4->id)
2010  {
2011  info4->found = 1;
2012  /* immediately, stop walking */
2013  *continue_walk = PT_STOP_WALK;
2014  }
2015 
2016  return node;
2017 }
2018 
2019 
2020 /*
2021  * meth_push_conjuncts() -
2022  * return:
2023  * parser(in):
2024  * spec_id(in): entity spec id of the conjuncts we want to push
2025  * where(in): where clause that contains conjuncts that might be able
2026  * to be pushed down
2027  */
2028 static PT_NODE *
2029 meth_push_conjuncts (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE ** where)
2030 {
2031  METH_INFO5 info5;
2032  METH_INFO1 info1;
2033  int outside_refs, nested_meths;
2034  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
2035 
2036  info5.new_where = NULL;
2037  info5.spec_id = spec_id;
2038 
2039  if (!(*where))
2040  {
2041  return NULL; /* there are no conjuncts to push */
2042  }
2043 
2044  sc_info.top_node = *where;
2045  sc_info.donot_fold = false;
2046 
2047  if ((*where)->node_type == PT_EXPR && (*where)->info.expr.op == PT_AND)
2048  {
2049  *where = parser_walk_tree (parser, *where, NULL, NULL, meth_grab_conj, &info5);
2050 
2051  /* check top conjunct */
2052  if ((*where)->node_type == PT_EXPR && (*where)->info.expr.op != PT_AND && (*where)->spec_ident == spec_id)
2053  {
2054  /* we can't push if there are outside refs */
2055  info1.id = spec_id;
2056  info1.found = 0;
2057  (void) parser_walk_tree (parser, *where, meth_find_outside_refs, &info1, NULL, NULL);
2058  outside_refs = info1.found;
2059 
2060  /* we can't push if there are nested method calls */
2061  info1.id = 0; /* match any method--even in nested subqueries */
2062  info1.found = 0;
2063  (void) parser_walk_tree (parser, *where, meth_find_method, &info1, NULL, NULL);
2064  nested_meths = info1.found;
2065 
2066  if (!outside_refs && !nested_meths)
2067  {
2068  info5.new_where = meth_add_conj (parser, info5.new_where, *where);
2069  *where = NULL;
2070  }
2071  }
2072 
2073  /* need to fold where clause since pushing conjuncts can introduce true nodes into the tree. */
2074  *where = pt_semantic_type (parser, *where, &sc_info);
2075 
2076  /* check if the where clause = true */
2077  *where = pt_where_type (parser, *where);
2078  }
2079  else
2080  {
2081  /* WHERE is cnf list */
2082  meth_grab_cnf_conj (parser, where, &info5);
2083  }
2084 
2085  return info5.new_where;
2086 }
2087 
2088 
2089 /*
2090  * meth_grab_conj() - Put conjuncts that match the given spec id on the
2091  * new_where clause and replace it in original tree
2092  * return:
2093  * parser(in):
2094  * node(in):
2095  * void_arg(in/out):
2096  * continue_walk(in/out):
2097  */
2098 static PT_NODE *
2099 meth_grab_conj (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
2100 {
2101  METH_INFO5 *info5 = (METH_INFO5 *) void_arg;
2102  PT_NODE *true_node;
2103  METH_INFO1 info1;
2104  int arg1_outside_refs, arg2_outside_refs;
2105  int arg1_nested_meths, arg2_nested_meths;
2106 
2107  *continue_walk = PT_CONTINUE_WALK;
2108 
2109  if ((node->node_type != PT_EXPR) || (node->info.expr.op != PT_AND))
2110  {
2111  return node;
2112  }
2113 
2114  /* we can't push if there are outside refs */
2115  info1.id = info5->spec_id;
2116  info1.found = 0;
2117  (void) parser_walk_tree (parser, node->info.expr.arg1, meth_find_outside_refs, &info1, NULL, NULL);
2118  arg1_outside_refs = info1.found;
2119 
2120  info1.id = info5->spec_id;
2121  info1.found = 0;
2122  (void) parser_walk_tree (parser, node->info.expr.arg2, meth_find_outside_refs, &info1, NULL, NULL);
2123  arg2_outside_refs = info1.found;
2124 
2125  /* we can't push if there are nested method calls */
2126  info1.id = 0; /* match any method--even in nested subqueries */
2127  info1.found = 0;
2128  (void) parser_walk_tree (parser, node->info.expr.arg1, meth_find_method, &info1, NULL, NULL);
2129  arg1_nested_meths = info1.found;
2130 
2131  info1.id = 0; /* match any method--even in nested subqueries */
2132  info1.found = 0;
2133  (void) parser_walk_tree (parser, node->info.expr.arg2, meth_find_method, &info1, NULL, NULL);
2134  arg2_nested_meths = info1.found;
2135 
2136  if (node->info.expr.arg1->spec_ident == info5->spec_id && node->info.expr.arg2->spec_ident == info5->spec_id
2137  && !arg1_outside_refs && !arg2_outside_refs && !arg1_nested_meths && !arg2_nested_meths)
2138  {
2139  info5->new_where = meth_add_conj (parser, info5->new_where, node->info.expr.arg1);
2140  info5->new_where = meth_add_conj (parser, info5->new_where, node->info.expr.arg2);
2141 
2142  /* create a true node to replace the current node */
2143  true_node = parser_new_node (parser, PT_VALUE);
2144  if (true_node == NULL)
2145  {
2146  PT_INTERNAL_ERROR (parser, "allocate new node");
2147  return NULL;
2148  }
2149 
2150  true_node->type_enum = PT_TYPE_LOGICAL;
2151  true_node->info.value.data_value.i = 1;
2152 
2153  return true_node; /* AND node collapses */
2154  }
2155 
2156  if (node->info.expr.arg1->spec_ident == info5->spec_id && !arg1_outside_refs && !arg1_nested_meths)
2157  {
2158  info5->new_where = meth_add_conj (parser, info5->new_where, node->info.expr.arg1);
2159 
2160  return node->info.expr.arg2; /* AND node collapses */
2161  }
2162 
2163  if (node->info.expr.arg2->spec_ident == info5->spec_id && !arg2_outside_refs && !arg2_nested_meths)
2164  {
2165  info5->new_where = meth_add_conj (parser, info5->new_where, node->info.expr.arg2);
2166 
2167  return node->info.expr.arg1; /* AND node collapses */
2168  }
2169 
2170  return node;
2171 }
2172 
2173 /*
2174  * meth_grab_cnf_conj() - Put conjuncts that match the given spec id on
2175  * the new_where clause and replace it in original tree
2176  * return:
2177  * parser(in):
2178  * where(in):
2179  * info5(out):
2180  */
2181 static void
2183 {
2184  PT_NODE *conj, *prev = NULL, *next;
2185  METH_INFO1 info1;
2186  int outside_refs;
2187  int nested_meths;
2188 
2189  conj = *where;
2190  while (conj)
2191  {
2192  next = conj->next;
2193  conj->next = NULL; /* cut */
2194 
2195  /* we can't push if there are outside refs */
2196  info1.id = info5->spec_id;
2197  info1.found = 0;
2198  (void) parser_walk_tree (parser, conj, meth_find_outside_refs, &info1, NULL, NULL);
2199  outside_refs = info1.found;
2200 
2201  /* we can't push if there are nested method calls */
2202  info1.id = 0; /* match any method - even in nested subqueries */
2203  info1.found = 0;
2204  (void) parser_walk_tree (parser, conj, meth_find_method, &info1, NULL, NULL);
2205  nested_meths = info1.found;
2206 
2207  if (!outside_refs && !nested_meths)
2208  {
2209  /* found pushable conjuncts */
2210  if (conj == *where)
2211  { /* first node of cnf list */
2212  *where = next; /* remove conj from where */
2213  }
2214  else
2215  {
2216  prev->next = next; /* remove conj from where */
2217  }
2218  /* append conj to new_where */
2219  info5->new_where = parser_append_node (conj, info5->new_where);
2220  }
2221  else
2222  {
2223  conj->next = next; /* restore next link */
2224  prev = conj; /* save prev conj */
2225  }
2226 
2227  conj = next;
2228  }
2229 }
2230 
2231 /*
2232  * meth_add_conj() - add the conjunct to the where clause
2233  * return:
2234  * parser(in):
2235  * where(in): where clause to add the conjunct to
2236  * new_conj(in): conjunct to add to the where clause
2237  */
2238 static PT_NODE *
2240 {
2241  PT_NODE *conj;
2242 
2243  if (where == NULL)
2244  {
2245  return new_conj;
2246  }
2247  else if (new_conj == NULL)
2248  {
2249  return where;
2250  }
2251  else
2252  {
2253  conj = parser_new_node (parser, PT_EXPR);
2254  if (conj == NULL)
2255  {
2256  PT_INTERNAL_ERROR (parser, "allocate new node");
2257  return NULL;
2258  }
2259 
2260  conj->type_enum = PT_TYPE_LOGICAL;
2261  conj->info.expr.op = PT_AND;
2262  conj->info.expr.arg1 = where;
2263  conj->info.expr.arg2 = new_conj;
2264 
2265  return conj;
2266  }
2267 }
2268 
2269 
2270 /*
2271  * meth_replace_id_in_method_names() - Re-resolve method name nodes that used
2272  * to resolve to the old_id to the new_id
2273  * return:
2274  * parser(in):
2275  * node(in):
2276  * void_arg(in):
2277  * continue_walk(in):
2278  */
2279 static PT_NODE *
2280 meth_replace_id_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk)
2281 {
2282  METH_INFO6 *info6 = (METH_INFO6 *) void_arg;
2283 
2284  if (node->node_type == PT_METHOD_CALL && (node->info.method_call.method_name->info.name.spec_id == info6->old_id))
2285  {
2287  }
2288 
2289  return node;
2290 }
2291 
2292 
2293 /*
2294  * meth_refs_to_scope() - See if a name node resolves to the given scope
2295  * return: 1 on found
2296  * parser(in):
2297  * scope(in): scope to check refs for
2298  * tree(in): tree to check refs in
2299  */
2300 static int
2302 {
2303  int found = 0;
2304  PT_NODE *spec;
2305  METH_INFO7 info7;
2306 
2307  for (spec = scope; spec != NULL; spec = spec->next)
2308  {
2309  info7.id = spec->info.spec.id;
2310  info7.found = 0;
2311  info7.check_method_calls = 1;
2312  tree = parser_walk_tree (parser, tree, meth_match_entity, &info7, NULL, NULL);
2313 
2314  if (info7.found)
2315  {
2316  found = 1;
2317  }
2318  }
2319 
2320  return found;
2321 }
2322 
2323 /*
2324  * meth_find_hierarchical_op() - Check expression tree for hierarchical op
2325  * return:
2326  * parser(in):
2327  * node(in):
2328  * arg(in/out):
2329  * continue_walk(in):
2330  */
2331 static PT_NODE *
2332 meth_find_hierarchical_op (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
2333 {
2334  bool *is_hierarchical_op = (bool *) arg;
2335 
2336  if (node->node_type != PT_EXPR)
2337  {
2338  *continue_walk = PT_STOP_WALK;
2339  }
2340  else
2341  {
2343  {
2344  *is_hierarchical_op = true;
2345  *continue_walk = PT_STOP_WALK;
2346  }
2347  }
2348 
2349  return node;
2350 }
2351 
2352 /*
2353  * meth_find_hierarchical_in_method_list() - Check method list for hierarchical
2354  * expressions in arguments
2355  * return:
2356  * parser(in):
2357  * method_list(in):
2358  * has_hierarchical_expr(out):
2359  */
2360 static void
2361 meth_find_hierarchical_in_method_list (PARSER_CONTEXT * parser, PT_NODE * method_list, bool * has_hierarchical_expr)
2362 {
2363  PT_NODE *node, *arg, *save_next;
2364 
2365  for (node = method_list; node != NULL && !(*has_hierarchical_expr); node = node->next)
2366  {
2367  if (node->node_type == PT_METHOD_CALL)
2368  {
2369  for (arg = node->info.method_call.arg_list; arg != NULL && !(*has_hierarchical_expr); arg = arg->next)
2370  {
2371  save_next = arg->next;
2372  arg->next = NULL;
2373  (void) parser_walk_tree (parser, arg, meth_find_hierarchical_op, has_hierarchical_expr, NULL, NULL);
2374  arg->next = save_next;
2375  }
2376  }
2377  }
2378 }
2379 
2380 /*
2381  * meth_copy_hierarchical_expr_to_list() - Copy and hierarchical expressions
2382  * from source to destination list
2383  * return:
2384  * parser(in):
2385  * src_list(in):
2386  * dst_list(in):
2387  * copy_count(in/out):
2388  */
2389 static void
2391  int *copy_count)
2392 {
2393  PT_NODE *node, *temp, *save_next;
2394  bool found, has_hierarchical_expr;
2395 
2396  for (node = src_list; node != NULL; node = node->next)
2397  {
2398  has_hierarchical_expr = false;
2399  save_next = node->next;
2400  node->next = NULL;
2401  (void) parser_walk_tree (parser, node, meth_find_hierarchical_op, &has_hierarchical_expr, NULL, NULL);
2402  node->next = save_next;
2403  if (has_hierarchical_expr)
2404  {
2405  /* don't copy if it's already there */
2406  found = false;
2407  for (temp = *dst_list_p; temp != NULL && !found; temp = temp->next)
2408  {
2409  if (node == temp)
2410  {
2411  found = true;
2412  }
2413  }
2414  if (!found)
2415  {
2416  *dst_list_p = parser_append_node (parser_copy_tree (parser, node), *dst_list_p);
2417  (*copy_count)++;
2418  }
2419  }
2420  }
2421 }
2422 
2423 /*
2424  * meth_move_hierarchical_to_derived() - Move hierarchical statement info to
2425  * derived
2426  * return:
2427  * parser(in):
2428  * statement_info(in):
2429  * derived_info(in):
2430  */
2431 static void
2433  PT_SELECT_INFO * derived_info)
2434 {
2435  /* copy predicates */
2436  derived_info->connect_by = parser_copy_tree_list (parser, statement_info->connect_by);
2437  derived_info->start_with = parser_copy_tree_list (parser, statement_info->start_with);
2438  derived_info->after_cb_filter = parser_copy_tree_list (parser, statement_info->after_cb_filter);
2439 
2440  /* copy flags */
2441  derived_info->check_cycles = statement_info->check_cycles;
2442  derived_info->single_table_opt = statement_info->single_table_opt;
2443 
2444  /* clear predicates */
2445  parser_free_tree (parser, statement_info->connect_by);
2446  parser_free_tree (parser, statement_info->start_with);
2447  parser_free_tree (parser, statement_info->after_cb_filter);
2448  statement_info->connect_by = NULL;
2449  statement_info->start_with = NULL;
2450  statement_info->after_cb_filter = NULL;
2451 
2452  /* reset flags */
2453  statement_info->check_cycles = CONNECT_BY_CYCLES_ERROR;
2454  statement_info->single_table_opt = 0;
2455 }
2456 
2457 /*
2458  * meth_replace_hierarchical_exprs() - Replace hierarchical exprs in list with
2459  * derived attrs
2460  * return:
2461  * parser(in):
2462  * statement_info(in):
2463  * derived_info(in):
2464  */
2465 static void
2467  int num_methods)
2468 {
2469  PT_NODE *node, *prev_node, *save_next, *new_node;
2470  bool has_hierarchical_expr;
2471  int i;
2472 
2473  for (i = 0; i < num_methods; i++)
2474  {
2475  ref_attrs = ref_attrs->next;
2476  }
2477 
2478  for (node = *select_list_p, prev_node = NULL; node != NULL; node = node->next)
2479  {
2480  has_hierarchical_expr = false;
2481  save_next = node->next;
2482  node->next = NULL;
2483  (void) parser_walk_tree (parser, node, meth_find_hierarchical_op, &has_hierarchical_expr, NULL, NULL);
2484  node->next = save_next;
2485  if (has_hierarchical_expr)
2486  {
2487  new_node = parser_copy_tree (parser, ref_attrs);
2488  new_node->next = node->next;
2489  if (prev_node)
2490  {
2491  prev_node->next = new_node;
2492  }
2493  else
2494  {
2495  *select_list_p = new_node;
2496  }
2497  node->next = NULL;
2498  parser_free_tree (parser, node);
2499  node = new_node;
2500  ref_attrs = ref_attrs->next;
2501  }
2502  prev_node = node;
2503  }
2504 }
static PT_NODE * meth_find_last_entity_post(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * meth_translate(PARSER_CONTEXT *parser, PT_NODE *volatile node)
PT_NODE * next
Definition: parse_tree.h:3447
static void meth_replace_method_params(PARSER_CONTEXT *parser, UINTPTR spec_id, PT_NODE *method_list, PT_NODE *as_attr_list)
PT_NAME_INFO name
Definition: parse_tree.h:3318
static void meth_grab_cnf_conj(PARSER_CONTEXT *parser, PT_NODE **where, METH_INFO5 *info5)
PT_NODE * arg_list
Definition: parse_tree.h:2258
PT_UNION_INFO union_
Definition: parse_tree.h:2782
PT_METHOD_CALL_INFO method_call
Definition: parse_tree.h:3316
UINTPTR id
Definition: parse_tree.h:2144
PT_NODE * entity_for_method
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
#define PT_ERRORm(parser, node, setNo, msgNo)
Definition: parse_tree.h:63
PT_NODE * pt_do_cnf(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: cnf.c:1191
PT_MISC_TYPE call_or_expr
Definition: parse_tree.h:2367
PT_MISC_TYPE
Definition: parse_tree.h:983
#define PT_REQUIRES_HIERARCHICAL_QUERY(op)
Definition: parse_tree.h:439
short location
Definition: parse_tree.h:2152
PT_MISC_TYPE flavor
Definition: parse_tree.h:2148
PT_SPEC_INFO spec
Definition: parse_tree.h:3346
PT_NODE * arg2
Definition: parse_tree.h:2664
int correlation_level
Definition: parse_tree.h:2745
PT_NODE * select_statement
#define pt_is_query(n)
Definition: parse_tree.h:258
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2552
static int meth_table_number
static PT_NODE * meth_add_conj(PARSER_CONTEXT *parser, PT_NODE *where, PT_NODE *new_conj)
PT_NODE * new_spec
union pt_query_info::@124 q
PT_NODE * path_entities
Definition: parse_tree.h:2138
static void meth_bump_correlation_level(PARSER_CONTEXT *parser, PT_NODE *node, int increment, int threshold, UINTPTR spec_id)
static PT_NODE * meth_collapse_nodes(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_replace_id_in_method_names(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define PT_SET_JMP_ENV(parser)
Definition: parse_tree.h:89
static PT_NODE * meth_grab_conj(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_match_entity(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_find_entity(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_have_methods(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static PT_NODE * meth_find_method(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_translate_helper(PARSER_CONTEXT *parser, PT_NODE *node)
static void meth_find_hierarchical_in_method_list(PARSER_CONTEXT *parser, PT_NODE *method_list, bool *has_hierarchical_expr)
PT_NODE * data_type
Definition: parse_tree.h:3453
unsigned single_table_opt
Definition: parse_tree.h:2711
PT_DOT_INFO dot
Definition: parse_tree.h:3287
PT_NODE * arg2
Definition: parse_tree.h:2086
static PT_NODE * meth_push_conjuncts(PARSER_CONTEXT *parser, UINTPTR spec_id, PT_NODE **where)
PT_NODE * pt_lambda(PARSER_CONTEXT *parser, PT_NODE *tree_with_names, PT_NODE *name_node, PT_NODE *corresponding_tree)
PT_NODE * mq_reset_paths(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *root_spec)
static void meth_replace_method_calls(PARSER_CONTEXT *parser, PT_NODE *root, PT_NODE *method_list, PT_NODE *as_attr_list, PT_NODE *new_spec, int num_methods)
static int meth_refs_to_scope(PARSER_CONTEXT *parser, PT_NODE *scope, PT_NODE *tree)
PT_TYPE_ENUM type_enum
Definition: parse_tree.h:3457
const char * mq_generate_name(PARSER_CONTEXT *parser, const char *root, int *version)
PT_NODE * method_list
Definition: parse_tree.h:2141
PT_MISC_TYPE derived_table_type
Definition: parse_tree.h:2147
PT_NODE * arg1
Definition: parse_tree.h:2663
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
PT_NODE * spec_list
#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)
PT_NODE * replacement
static PT_NODE * meth_make_unique_range_var(PARSER_CONTEXT *parser, PT_NODE *spec)
PT_NODE * pt_where_type(PARSER_CONTEXT *parser, PT_NODE *where)
static void meth_copy_hierarchical_expr_to_list(PARSER_CONTEXT *parser, PT_NODE *src_list, PT_NODE **dst_list_p, int *copy_count)
PT_NODE * on_cond
Definition: parse_tree.h:2149
PT_DATA_VALUE data_value
Definition: parse_tree.h:3058
PT_NODE * top_node
Definition: parse_tree.h:1707
PT_NODE * method_name
Definition: parse_tree.h:2363
const char * original
Definition: parse_tree.h:2544
PT_NODE * entity
static PT_NODE * meth_translate_local(PARSER_CONTEXT *parser, PT_NODE *statement, void *void_arg, int *continue_walk)
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
PT_NODE * parser_copy_tree(PARSER_CONTEXT *parser, const PT_NODE *tree)
PT_NODE * pt_semantic_type(PARSER_CONTEXT *parser, PT_NODE *tree, SEMANTIC_CHK_INFO *sc_info)
PT_NODE * new_where
PT_NODE * from
Definition: parse_tree.h:2686
static PT_NODE * meth_find_last_entity(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
UINTPTR spec_id
Definition: parse_tree.h:2543
static PT_NODE * meth_non_method_path_entities(PARSER_CONTEXT *parser, PT_NODE *paths)
static void meth_replace_referenced_attrs(PARSER_CONTEXT *parser, PT_NODE *root, PT_NODE *attr_list, PT_NODE *as_attr_list, int num)
int methods_to_translate
SP_PARSER_CTX * parser
PT_NODE * arg1
Definition: parse_tree.h:2197
PT_NODE * pt_find_entity(PARSER_CONTEXT *parser, const PT_NODE *scope, UINTPTR id)
#define NULL
Definition: freelistheap.h:34
PT_NODE * as_attr_list
Definition: parse_tree.h:2136
static PT_NODE * meth_bump_corr_post(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_NODE * referenced_attrs
Definition: parse_tree.h:2137
static PT_NODE * meth_replace_call(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_find_outside_refs_subquery(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
PT_MISC_TYPE is_subquery
Definition: parse_tree.h:2747
static PT_NODE * meth_find_outside_refs(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_get_method_params(PARSER_CONTEXT *parser, UINTPTR spec_id, PT_NODE *method_list, int *num)
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
PT_NODE * set
Definition: parse_tree.h:3047
static PT_NODE * meth_bump_corr_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define MSGCAT_SEMANTIC_METH_CORR_SET_EXPR
PT_NODE * parser_append_node(PT_NODE *node, PT_NODE *list)
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
static void meth_replace_hierarchical_exprs(PARSER_CONTEXT *parser, PT_NODE **select_list_p, PT_NODE *ref_attrs, int num_methods)
static PT_NODE * meth_gen_as_attr_list(PARSER_CONTEXT *parser, PT_NODE *range_var, UINTPTR spec_id, PT_NODE *attr_list)
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
static PT_NODE * meth_create_method_list(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
#define MSGCAT_SET_PARSER_SEMANTIC
static int meth_attr_number
static PT_NODE * meth_find_hierarchical_op(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
PT_NODE * connect_by
Definition: parse_tree.h:2689
static PT_NODE * meth_is_method(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static void meth_move_hierarchical_to_derived(PARSER_CONTEXT *parser, PT_SELECT_INFO *statement_info, PT_SELECT_INFO *derived_info)
PT_NODE * start_with
Definition: parse_tree.h:2690
PT_NODE * after_cb_filter
Definition: parse_tree.h:2691
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2146
int pt_statement_have_methods(PARSER_CONTEXT *parser, PT_NODE *statement)
int entities_nesting_depth
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
PT_NODE * list
Definition: parse_tree.h:2685
PT_OP_TYPE op
Definition: parse_tree.h:2200
static PT_NODE * meth_translate_spec(PARSER_CONTEXT *parser, PT_NODE *spec, void *void_arg, int *continue_walk)
#define PT_INTERNAL_ERROR(parser, what)
Definition: parse_tree.h:112
int db_make_int(DB_VALUE *value, const int num)
PT_NODE * root
#define pt_has_error(parser)
Definition: parser.h:507
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)
UINTPTR method_id
PT_NODE * pt_dbval_to_value(PARSER_CONTEXT *parser, const DB_VALUE *val)
Definition: parse_dbi.c:574
UINTPTR spec_ident
Definition: parse_tree.h:3451
int column_number
Definition: parse_tree.h:3442
int pt_length_of_list(const PT_NODE *list)
PT_SELECT_INFO select
Definition: parse_tree.h:2781
static PT_NODE * meth_find_merge(PARSER_CONTEXT *parser, PT_NODE *node, void *void_arg, int *continue_walk)
static PT_NODE * meth_translate_select(PARSER_CONTEXT *parser, PT_NODE *select_statement, PT_NODE *root)
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)
PT_NODE * method
PT_NODE * parser_copy_tree_list(PARSER_CONTEXT *parser, PT_NODE *tree)
PT_JOIN_TYPE join_type
Definition: parse_tree.h:2151
PT_NODE * on_call_target
Definition: parse_tree.h:2365
static PT_NODE * meth_method_path_entities(PARSER_CONTEXT *parser, PT_NODE *paths)
PT_NODE * derived_table
Definition: parse_tree.h:2134
PT_NODE * range_var
Definition: parse_tree.h:2135