CUBRID Engine  latest
plan_generation.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  * plan_generation.c - Generate XASL trees from query optimizer plans
21  */
22 
23 #ident "$Id$"
24 
25 #include <assert.h>
26 
27 #include "optimizer.h"
28 
29 #include "config.h"
30 #include "object_primitive.h"
31 #include "query_bitset.h"
32 #include "query_graph.h"
33 #include "query_planner.h"
34 #include "parser.h"
35 #include "parser_support.h"
36 #include "system_parameter.h"
37 #include "xasl.h"
38 #include "xasl_generation.h"
39 #include "xasl_predicate.hpp"
40 
41 typedef int (*ELIGIBILITY_FN) (QO_TERM *);
42 
43 static XASL_NODE *make_scan_proc (QO_ENV * env);
44 static XASL_NODE *make_mergelist_proc (QO_ENV * env, QO_PLAN * plan, XASL_NODE * left, PT_NODE * left_list,
45  BITSET * left_exprs, PT_NODE * left_elist, XASL_NODE * rght, PT_NODE * rght_list,
46  BITSET * rght_exprs, PT_NODE * rght_elist);
47 static XASL_NODE *make_fetch_proc (QO_ENV * env, QO_PLAN * plan);
48 static XASL_NODE *make_buildlist_proc (QO_ENV * env, PT_NODE * namelist);
49 
50 static XASL_NODE *init_class_scan_proc (QO_ENV * env, XASL_NODE * xasl, QO_PLAN * plan);
51 static XASL_NODE *init_list_scan_proc (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * list, PT_NODE * namelist,
52  BITSET * predset, int *poslist);
53 
55 static XASL_NODE *add_scan_proc (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * scan);
56 static XASL_NODE *add_fetch_proc (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * proc);
57 static XASL_NODE *add_uncorrelated (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * sub);
58 static XASL_NODE *add_subqueries (QO_ENV * env, XASL_NODE * xasl, BITSET *);
59 static XASL_NODE *add_sort_spec (QO_ENV *, XASL_NODE *, QO_PLAN *, DB_VALUE *, bool);
62 
63 static PT_NODE *make_pred_from_bitset (QO_ENV * env, BITSET * predset, ELIGIBILITY_FN safe);
64 static void make_pred_from_plan (QO_ENV * env, QO_PLAN * plan, PT_NODE ** key_access_pred, PT_NODE ** access_pred,
65  QO_XASL_INDEX_INFO * qo_index_infop, PT_NODE ** hash_pred);
66 static PT_NODE *make_if_pred_from_plan (QO_ENV * env, QO_PLAN * plan);
67 static PT_NODE *make_instnum_pred_from_plan (QO_ENV * env, QO_PLAN * plan);
69 
72 static XASL_NODE *preserve_info (QO_ENV * env, QO_PLAN * plan, XASL_NODE * xasl);
73 
74 static int is_normal_access_term (QO_TERM *);
75 static int is_normal_if_term (QO_TERM *);
76 static int is_after_join_term (QO_TERM *);
77 static int is_totally_after_join_term (QO_TERM *);
78 static int is_follow_if_term (QO_TERM *);
79 static int is_always_true (QO_TERM *);
80 
82 static void qo_free_xasl_index_info (QO_ENV * env, QO_XASL_INDEX_INFO * info);
83 
84 static bool qo_validate_regu_var_for_limit (REGU_VARIABLE * var_p);
86  REGU_PTR_LIST * upper);
88  REGU_PTR_LIST * upper);
89 
91 static void regu_ptr_list_free (REGU_PTR_LIST list);
93 
94 static bool qo_check_seg_belongs_to_range_term (QO_PLAN * subplan, QO_ENV * env, int seg_idx);
95 static int qo_check_plan_index_for_multi_range_opt (PT_NODE * orderby_nodes, PT_NODE * orderby_sort_list,
96  QO_PLAN * plan, bool * is_valid, int *first_col_idx_pos,
97  bool * reverse);
98 static int qo_check_terms_for_multiple_range_opt (QO_PLAN * plan, int first_sort_col_idx, bool * can_optimize);
99 static bool qo_check_subqueries_for_multi_range_opt (QO_PLAN * plan, int sort_col_idx_pos);
100 
101 static int qo_check_subplans_for_multi_range_opt (QO_PLAN * parent, QO_PLAN * plan, QO_PLAN * sortplan, bool * is_valid,
102  bool * seen);
103 static bool qo_check_subplan_join_cond_for_multi_range_opt (QO_PLAN * parent, QO_PLAN * subplan, QO_PLAN * sort_plan);
104 static bool qo_check_parent_eq_class_for_multi_range_opt (QO_PLAN * parent, QO_PLAN * subplan, QO_PLAN * sort_plan);
105 static XASL_NODE *make_sort_limit_proc (QO_ENV * env, QO_PLAN * plan, PT_NODE * namelist, XASL_NODE * xasl);
107  bool * is_new_node);
108 static int qo_get_multi_col_range_segs (QO_ENV * env, QO_PLAN * plan, QO_INDEX_ENTRY * index_entryp,
109  BITSET * multi_col_segs, BITSET * multi_col_range_segs, BITSET * index_segs);
110 
111 /*
112  * make_scan_proc () -
113  * return: XASL_NODE *
114  * env(in): The optimizer environment
115  */
116 static XASL_NODE *
118 {
120 }
121 
122 
123 /*
124  * make_fetch_proc () -
125  * return:
126  * env(in):
127  * plan(in):
128  */
129 static XASL_NODE *
131 {
132  XASL_NODE *xasl;
133  PT_NODE *access_pred;
134  PT_NODE *if_pred;
135 
136  make_pred_from_plan (env, plan, NULL, &access_pred, NULL, NULL);
137  if_pred = make_if_pred_from_plan (env, plan);
138 
139  xasl =
140  pt_to_fetch_proc (QO_ENV_PARSER (env), QO_NODE_ENTITY_SPEC (QO_TERM_TAIL (plan->plan_un.follow.path)), access_pred);
141  xasl = add_if_predicate (env, xasl, if_pred);
142 
143  /* free pointer node list */
144  parser_free_tree (QO_ENV_PARSER (env), access_pred);
145  parser_free_tree (QO_ENV_PARSER (env), if_pred);
146 
147  return xasl;
148 }
149 
150 /*
151  * make_mergelist_proc () -
152  * return: XASL_NODE *
153  * env(in): The optimizer environment
154  * plan(in): The (sub)plan to generate code for merge
155  * left(in): The XASL node that should build a sorted outer result
156  * left_list(in): The expr, name list used to create the left XASL node
157  * left_exprs(in): The join terms bitset of left expr segs
158  * left_elist(in): The join terms expr list of left expr segs
159  * rght(in): The XASL node that should build a sorted inner result
160  * rght_list(in): The expr, name list used to create the right XASL node
161  * rght_exprs(in): The join terms bitset of right expr segs
162  * rght_elist(in): The join terms expr list of right expr segs
163  *
164  * Note: Make a MERGELIST_PROC XASL node that will eventually reside
165  * on the merge_list_ptr of some other XASL node.
166  * Thes initializes the left and right procs things
167  * live in such a specialized environment that there is no need
168  * to initialize anything other than the type and the access
169  * spec; the scan evidently uses the val_list, etc. from the
170  * outer block.
171  */
172 static XASL_NODE *
173 make_mergelist_proc (QO_ENV * env, QO_PLAN * plan, XASL_NODE * left, PT_NODE * left_list, BITSET * left_exprs,
174  PT_NODE * left_elist, XASL_NODE * rght, PT_NODE * rght_list, BITSET * rght_exprs,
175  PT_NODE * rght_elist)
176 {
177  XASL_NODE *merge = NULL;
179  QFILE_LIST_MERGE_INFO *ls_merge;
180  PT_NODE *outer_attr, *inner_attr;
181  int i, left_epos, rght_epos, cnt, seg_idx, ncols;
182  int left_nlen, left_elen, rght_nlen, rght_elen, nlen;
183  SORT_LIST *order, *prev_order;
184  QO_TERM *term;
185  BITSET_ITERATOR bi;
186  BITSET term_segs;
187 
188  bitset_init (&term_segs, env);
189 
190  if (env == NULL || plan == NULL)
191  {
192  goto exit_on_error;
193  }
194 
195  parser = QO_ENV_PARSER (env);
196 
197  merge = ptqo_to_merge_list_proc (parser, left, rght, plan->plan_un.join.join_type);
198 
199  if (merge == NULL || left == NULL || left_list == NULL || rght == NULL || rght_list == NULL)
200  {
201  goto exit_on_error;
202  }
203 
204  ls_merge = &merge->proc.mergelist.ls_merge;
205 
206  ls_merge->join_type = plan->plan_un.join.join_type;
207 
208  ncols = ls_merge->ls_column_cnt = bitset_cardinality (&(plan->plan_un.join.join_terms));
209  assert (ncols > 0);
210 
211  ls_merge->ls_outer_column = (int *) pt_alloc_packing_buf (ncols * sizeof (int));
212  if (ls_merge->ls_outer_column == NULL)
213  {
214  goto exit_on_error;
215  }
216 
217  ls_merge->ls_outer_unique = (int *) pt_alloc_packing_buf (ncols * sizeof (int));
218  if (ls_merge->ls_outer_unique == NULL)
219  {
220  goto exit_on_error;
221  }
222 
223  ls_merge->ls_inner_column = (int *) pt_alloc_packing_buf (ncols * sizeof (int));
224 
225  if (ls_merge->ls_inner_column == NULL)
226  {
227  goto exit_on_error;
228  }
229 
230  ls_merge->ls_inner_unique = (int *) pt_alloc_packing_buf (ncols * sizeof (int));
231  if (ls_merge->ls_inner_unique == NULL)
232  {
233  goto exit_on_error;
234  }
235 
236  left->orderby_list = NULL;
237  rght->orderby_list = NULL;
238 
239  cnt = 0; /* init */
240  left_epos = rght_epos = 0; /* init */
241  for (i = bitset_iterate (&(plan->plan_un.join.join_terms), &bi); i != -1; i = bitset_next_member (&bi))
242  {
243  term = QO_ENV_TERM (env, i);
244 
245  if (ls_merge->join_type == JOIN_INNER && QO_IS_PATH_TERM (term))
246  {
247  /* mark merge join spec as single-fetch */
248  ls_merge->single_fetch = QPROC_SINGLE_OUTER;
249  }
250 
251  if (BITSET_MEMBER (*left_exprs, i) && left_elist != NULL)
252  {
253  /* Then we added an "extra" column for the expression to the left_elist. We want to treat that expression as
254  * the outer expression, but we want to leave it off of the list of segments that are projected out of the
255  * merge. Take it off, but remember it in "outer_attr" so that we can fix up domain info in a little while. */
256  ls_merge->ls_outer_column[cnt] = left_epos++;
257  outer_attr = left_elist;
258  left_elist = left_elist->next;
259  }
260  else
261  {
262  /* Determine which attributes are involved in this predicate. */
263  bitset_assign (&term_segs, &(QO_TERM_SEGS (term)));
264  bitset_intersect (&term_segs, &((plan->plan_un.join.outer)->info->projected_segs));
265  seg_idx = bitset_first_member (&term_segs);
266  if (seg_idx == -1)
267  {
268  goto exit_on_error;
269  }
270 
271  outer_attr = QO_SEG_PT_NODE (QO_ENV_SEG (env, seg_idx));
272 
273  ls_merge->ls_outer_column[cnt] = pt_find_attribute (parser, outer_attr, left_list);
274  }
275  ls_merge->ls_outer_unique[cnt] = false; /* currently, unused */
276 
277  if (BITSET_MEMBER (*rght_exprs, i) && rght_elist != NULL)
278  {
279  /* This situation is exactly analogous to the one above, except that we're concerned with the right (inner)
280  * side this time. */
281  ls_merge->ls_inner_column[cnt] = rght_epos++;
282  inner_attr = rght_elist;
283  rght_elist = rght_elist->next;
284  }
285  else
286  {
287  /* Determine which attributes are involved in this predicate. */
288  bitset_assign (&term_segs, &(QO_TERM_SEGS (term)));
289  bitset_intersect (&term_segs, &((plan->plan_un.join.inner)->info->projected_segs));
290  seg_idx = bitset_first_member (&term_segs);
291  if (seg_idx == -1)
292  {
293  goto exit_on_error;
294  }
295 
296  inner_attr = QO_SEG_PT_NODE (QO_ENV_SEG (env, seg_idx));
297 
298  ls_merge->ls_inner_column[cnt] = pt_find_attribute (parser, inner_attr, rght_list);
299  }
300  ls_merge->ls_inner_unique[cnt] = false; /* currently, unused */
301 
302  /* set outer list order entry */
303  prev_order = NULL;
304  for (order = left->orderby_list; order; order = order->next)
305  {
306  if (order->pos_descr.pos_no == ls_merge->ls_outer_column[cnt])
307  {
308  /* found order entry */
309  break;
310  }
311  prev_order = order;
312  }
313 
314  /* not found outer order entry */
315  if (order == NULL)
316  {
317  order = ptqo_single_orderby (parser);
318  if (order == NULL)
319  {
320  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, "left_order != NULL");
321  goto exit_on_error;
322  }
323 
324  order->s_order = S_ASC;
325  order->pos_descr.pos_no = ls_merge->ls_outer_column[cnt];
326  order->pos_descr.dom = pt_xasl_node_to_domain (parser, outer_attr);
327  if (prev_order == NULL)
328  {
329  left->orderby_list = order;
330  }
331  else
332  {
333  prev_order->next = order;
334  }
335  }
336 
337  /* set inner list order entry */
338  prev_order = NULL;
339  for (order = rght->orderby_list; order; order = order->next)
340  {
341  if (order->pos_descr.pos_no == ls_merge->ls_inner_column[cnt])
342  {
343  /* found order entry */
344  break;
345  }
346  prev_order = order;
347  }
348 
349  /* not found inner order entry */
350  if (order == NULL)
351  {
352  order = ptqo_single_orderby (parser);
353  if (order == NULL)
354  {
355  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, "right_order != NULL");
356  goto exit_on_error;
357  }
358 
359  order->s_order = S_ASC;
360  order->pos_descr.pos_no = ls_merge->ls_inner_column[cnt];
361  order->pos_descr.dom = pt_xasl_node_to_domain (parser, inner_attr);
362  if (prev_order == NULL)
363  {
364  rght->orderby_list = order;
365  }
366  else
367  {
368  prev_order->next = order;
369  }
370  }
371 
372  cnt++;
373  } /* for (i = ... ) */
374  assert (cnt == ncols);
375 
376  left_elen = bitset_cardinality (left_exprs);
377  left_nlen = pt_length_of_list (left_list) - left_elen;
378  rght_elen = bitset_cardinality (rght_exprs);
379  rght_nlen = pt_length_of_list (rght_list) - rght_elen;
380 
381  nlen = ls_merge->ls_pos_cnt = left_nlen + rght_nlen;
382  ls_merge->ls_outer_inner_list = (int *) pt_alloc_packing_buf (nlen * sizeof (int));
383  if (ls_merge->ls_outer_inner_list == NULL)
384  {
385  goto exit_on_error;
386  }
387 
388  ls_merge->ls_pos_list = (int *) pt_alloc_packing_buf (nlen * sizeof (int));
389  if (ls_merge->ls_pos_list == NULL)
390  {
391  goto exit_on_error;
392  }
393 
394  /* these could be sorted out arbitrily. This could make it easier to avoid the wrapper buildlist_proc, when no
395  * expressions, predicates, subqueries, fetches, or aggregation is involved. For now, we always build the same thing,
396  * with simple column concatenation. */
397 
398  for (i = 0; i < left_nlen; i++)
399  {
401  ls_merge->ls_pos_list[i] = i + left_elen;
402  }
403 
404  for (i = 0; i < nlen - left_nlen; i++)
405  {
406  ls_merge->ls_outer_inner_list[left_nlen + i] = QFILE_INNER_LIST;
407  ls_merge->ls_pos_list[left_nlen + i] = i + rght_elen;
408  }
409 
410  /* make outer_spec_list, outer_val_list, inner_spec_list, and inner_val_list */
411  if (ls_merge->join_type != JOIN_INNER)
412  {
413  PT_NODE *other_pred;
414  int *poslist;
415 
416  /* set poslist of outer XASL node */
417  poslist = NULL; /* init */
418  if (left_elen > 0)
419  {
420  /* proceed to name list and skip out join edge exprs */
421  for (i = 0; i < left_elen; i++)
422  {
423  left_list = left_list->next;
424  }
425 
426  poslist = (int *) malloc (left_nlen * sizeof (int));
427  if (poslist == NULL)
428  {
429  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, left_nlen * sizeof (int));
430  goto exit_on_error;
431  }
432 
433  for (i = 0; i < left_nlen; i++)
434  {
435  poslist[i] = i + left_elen;
436  }
437  }
438 
439  /* sets xasl->spec_list and xasl->val_list */
440  merge = ptqo_to_list_scan_proc (parser, merge, SCAN_PROC, left, left_list, NULL, poslist);
441  /* dealloc */
442  if (poslist != NULL)
443  {
444  free_and_init (poslist);
445  }
446 
447  if (merge == NULL)
448  {
449  goto exit_on_error;
450  }
451 
452  merge->proc.mergelist.outer_spec_list = merge->spec_list;
453  merge->proc.mergelist.outer_val_list = merge->val_list;
454 
455  /* set poslist of inner XASL node */
456  poslist = NULL; /* init */
457  if (rght_elen > 0)
458  {
459  /* proceed to name list and skip out join edge exprs */
460  for (i = 0; i < rght_elen; i++)
461  {
462  rght_list = rght_list->next;
463  }
464 
465  poslist = (int *) malloc (rght_nlen * sizeof (int));
466  if (poslist == NULL)
467  {
468  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, rght_nlen * sizeof (int));
469  goto exit_on_error;
470  }
471 
472  for (i = 0; i < rght_nlen; i++)
473  {
474  poslist[i] = i + rght_elen;
475  }
476  }
477 
478  /* sets xasl->spec_list and xasl->val_list */
479  merge = ptqo_to_list_scan_proc (parser, merge, SCAN_PROC, rght, rght_list, NULL, poslist);
480  /* dealloc */
481  if (poslist)
482  {
483  free_and_init (poslist);
484  }
485 
486  if (merge == NULL)
487  {
488  goto exit_on_error;
489  }
490 
491  merge->proc.mergelist.inner_spec_list = merge->spec_list;
492  merge->proc.mergelist.inner_val_list = merge->val_list;
493 
494  merge->spec_list = NULL;
495  merge->val_list = NULL;
496 
497  /* add outer join terms */
498  other_pred = make_pred_from_bitset (env, &(plan->plan_un.join.during_join_terms), is_always_true);
499  if (other_pred)
500  {
501  merge->after_join_pred = pt_to_pred_expr (parser, other_pred);
502 
503  /* free pointer node list */
504  parser_free_tree (parser, other_pred);
505  }
506  }
507  else
508  {
513  }
514 
515 exit_on_end:
516 
517  bitset_delset (&term_segs);
518 
519  return merge;
520 
521 exit_on_error:
522 
523  merge = NULL;
524  goto exit_on_end;
525 }
526 
527 /*
528  * make_buildlist_proc () -
529  * return: XASL_NODE *
530  * env(in): The optimizer environment
531  * namelist(in): The list of names to use as input to and output from this
532  * node
533  */
534 static XASL_NODE *
535 make_buildlist_proc (QO_ENV * env, PT_NODE * namelist)
536 {
537  return pt_skeleton_buildlist_proc (QO_ENV_PARSER (env), namelist);
538 }
539 
540 /*
541  * bitset_has_path () -
542  * return: int 1 iff path term is present, 0 otherwise
543  * env(in): The optimizer environment
544  * predset(in): The bitset of predicates to turn into a predicate tree
545  */
546 static int
547 bitset_has_path (QO_ENV * env, BITSET * predset)
548 {
549  BITSET_ITERATOR bi;
550  int i;
551 
552  for (i = bitset_iterate (predset, &bi); i != -1; i = bitset_next_member (&bi))
553  {
554  QO_TERM *term;
555 
556  term = QO_ENV_TERM (env, i);
557  if (QO_IS_PATH_TERM (term))
558  {
559  return 1;
560  }
561  }
562 
563  return 0;
564 }
565 
566 /*
567  * mark_access_as_outer_join () - mark aan xasl proc's access spec
568  * as left outer join
569  * return:
570  * parser(in): The parser environment
571  * xasl(in): The already allocated node to be initialized
572  */
573 static void
575 {
576  ACCESS_SPEC_TYPE *access;
577 
578  for (access = xasl->spec_list; access; access = access->next)
579  {
581  }
582 }
583 
584 /*
585  * init_class_scan_proc () -
586  * return: XASL_NODE *
587  * env(in): The optimizer environment
588  * xasl(in): The already allocated node to be initialized
589  * plan(in): The plan from which to initialize the scan proc
590  *
591  * Note: Take a BUILDwhatever skeleton and flesh it out as a scan
592  * gadget. Don't mess with any other fields than you absolutely
593  * must: they may have already been initialized by other
594  * routines.
595  */
596 static XASL_NODE *
598 {
600  PT_NODE *spec;
601  PT_NODE *key_pred;
602  PT_NODE *access_pred, *hash_pred;
603  PT_NODE *if_pred;
604  PT_NODE *after_join_pred;
605  QO_XASL_INDEX_INFO *info;
606 
607  parser = QO_ENV_PARSER (env);
608 
609  spec = QO_NODE_ENTITY_SPEC (plan->plan_un.scan.node);
610 
611  info = qo_get_xasl_index_info (env, plan);
612  make_pred_from_plan (env, plan, &key_pred, &access_pred, info, &hash_pred);
613  xasl = ptqo_to_scan_proc (parser, plan, xasl, spec, key_pred, access_pred, info, hash_pred);
614 
615  /* free pointer node list */
616  parser_free_tree (parser, key_pred);
617  parser_free_tree (parser, access_pred);
618 
619  if (xasl)
620  {
621  after_join_pred = make_pred_from_bitset (env, &(plan->sarged_terms), is_after_join_term);
622  if_pred = make_if_pred_from_plan (env, plan);
623 
624  xasl = add_after_join_predicate (env, xasl, after_join_pred);
625  xasl = add_if_predicate (env, xasl, if_pred);
626 
627  /* free pointer node list */
628  parser_free_tree (parser, after_join_pred);
629  parser_free_tree (parser, if_pred);
630  }
631 
632  if (info)
633  {
634  qo_free_xasl_index_info (env, info);
635  }
636 
637  return xasl;
638 }
639 
640 /*
641  * init_list_scan_proc () -
642  * return: XASL_NODE *
643  * env(in): The optimizer environment
644  * xasl(in): The already allocated node to be initialized
645  * listfile(in): The buildlist proc node for the list file to be scanned
646  * namelist(in): The list of names (columns) to be retrieved from the file
647  * predset(in): A bitset of predicates to be added to the access spec
648  * poslist(in):
649  *
650  * Note: Take a BUILDwhatever skeleton and flesh it out as a scan
651  * gadget. Don't mess with any other fields than you absolutely
652  * must: they may have already been initialized by other
653  * routines.
654  */
655 static XASL_NODE *
656 init_list_scan_proc (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * listfile, PT_NODE * namelist, BITSET * predset,
657  int *poslist)
658 {
659  PT_NODE *access_pred, *if_pred, *after_join_pred, *instnum_pred;
660 
661  if (xasl)
662  {
663  access_pred = make_pred_from_bitset (env, predset, is_normal_access_term);
664  if_pred = make_pred_from_bitset (env, predset, is_normal_if_term);
665  after_join_pred = make_pred_from_bitset (env, predset, is_after_join_term);
666  instnum_pred = make_pred_from_bitset (env, predset, is_totally_after_join_term);
667 
668  xasl = ptqo_to_list_scan_proc (QO_ENV_PARSER (env), xasl, SCAN_PROC, listfile, namelist, access_pred, poslist);
669 
671  {
672  pt_set_level_node_etc (QO_ENV_PARSER (env), if_pred, &xasl->level_val);
673  pt_set_isleaf_node_etc (QO_ENV_PARSER (env), if_pred, &xasl->isleaf_val);
674  pt_set_iscycle_node_etc (QO_ENV_PARSER (env), if_pred, &xasl->iscycle_val);
675  pt_set_connect_by_operator_node_etc (QO_ENV_PARSER (env), if_pred, xasl);
676  pt_set_qprior_node_etc (QO_ENV_PARSER (env), if_pred, xasl);
677  }
678 
679  xasl = add_if_predicate (env, xasl, if_pred);
680  xasl = add_after_join_predicate (env, xasl, after_join_pred);
681  xasl = pt_to_instnum_pred (QO_ENV_PARSER (env), xasl, instnum_pred);
682 
683  /* free pointer node list */
684  parser_free_tree (QO_ENV_PARSER (env), access_pred);
685  parser_free_tree (QO_ENV_PARSER (env), if_pred);
686  parser_free_tree (QO_ENV_PARSER (env), after_join_pred);
687  parser_free_tree (QO_ENV_PARSER (env), instnum_pred);
688  }
689 
690  return xasl;
691 }
692 
693 /*
694  * add_access_spec () -
695  * return: XASL_NODE *
696  * env(in): The optimizer environment
697  * xasl(in): The XASL block to twiddle
698  * plan(in):
699  */
700 static XASL_NODE *
701 add_access_spec (QO_ENV * env, XASL_NODE * xasl, QO_PLAN * plan)
702 {
704  PT_NODE *class_spec;
705  PT_NODE *key_pred = NULL;
706  PT_NODE *access_pred = NULL;
707  PT_NODE *if_pred = NULL;
708  PT_NODE *instnum_pred = NULL;
709  QO_XASL_INDEX_INFO *info = NULL;
710 
711  if (!xasl)
712  { /* may be invalid argument */
713  return xasl;
714  }
715 
716  assert (plan->plan_type == QO_PLANTYPE_SCAN);
717 
718  parser = QO_ENV_PARSER (env);
719 
720  class_spec = QO_NODE_ENTITY_SPEC (plan->plan_un.scan.node);
721 
722  /* set the type for XASL generation */
723  if (PT_IS_VALUE_QUERY (env->pt_tree))
724  {
725  PT_SET_VALUE_QUERY (class_spec);
726  }
727 
728  info = qo_get_xasl_index_info (env, plan);
729  make_pred_from_plan (env, plan, &key_pred, &access_pred, info, NULL);
730 
731  xasl->spec_list = pt_to_spec_list (parser, class_spec, key_pred, access_pred, plan, info, NULL, NULL);
732  if (xasl->spec_list == NULL)
733  {
734  goto exit_on_error;
735  }
736 
737  xasl->val_list = pt_to_val_list (parser, class_spec->info.spec.id);
738  if (xasl->val_list == NULL)
739  {
740  goto exit_on_error;
741  }
742 
743  if_pred = make_if_pred_from_plan (env, plan);
744  instnum_pred = make_instnum_pred_from_plan (env, plan);
745 
747  {
748  pt_set_level_node_etc (parser, if_pred, &xasl->level_val);
749  pt_set_isleaf_node_etc (parser, if_pred, &xasl->isleaf_val);
750  pt_set_iscycle_node_etc (parser, if_pred, &xasl->iscycle_val);
751  pt_set_connect_by_operator_node_etc (parser, if_pred, xasl);
752  pt_set_qprior_node_etc (parser, if_pred, xasl);
753  }
754 
755  xasl = add_if_predicate (env, xasl, if_pred);
756  xasl = pt_to_instnum_pred (QO_ENV_PARSER (env), xasl, instnum_pred);
757 
758 success:
759 
760  /* free pointer node list */
761  parser_free_tree (parser, key_pred);
762  parser_free_tree (parser, access_pred);
763  parser_free_tree (parser, if_pred);
764  parser_free_tree (parser, instnum_pred);
765 
766  qo_free_xasl_index_info (env, info);
767 
768  return xasl;
769 
770 exit_on_error:
771 
772  xasl = NULL;
773  goto success;
774 }
775 
776 /*
777  * add_scan_proc () - Add the scan proc to the end of xasl's scan_ptr list
778  * return: XASL_NODE *
779  * env(in): The optimizer environment
780  * xasl(in): The XASL block to receive the scan block
781  * scan(in): The scanproc to be added
782  */
783 static XASL_NODE *
784 add_scan_proc (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * scan)
785 {
786  XASL_NODE *xp;
787 
788  if (xasl)
789  {
790  for (xp = xasl; xp->scan_ptr; xp = xp->scan_ptr)
791  ;
792  xp->scan_ptr = scan;
793  }
794  else
795  xasl = NULL;
796 
797  return xasl;
798 }
799 
800 /*
801  * add_fetch_proc () - Create a fetch proc and add it to the *head*
802  * of the list of fetch procs in xasl->fptr
803  * return: XASL_NODE *
804  * env(in): The optimizer environment
805  * xasl(in): The XASL block to receive the fetch block
806  * procs(in): The fetch proc to be added
807  */
808 static XASL_NODE *
809 add_fetch_proc (QO_ENV * env, XASL_NODE * xasl, XASL_NODE * procs)
810 {
811  XASL_NODE *f;
812 
813  if (xasl)
814  {
815  /*
816  * The idea here is that we want these fetches to run *every
817  * time* a new candidate row is produced by xasl, which means
818  * they should go at the end of this proc's fptr_list.
819  */
820  for (f = xasl; f->fptr_list; f = f->fptr_list)
821  ;
822  f->fptr_list = procs;
823  }
824  else
825  {
826  xasl = NULL;
827  }
828 
829  return xasl;
830 }
831 
832 /*
833  * add_uncorrelated () - Add the scan proc to the *head* of the list of
834  * scanprocs in xasl->scan_ptr
835  * return: XASL_NODE *
836  * env(in): The optimizer environment
837  * xasl(in): The XASL block to receive the scan block
838  * sub(in): The XASL thing to be added to xasl's list of uncorrelated
839  * "subqueries"
840  */
841 static XASL_NODE *
843 {
844 
845  if (xasl && sub)
846  {
847  xasl->aptr_list = pt_remove_xasl (pt_append_xasl (xasl->aptr_list, sub), xasl);
848  }
849  else
850  {
851  xasl = NULL;
852  }
853 
854  return xasl;
855 }
856 
857 /*
858  * add_subqueries () - Add the xasl trees for the subqueries to the xasl node
859  * return: XASL_NODE *
860  * env(in): The optimizer environment
861  * xasl(in): The XASL block to receive the scan block
862  * subqueries(in): A bitset representing the correlated subqueries that
863  * should be tacked onto xasl
864  *
865  * Note: Because of the way the outer driver controls
866  * things, we never have to worry about subqueries that nested
867  * deeper than one, so there is no ordering that needs to be
868  * maintained here; we can just put these guys on the d-list in
869  * any convenient order.
870  */
871 static XASL_NODE *
872 add_subqueries (QO_ENV * env, XASL_NODE * xasl, BITSET * subqueries)
873 {
874  BITSET_ITERATOR bi;
875  int i;
876  XASL_NODE *sub_xasl;
877  QO_SUBQUERY *subq;
878 
879  if (xasl)
880  {
881  for (i = bitset_iterate (subqueries, &bi); i != -1; i = bitset_next_member (&bi))
882  {
883  subq = &env->subqueries[i];
884  sub_xasl = (XASL_NODE *) subq->node->info.query.xasl;
885  if (sub_xasl)
886  {
887  if (bitset_is_empty (&(subq->nodes)))
888  { /* uncorrelated */
889  xasl->aptr_list = pt_remove_xasl (pt_append_xasl (xasl->aptr_list, sub_xasl), xasl);
890  }
891  else
892  { /* correlated */
893  xasl->dptr_list = pt_remove_xasl (pt_append_xasl (xasl->dptr_list, sub_xasl), xasl);
894  }
895  }
896  }
897  }
898 
899  return xasl;
900 }
901 
902 /*
903  * add_sort_spec () -
904  * return: XASL_NODE *
905  * env(in): The optimizer environment
906  * xasl(in): The XASL node that should build a sorted result
907  * plan(in): The plan that needs sorting
908  * instnum_flag(in): instnum indicator
909  */
910 static XASL_NODE *
911 add_sort_spec (QO_ENV * env, XASL_NODE * xasl, QO_PLAN * plan, DB_VALUE * ordby_val, bool instnum_flag)
912 {
913  QO_PLAN *subplan;
914 
915  subplan = plan->plan_un.sort.subplan;
916 
917  /*
918  * xasl->orderby_list for m-join is added in make_mergelist_proc()
919  */
920 
921  if (instnum_flag)
922  {
923  if (xasl && subplan->plan_type == QO_PLANTYPE_JOIN
924  && subplan->plan_un.join.join_method == QO_JOINMETHOD_MERGE_JOIN)
925  {
926  PT_NODE *instnum_pred;
927 
928  instnum_pred = make_instnum_pred_from_plan (env, plan);
929  xasl = pt_to_instnum_pred (QO_ENV_PARSER (env), xasl, instnum_pred);
930  /* free pointer node list */
931  parser_free_tree (QO_ENV_PARSER (env), instnum_pred);
932  }
933  }
934 
935  if (xasl && plan->plan_un.sort.sort_type == SORT_LIMIT)
936  {
937  /* setup ORDER BY list here */
938  int ordbynum_flag;
939  QO_LIMIT_INFO *limit_infop;
941  PT_NODE *query = QO_ENV_PT_TREE (env);
942  PT_NODE *upper_bound = NULL, *save_next = NULL;
943  bool free_upper_bound = false;
944 
945  xasl->orderby_list = pt_to_orderby (parser, query->info.query.order_by, query);
947 
948  xasl->orderby_limit = NULL;
949  /* A SORT-LIMIT plan can only handle the upper limit of the orderby_num predicate. This is because the
950  * orderby_num pred will be applied twice: once for the SORT-LIMIT plan and once for the top plan. If the lower
951  * bound is evaluated twice, some tuples are lost. */
952  upper_bound = query->info.query.orderby_for;
953  upper_bound = qo_get_orderby_num_upper_bound_node (parser, upper_bound, &free_upper_bound);
954  if (upper_bound == NULL)
955  {
956  /* Must have an upper limit if we're considering a SORT-LIMIT plan. */
957  return NULL;
958  }
959  save_next = upper_bound->next;
960  upper_bound->next = NULL;
961  ordbynum_flag = 0;
962  xasl->ordbynum_pred = pt_to_pred_expr_with_arg (parser, upper_bound, &ordbynum_flag);
963  upper_bound->next = save_next;
964  if (free_upper_bound)
965  {
966  parser_free_tree (parser, upper_bound);
967  }
968 
969  if (ordbynum_flag & PT_PRED_ARG_ORDBYNUM_CONTINUE)
970  {
972  }
973  limit_infop = qo_get_key_limit_from_ordbynum (parser, plan, xasl, false);
974  if (limit_infop)
975  {
976  xasl->orderby_limit = limit_infop->upper;
977  db_private_free (NULL, limit_infop);
978  }
979  xasl->ordbynum_val = ordby_val;
980  }
981 
982  return xasl;
983 }
984 
985 /*
986  * add_if_predicate () - Tack the predicate onto the XASL node's if_pred list
987  * return: XASL_NODE *
988  * env(in): The optimizer environment
989  * xasl(in): The XASL block to which we should add the predicate
990  * pred(in): The pt predicate to tacked on to xasl
991  */
992 static XASL_NODE *
993 add_if_predicate (QO_ENV * env, XASL_NODE * xasl, PT_NODE * pred)
994 {
996 
997  if (xasl && pred)
998  {
999  parser = QO_ENV_PARSER (env);
1000  xasl->if_pred = pt_to_pred_expr (parser, pred);
1001  }
1002 
1003  return xasl;
1004 }
1005 
1006 /*
1007  * add_after_join_predicate () -
1008  * return:
1009  * env(in):
1010  * xasl(in):
1011  * pred(in):
1012  */
1013 static XASL_NODE *
1015 {
1017 
1018  if (xasl && pred)
1019  {
1020  parser = QO_ENV_PARSER (env);
1021  xasl->after_join_pred = pt_to_pred_expr (parser, pred);
1022  }
1023 
1024  return xasl;
1025 }
1026 
1027 /*
1028  * path_access_term () -
1029  * return:
1030  * term(in):
1031  */
1032 static int
1034 {
1035  return QO_IS_PATH_TERM (term);
1036 }
1037 
1038 /*
1039  * path_if_term () -
1040  * return:
1041  * term(in):
1042  */
1043 static int
1045 {
1046  return !QO_IS_PATH_TERM (term) && !is_totally_after_join_term (term);
1047 }
1048 
1049 /*
1050  * is_normal_access_term () -
1051  * return:
1052  * term(in):
1053  */
1054 static int
1056 {
1057  if (!bitset_is_empty (&(QO_TERM_SUBQUERIES (term))))
1058  {
1059  return 0;
1060  }
1061 
1062  if (QO_TERM_CLASS (term) == QO_TC_OTHER
1063  /* || QO_TERM_CLASS(term) == QO_TC_DURING_JOIN || */
1064  /* nl outer join treats during join terms as sarged terms of inner */
1066  {
1067  return 0;
1068  }
1069 
1070  return 1;
1071 }
1072 
1073 /*
1074  * is_normal_if_term () -
1075  * return:
1076  * term(in):
1077  */
1078 static int
1080 {
1081  if (!bitset_is_empty (&(QO_TERM_SUBQUERIES (term))))
1082  {
1083  return 1;
1084  }
1085  if (QO_TERM_CLASS (term) == QO_TC_OTHER)
1086  {
1087  return 1;
1088  }
1089 
1090  return 0;
1091 }
1092 
1093 /*
1094  * is_after_join_term () -
1095  * return:
1096  * term(in):
1097  */
1098 static int
1100 {
1101  if (!bitset_is_empty (&(QO_TERM_SUBQUERIES (term))))
1102  {
1103  return 0;
1104  }
1105  if (QO_TERM_CLASS (term) == QO_TC_AFTER_JOIN)
1106  {
1107  return 1;
1108  }
1109 
1110  return 0;
1111 }
1112 
1113 /*
1114  * is_totally_after_join_term () -
1115  * return:
1116  * term(in):
1117  */
1118 static int
1120 {
1121  if (!bitset_is_empty (&(QO_TERM_SUBQUERIES (term))))
1122  {
1123  return 0;
1124  }
1126  {
1127  return 1;
1128  }
1129 
1130  return 0;
1131 }
1132 
1133 /*
1134  * is_follow_if_term () -
1135  * return:
1136  * term(in):
1137  */
1138 static int
1140 {
1141  if (QO_TERM_CLASS (term) == QO_TC_DURING_JOIN /* ? */
1143  {
1144  return 0;
1145  }
1146 
1147  return 1;
1148 }
1149 
1150 /*
1151  * is_always_true () -
1152  * return:
1153  * term(in):
1154  */
1155 static int
1157 {
1158  return true;
1159 }
1160 
1161 /*
1162  * make_pred_from_bitset () -
1163  * return: PT_NODE *
1164  * env(in): The optimizer environment
1165  * predset(in): The bitset of predicates to turn into a predicate tree
1166  * safe(in): A function to test whether a particular term should be
1167  * put on a predicate
1168  *
1169  * Note: make pred_info * style predicates from a bitset of conjuncts.
1170  * use only those conjuncts that can be put on an access pred.
1171  */
1172 static PT_NODE *
1174 {
1176  PT_NODE *pred_list, *pointer, *prev, *curr;
1177  BITSET_ITERATOR bi;
1178  int i;
1179  QO_TERM *term;
1180  bool found;
1181  PT_NODE *pt_expr;
1182  double cmp;
1183 
1184  parser = QO_ENV_PARSER (env);
1185 
1186  pred_list = NULL; /* init */
1187  for (i = bitset_iterate (predset, &bi); i != -1; i = bitset_next_member (&bi))
1188  {
1189  term = QO_ENV_TERM (env, i);
1190 
1191  /* Don't ever let one of our fabricated terms find its way into the predicate; that will cause serious confusion. */
1192  if (QO_IS_FAKE_TERM (term) || !(*safe) (term))
1193  {
1194  continue;
1195  }
1196 
1197  /* We need to use predicate pointer. modifying WHERE clause structure in place gives us no way to compile the
1198  * query if the optimizer bails out. */
1199  pt_expr = QO_TERM_PT_EXPR (term);
1200  if (pt_expr == NULL)
1201  {
1202  /* is possible ? */
1203  goto exit_on_error;
1204  }
1205  pointer = pt_point (parser, pt_expr);
1206  if (pointer == NULL)
1207  {
1208  goto exit_on_error;
1209  }
1210 
1211  /* set AND predicate evaluation selectivity, rank; */
1212  pointer->info.pointer.sel = QO_TERM_SELECTIVITY (term);
1213  pointer->info.pointer.rank = QO_TERM_RANK (term);
1214 
1215  /* insert to the AND predicate list by descending order of (selectivity, rank) vector; this order is used at
1216  * pt_to_pred_expr_with_arg() */
1217  found = false; /* init */
1218  prev = NULL; /* init */
1219  for (curr = pred_list; curr; curr = curr->next)
1220  {
1221  cmp = curr->info.pointer.sel - pointer->info.pointer.sel;
1222 
1223  if (cmp == 0)
1224  { /* same selectivity, re-compare rank */
1225  cmp = curr->info.pointer.rank - pointer->info.pointer.rank;
1226  }
1227 
1228  if (cmp <= 0)
1229  {
1230  pointer->next = curr;
1231  if (prev == NULL)
1232  { /* very the first */
1233  pred_list = pointer;
1234  }
1235  else
1236  {
1237  prev->next = pointer;
1238  }
1239  found = true;
1240  break;
1241  }
1242 
1243  prev = curr;
1244  }
1245 
1246  /* append to the predicate list */
1247  if (found == false)
1248  {
1249  if (prev == NULL)
1250  { /* very the first */
1251  pointer->next = pred_list;
1252  pred_list = pointer;
1253  }
1254  else
1255  { /* very the last */
1256  prev->next = pointer;
1257  }
1258  }
1259  }
1260 
1261  return pred_list;
1262 
1263 exit_on_error:
1264 
1265  if (pred_list)
1266  {
1267  parser_free_tree (parser, pred_list);
1268  }
1269 
1270  return NULL;
1271 }
1272 
1273 /*
1274  * make_pred_from_plan () -
1275  * return:
1276  * env(in): The optimizer environment
1277  * plan(in): Query plan
1278  * key_predp(in): Index information of query plan.
1279  * Predicate tree to be used as key filter
1280  * predp(in): Predicate tree to be used as data filter
1281  * qo_index_infop(in):
1282  *
1283  * Note: Make a PT_NODE * style predicate from a bitset of conjuncts.
1284  * Splits sargs into key filter predicates and data filter predicates.
1285  */
1286 static void
1287 make_pred_from_plan (QO_ENV * env, QO_PLAN * plan, PT_NODE ** key_predp, PT_NODE ** predp,
1288  QO_XASL_INDEX_INFO * qo_index_infop, PT_NODE ** hash_predp)
1289 {
1290  QO_INDEX_ENTRY *index_entryp = NULL;
1291 
1292  /* initialize output parameter */
1293  if (key_predp != NULL)
1294  {
1295  *key_predp = NULL;
1296  }
1297  if (predp != NULL)
1298  {
1299  *predp = NULL;
1300  }
1301  if (hash_predp != NULL)
1302  {
1303  *hash_predp = NULL;
1304  }
1305 
1306  if (plan->plan_type == QO_PLANTYPE_FOLLOW)
1307  {
1308  /* Don't allow predicates to migrate to fetch_proc access specs; the special handling of NULL doesn't look at the
1309  * access spec, so it will miss predicates that are deposited there. Always put these things on the if_pred for
1310  * now. This needs to get fixed. >>>> Note the same problem is encountered when emulating follow with >>>> joins.
1311  * The access pred must return a row, even if its null. >>>> the rest or the predicate may then be applied. */
1312  return;
1313  }
1314 
1315  /* This is safe guard code - DO NOT DELETE ME */
1316  do
1317  {
1318  /* exclude key-range terms from key-filter terms */
1319  bitset_difference (&(plan->plan_un.scan.kf_terms), &(plan->plan_un.scan.terms));
1320 
1321  /* exclude key-range terms from sarged terms */
1322  bitset_difference (&(plan->sarged_terms), &(plan->plan_un.scan.terms));
1323  /* exclude key-filter terms from sarged terms */
1324  bitset_difference (&(plan->sarged_terms), &(plan->plan_un.scan.kf_terms));
1325  }
1326  while (0);
1327 
1328  /* make predicate list for hash key */
1329  if (hash_predp != NULL)
1330  {
1331  *hash_predp = make_pred_from_bitset (env, &(plan->plan_un.scan.hash_terms), is_always_true);
1332  }
1333  /* if key filter(predicates) is not required */
1334  if (predp != NULL && (key_predp == NULL || qo_index_infop == NULL))
1335  {
1336  *predp = (make_pred_from_bitset (env, &(plan->sarged_terms), bitset_has_path (env, &(plan->sarged_terms))
1338  return;
1339  }
1340 
1341  /* make predicate list for key filter */
1342  if (key_predp != NULL)
1343  {
1344  if (qo_index_infop && qo_index_infop->need_copy_multi_range_term != -1 && qo_index_infop->need_copy_to_sarg_term)
1345  {
1346  bitset_add (&(plan->sarged_terms), qo_index_infop->need_copy_multi_range_term);
1347  }
1348  else if (qo_index_infop->need_copy_multi_range_term != -1)
1349  {
1350  index_entryp = qo_index_infop->ni_entry->head;
1351  if (index_entryp && index_entryp->constraints && index_entryp->constraints->func_index_info
1352  && index_entryp->cover_segments == false)
1353  {
1354  /* if predicate has function index column then do not permit key-filter. so force-copy to sarg */
1355  bitset_add (&(plan->sarged_terms), qo_index_infop->need_copy_multi_range_term);
1356  }
1357  else
1358  {
1359  /*force-copy multi col range pred to key filter */
1360  bitset_add (&(plan->plan_un.scan.kf_terms), qo_index_infop->need_copy_multi_range_term);
1361  }
1362  }
1363  *key_predp = make_pred_from_bitset (env, &(plan->plan_un.scan.kf_terms), is_always_true);
1364  }
1365 
1366  /* make predicate list for data filter */
1367  if (predp != NULL)
1368  {
1369  *predp = (make_pred_from_bitset (env, &(plan->sarged_terms), bitset_has_path (env, &(plan->sarged_terms))
1371  }
1372 }
1373 
1374 /*
1375  * make_if_pred_from_plan () -
1376  * return:
1377  * env(in):
1378  * plan(in):
1379  */
1380 static PT_NODE *
1382 {
1383  ELIGIBILITY_FN test;
1384 
1385  if (plan->plan_type == QO_PLANTYPE_FOLLOW)
1386  {
1387  /*
1388  * Put all predicates on the if_pred right now, because the "dead
1389  * end" handling for NULLs won't look at predicates on the access
1390  * spec.
1391  *
1392  * This needs to get fixed.
1393  */
1394  test = is_follow_if_term;
1395  }
1396  else
1397  {
1398  test = bitset_has_path (env, &(plan->sarged_terms)) ? path_if_term : is_normal_if_term;
1399  }
1400 
1401  return make_pred_from_bitset (env, &(plan->sarged_terms), test);
1402 }
1403 
1404 /*
1405  * make_instnum_pred_from_plan () -
1406  * return:
1407  * env(in):
1408  * plan(in):
1409  */
1410 static PT_NODE *
1412 {
1413  /* is it enough? */
1415 }
1416 
1417 /*
1418  * make_namelist_from_projected_segs () -
1419  * return: PT_NODE *
1420  * env(in): The optimizer environment
1421  * plan(in): he plan whose projected segments need to be put into a name list
1422  *
1423  * Note: Take a bitset of segment indexes and produce a name list
1424  * suitable for creating the outptr_list member of a buildlist
1425  * proc. This is used by the creators of temporary list files:
1426  * merge joins and sorts.
1427  *
1428  * In the interests of sanity, the elements in the list appear
1429  * in the same order as the indexes in the scan of the bitset.
1430  */
1431 static PT_NODE *
1433 {
1435  PT_NODE *namelist;
1436  PT_NODE **namelistp;
1437  BITSET_ITERATOR bi;
1438  int i;
1439 
1440  parser = QO_ENV_PARSER (env);
1441  namelist = NULL;
1442  namelistp = &namelist;
1443 
1444  for (i = bitset_iterate (&((plan->info)->projected_segs), &bi); namelistp != NULL && i != -1;
1445  i = bitset_next_member (&bi))
1446  {
1447  QO_SEGMENT *seg;
1448  PT_NODE *name;
1449 
1450  seg = QO_ENV_SEG (env, i);
1451  name = pt_point (parser, QO_SEG_PT_NODE (seg));
1452 
1453  *namelistp = name;
1454  namelistp = &name->next;
1455  }
1456 
1457  return namelist;
1458 }
1459 
1460 /*
1461  * check_merge_xasl () -
1462  * return:
1463  * env(in):
1464  * xasl(in):
1465  */
1466 static XASL_NODE *
1468 {
1469  XASL_NODE *merge;
1470  int i, ncols;
1471 
1472  /*
1473  * NULL is actually a semi-common case; it can arise under timeout
1474  * conditions, etc.
1475  */
1476  if (xasl == NULL)
1477  {
1478  return NULL;
1479  }
1480 
1481  /*
1482  * The mergelist proc isn't necessarily the first thing on the
1483  * aptr_list; some other procs may have found their way in front of
1484  * it, and that's not incorrect. Search until we find a mergelist
1485  * proc; is there any way to have more than one?
1486  */
1487  for (merge = xasl->aptr_list; merge && merge->type != MERGELIST_PROC; merge = merge->next)
1488  ;
1489 
1490  if (merge == NULL
1491  /*
1492  * Make sure there are two things on the aptr list.
1493  */
1494  || merge->type != MERGELIST_PROC || merge->aptr_list == NULL /* left */
1495  || merge->aptr_list->next == NULL /* right */
1496  /*
1497  * Make sure both buildlist gadgets look well-formed.
1498  */
1499  || xasl->spec_list == NULL || xasl->val_list == NULL || xasl->outptr_list == NULL
1500  /*
1501  * Make sure the merge_list_info looks plausible.
1502  */
1503  || merge->proc.mergelist.outer_xasl == NULL || merge->proc.mergelist.inner_xasl == NULL
1504  || merge->proc.mergelist.ls_merge.ls_column_cnt <= 0)
1505  {
1507  xasl = NULL;
1508  }
1509 
1510  if (merge != NULL)
1511  {
1512  ncols = merge->proc.mergelist.ls_merge.ls_column_cnt;
1513  for (i = 0; i < ncols; i++)
1514  {
1515  if (merge->proc.mergelist.ls_merge.ls_outer_column[i] < 0
1516  || merge->proc.mergelist.ls_merge.ls_inner_column[i] < 0)
1517  {
1519  xasl = NULL;
1520  break;
1521  }
1522  }
1523  }
1524 
1525  return xasl;
1526 }
1527 
1528 /*
1529  * make_outer_instnum () -
1530  * return:
1531  * env(in):
1532  * outer(in):
1533  * plan(in):
1534  */
1535 static void
1536 make_outer_instnum (QO_ENV * env, QO_PLAN * outer, QO_PLAN * plan)
1537 {
1538  int t;
1539  BITSET_ITERATOR iter;
1540  QO_TERM *termp;
1541 
1542  for (t = bitset_iterate (&(plan->sarged_terms), &iter); t != -1; t = bitset_next_member (&iter))
1543  {
1544  termp = QO_ENV_TERM (env, t);
1545 
1546  if (is_totally_after_join_term (termp))
1547  {
1548  bitset_add (&(outer->sarged_terms), t);
1549  }
1550  }
1551 }
1552 
1553 /*
1554  * gen_outer () -
1555  * return: XASL_NODE *
1556  * env(in): The optimizer environment
1557  * plan(in): The (sub)plan to generate code for
1558  * subqueries(in): The set of subqueries that need to be reevaluated every
1559  * time a new row is produced by plan
1560  * inner_scans(in): A list of scan
1561  * fetches(in): A list of fetch procs that should be executed every time plan
1562  * produces a new row
1563  * xasl(in): The xasl node that is receiving the various procs we generate
1564  */
1565 static XASL_NODE *
1566 gen_outer (QO_ENV * env, QO_PLAN * plan, BITSET * subqueries, XASL_NODE * inner_scans, XASL_NODE * fetches,
1567  XASL_NODE * xasl)
1568 {
1570  XASL_NODE *scan, *listfile, *merge, *fetch;
1571  QO_PLAN *outer, *inner;
1572  JOIN_TYPE join_type = NO_JOIN;
1573  QO_TERM *term;
1574  int i;
1575  BITSET_ITERATOR bi;
1576  BITSET new_subqueries;
1577  BITSET fake_subqueries;
1578  BITSET predset;
1579  BITSET taj_terms;
1580 
1581  if (env == NULL)
1582  {
1583  return NULL;
1584  }
1585  parser = QO_ENV_PARSER (env);
1586 
1587  if (parser == NULL || plan == NULL || xasl == NULL)
1588  {
1589  return NULL;
1590  }
1591 
1592  bitset_init (&new_subqueries, env);
1593  bitset_init (&fake_subqueries, env);
1594  bitset_init (&predset, env);
1595  bitset_init (&taj_terms, env);
1596 
1597  /* set subqueries */
1598  bitset_assign (&new_subqueries, subqueries);
1599  bitset_union (&new_subqueries, &(plan->subqueries));
1600 
1601  /* set predicates */
1602  bitset_assign (&predset, &(plan->sarged_terms));
1603 
1604  switch (plan->plan_type)
1605  {
1606  case QO_PLANTYPE_JOIN:
1607  join_type = plan->plan_un.join.join_type;
1608 
1609  /*
1610  * The join terms may be EMPTY if this "join" is actually a
1611  * cartesian product, or if it has been implemented as an
1612  * index scan on the inner term (in which case it has already
1613  * been placed in the inner plan as the index term).
1614  */
1615  bitset_union (&predset, &(plan->plan_un.join.join_terms));
1616 
1617  /* outer join could have terms classed as AFTER JOIN TERM; setting after join terms to merged list scan */
1618  if (IS_OUTER_JOIN_TYPE (join_type))
1619  {
1620  bitset_union (&predset, &(plan->plan_un.join.during_join_terms));
1621  bitset_union (&predset, &(plan->plan_un.join.after_join_terms));
1622  }
1623  break;
1624 
1625  case QO_PLANTYPE_FOLLOW:
1626  /* include follow edge */
1627  bitset_add (&predset, QO_TERM_IDX (plan->plan_un.follow.path));
1628  break;
1629 
1630  default:
1631  break;
1632  }
1633 
1634  /*
1635  * Because this routine tail-calls itself in several common cases, we
1636  * could implement those tail calls with a loop back to the beginning
1637  * of the code. However, because these calls won't get very deep in
1638  * practice (~10 deep), I've left the code as is in the interest of
1639  * clarity.
1640  */
1641 
1642  switch (plan->plan_type)
1643  {
1644  case QO_PLANTYPE_SCAN:
1645  /*
1646  * This case only needs to attach the access spec to the incoming
1647  * XASL node. The remainder of the interesting initialization
1648  * (e.g., the val list) of that XASL node is expected to be
1649  * performed by the caller.
1650  */
1651  xasl = add_access_spec (env, xasl, plan);
1652  xasl = add_scan_proc (env, xasl, inner_scans);
1653  xasl = add_fetch_proc (env, xasl, fetches);
1654  xasl = add_subqueries (env, xasl, &new_subqueries);
1655  break;
1656 
1657  case QO_PLANTYPE_SORT:
1658  /*
1659  * check for top level plan
1660  */
1661  if (plan->top_rooted)
1662  {
1663  if (plan->plan_un.sort.sort_type == SORT_TEMP)
1664  {
1665  ; /* nop */
1666  }
1667  else
1668  {
1669  /* SORT-LIMIT plans should never be top rooted */
1670  assert (plan->plan_un.sort.sort_type != SORT_LIMIT);
1671  xasl = gen_outer (env, plan->plan_un.sort.subplan, &new_subqueries, inner_scans, fetches, xasl);
1672  return xasl;
1673  }
1674  }
1675 
1676  /*
1677  * If inner_scans is not empty, this plan is really a subplan of
1678  * some outer join node, and we need to make xasl scan the
1679  * contents of the temp file intended to be created by this plan.
1680  * If not, we're really at the "top" of a tree (we haven't gone
1681  * through a join node yet) and we can simply recurse, tacking on
1682  * our sort spec after the recursion. The exception to this rule is
1683  * the SORT-LIMIT plan which must always be working on a temp file.
1684  */
1685  if (inner_scans != NULL || plan->plan_un.sort.sort_type == SORT_LIMIT)
1686  {
1687  PT_NODE *namelist = NULL;
1688 
1689  namelist = make_namelist_from_projected_segs (env, plan);
1690  if (plan->plan_un.sort.sort_type == SORT_LIMIT)
1691  {
1692  listfile = make_sort_limit_proc (env, plan, namelist, xasl);
1693  }
1694  else
1695  {
1696  listfile = make_buildlist_proc (env, namelist);
1697  listfile = gen_outer (env, plan->plan_un.sort.subplan, &EMPTY_SET, NULL, NULL, listfile);
1698  listfile = add_sort_spec (env, listfile, plan, xasl->ordbynum_val, false);
1699  }
1700 
1701  xasl = add_uncorrelated (env, xasl, listfile);
1702  xasl = init_list_scan_proc (env, xasl, listfile, namelist, &(plan->sarged_terms), NULL);
1703  if (namelist)
1704  {
1705  parser_free_tree (parser, namelist);
1706  }
1707  xasl = add_scan_proc (env, xasl, inner_scans);
1708  xasl = add_fetch_proc (env, xasl, fetches);
1709  xasl = add_subqueries (env, xasl, &new_subqueries);
1710  }
1711  else
1712  {
1713  xasl = gen_outer (env, plan->plan_un.sort.subplan, &new_subqueries, inner_scans, fetches, xasl);
1714  xasl = add_sort_spec (env, xasl, plan, NULL, true /* add instnum pred */ );
1715  }
1716  break;
1717 
1718  case QO_PLANTYPE_JOIN:
1719 
1720  outer = plan->plan_un.join.outer;
1721  inner = plan->plan_un.join.inner;
1722 
1723  switch (plan->plan_un.join.join_method)
1724  {
1725  case QO_JOINMETHOD_NL_JOIN:
1726  /* check for cselect of method */
1727  if (join_type == JOIN_CSELECT)
1728  {
1729  xasl = pt_gen_simple_merge_plan (parser, QO_ENV_PT_TREE (env), plan, xasl);
1730  break;
1731  }
1732  /* FALLTHRU */
1734  for (i = bitset_iterate (&(plan->plan_un.join.join_terms), &bi); i != -1; i = bitset_next_member (&bi))
1735  {
1736  term = QO_ENV_TERM (env, i);
1737  if (QO_IS_FAKE_TERM (term))
1738  {
1739  bitset_union (&fake_subqueries, &(QO_TERM_SUBQUERIES (term)));
1740  }
1741  }
1742 
1743  bitset_difference (&new_subqueries, &fake_subqueries);
1744 
1745  for (i = bitset_iterate (&predset, &bi); i != -1; i = bitset_next_member (&bi))
1746  {
1747  term = QO_ENV_TERM (env, i);
1748  if (is_totally_after_join_term (term))
1749  {
1750  bitset_add (&taj_terms, i);
1751  }
1752  else if (is_normal_access_term (term))
1753  {
1754  /* Check if join term can be pushed to key filter instead of sargable terms. The index used for inner
1755  * index scan must include all term segments that belong to inner node */
1756  if (qo_is_index_covering_scan (inner) || qo_plan_multi_range_opt (inner))
1757  {
1758  /* Coverage indexes and indexes using multi range optimization are certified to include segments
1759  * from inner node */
1760  bitset_add (&(inner->plan_un.scan.kf_terms), i);
1761  bitset_difference (&predset, &(inner->plan_un.scan.kf_terms));
1762  }
1763  else if (qo_is_iscan (plan))
1764  {
1765  /* check that index covers all segments */
1766  BITSET term_segs, index_segs;
1767  QO_INDEX_ENTRY *idx_entryp = NULL;
1768  int j;
1769 
1770  /* create bitset including index segments */
1771  bitset_init (&index_segs, env);
1772  idx_entryp = inner->plan_un.scan.index->head;
1773  for (j = 0; j < idx_entryp->nsegs; j++)
1774  {
1775  bitset_add (&index_segs, idx_entryp->seg_idxs[j]);
1776  }
1777 
1778  /* create bitset including term segments that belong to inner node */
1779  bitset_init (&term_segs, env);
1780  bitset_union (&term_segs, &term->segments);
1781  bitset_intersect (&term_segs, &(QO_NODE_SEGS (plan->plan_un.scan.node)));
1782 
1783  /* check that term_segs is covered by index_segs */
1784  bitset_difference (&term_segs, &index_segs);
1785  if (bitset_is_empty (&term_segs))
1786  {
1787  /* safe to add term to key filter terms */
1788  bitset_add (&(inner->plan_un.scan.kf_terms), i);
1789  bitset_difference (&predset, &(inner->plan_un.scan.kf_terms));
1790  }
1791  }
1792  }
1793  }
1794  /* exclude totally after join term and push into inner */
1795  bitset_difference (&predset, &taj_terms);
1796 
1797  /* copy hash join term to inner for hash list scan */
1798  if (qo_is_seq_scan (inner) && !bitset_is_empty (&(plan->plan_un.join.hash_terms)))
1799  {
1800  bitset_assign (&(inner->plan_un.scan.hash_terms), &(plan->plan_un.join.hash_terms));
1801  }
1802 
1803  /*
1804  * In case of outer join, we should not use sarg terms as key filter terms.
1805  * If not, a term, which should be applied after single scan, can be applied
1806  * during btree_range_search. It means that there can be no records fetched
1807  * by single scan due to key filtering, and null records can be returned
1808  * by scan_handle_single_scan. It might lead to making a wrong result.
1809  */
1810  scan = gen_inner (env, inner, &predset, &new_subqueries, inner_scans, fetches);
1811  if (scan)
1812  {
1813  if (IS_OUTER_JOIN_TYPE (join_type))
1814  {
1815  mark_access_as_outer_join (parser, scan);
1816  }
1817  }
1818  bitset_assign (&new_subqueries, &fake_subqueries);
1819  make_outer_instnum (env, outer, plan);
1820  xasl = gen_outer (env, outer, &new_subqueries, scan, NULL, xasl);
1821  break;
1822 
1824  /*
1825  * The optimizer isn't supposed to produce plans in which a
1826  * merge join isn't "shielded" by a sort (temp file) plan,
1827  * precisely because XASL has a difficult time coping with
1828  * that. Because of that, inner_scans should ALWAYS be NULL
1829  * here.
1830  */
1831  assert (inner_scans == NULL);
1832  if (inner_scans)
1833  {
1834  xasl = NULL;
1835  break;
1836  }
1837 
1838  /*
1839  * In this case, we have to hold on to the accumulated
1840  * predicates and subqueries, and tack them on to the scan
1841  * proc that eventually reads the result of the join. The
1842  * subplans for the two join components should start with
1843  * clean slates.
1844  */
1845  {
1846 
1847  XASL_NODE *left_xasl, *rght_xasl;
1848  PT_NODE *left_elist, *left_nlist, *left_list, *left;
1849  PT_NODE *rght_elist, *rght_nlist, *rght_list, *rght;
1850  PT_NODE *seg_nlist, *pt_expr;
1851  int left_nlen, rght_nlen, seg_nlen;
1852  int *seg_pos_list;
1853  BITSET plan_segs, temp_segs, left_exprs, rght_exprs;
1854 
1855  bitset_init (&plan_segs, env);
1856  bitset_init (&temp_segs, env);
1857  bitset_init (&left_exprs, env);
1858  bitset_init (&rght_exprs, env);
1859 
1860  /* init */
1861  left_nlist = rght_nlist = left_list = NULL;
1862  left_elist = rght_elist = rght_list = NULL;
1863 
1864  seg_nlist = NULL;
1865  seg_pos_list = NULL;
1866 
1867  /* find outer/inner segs from expr and name */
1868  bitset_assign (&plan_segs, &((plan->info)->projected_segs));
1869  for (i = bitset_iterate (&predset, &bi); i != -1; i = bitset_next_member (&bi))
1870  {
1871 
1872  term = QO_ENV_TERM (env, i);
1873 
1874  if (BITSET_MEMBER (plan->plan_un.join.join_terms, i))
1875  { /* is m-join edge */
1876 
1877  BITSET_CLEAR (temp_segs); /* init */
1878 
1879  pt_expr = QO_TERM_PT_EXPR (term);
1880  qo_expr_segs (env, pt_left_part (pt_expr), &temp_segs);
1881 
1882  /* is lhs matching outer ? */
1883  if (bitset_intersects (&temp_segs, &((outer->info)->projected_segs)))
1884  {
1885  left = pt_left_part (pt_expr);
1886  rght = pt_right_part (pt_expr);
1887  if (pt_expr->info.expr.op == PT_RANGE && rght != NULL)
1888  {
1889  rght = rght->info.expr.arg1;
1890  }
1891  }
1892  else
1893  {
1894  rght = pt_left_part (pt_expr);
1895  left = pt_right_part (pt_expr);
1896  if (pt_expr->info.expr.op == PT_RANGE && left != NULL)
1897  {
1898  left = left->info.expr.arg1;
1899  }
1900  }
1901 
1902  if (pt_is_expr_node (left) || pt_is_function (left))
1903  {
1904  /* append to the expr list */
1905  left_elist = parser_append_node (pt_point (parser, left), left_elist);
1906  bitset_add (&left_exprs, i);
1907  }
1908  else
1909  {
1910  bitset_union (&plan_segs, &(QO_TERM_SEGS (term)));
1911  }
1912 
1913  if (pt_is_expr_node (rght) || pt_is_function (rght))
1914  {
1915  /* append to the expr list */
1916  rght_elist = parser_append_node (pt_point (parser, rght), rght_elist);
1917  bitset_add (&rght_exprs, i);
1918  }
1919  else
1920  {
1921  bitset_union (&plan_segs, &(QO_TERM_SEGS (term)));
1922  }
1923  }
1924  else
1925  {
1926  bitset_union (&plan_segs, &(QO_TERM_SEGS (term)));
1927  }
1928  }
1929 
1930  /* build outer segs namelist */
1931  bitset_assign (&temp_segs, &((outer->info)->projected_segs)); /* save */
1932 
1933  bitset_intersect (&((outer->info)->projected_segs), &plan_segs);
1934  left_nlist = make_namelist_from_projected_segs (env, outer);
1935  left_nlen = pt_length_of_list (left_nlist); /* only names include */
1936 
1937  /* make expr, name list */
1938  left_list = parser_append_node (left_nlist, left_elist);
1939  left_xasl = make_buildlist_proc (env, left_list);
1940  left_xasl = gen_outer (env, outer, &EMPTY_SET, NULL, NULL, left_xasl);
1941  bitset_assign (&((outer->info)->projected_segs), &temp_segs); /* restore */
1942 
1943  /* build inner segs namelist */
1944  bitset_assign (&temp_segs, &((inner->info)->projected_segs)); /* save */
1945 
1946  bitset_intersect (&((inner->info)->projected_segs), &plan_segs);
1947  rght_nlist = make_namelist_from_projected_segs (env, inner);
1948  rght_nlen = pt_length_of_list (rght_nlist); /* only names include */
1949 
1950  /* make expr, name list */
1951  rght_list = parser_append_node (rght_nlist, rght_elist);
1952  rght_xasl = make_buildlist_proc (env, rght_list);
1953  rght_xasl = gen_outer (env, inner, &EMPTY_SET, NULL, NULL, rght_xasl);
1954  bitset_assign (&((inner->info)->projected_segs), &temp_segs); /* restore */
1955 
1956  merge =
1957  make_mergelist_proc (env, plan, left_xasl, left_list, &left_exprs, left_elist, rght_xasl, rght_list,
1958  &rght_exprs, rght_elist);
1959  if (merge == NULL)
1960  {
1961  xasl = NULL; /* cause error */
1962 
1963  if (left_list)
1964  parser_free_tree (parser, left_list);
1965  if (rght_list)
1966  parser_free_tree (parser, rght_list);
1967 
1968  if (seg_nlist)
1969  parser_free_tree (parser, seg_nlist);
1970 
1971  if (seg_pos_list)
1972  free_and_init (seg_pos_list);
1973 
1974  bitset_delset (&plan_segs);
1975  bitset_delset (&temp_segs);
1976  bitset_delset (&left_exprs);
1977  bitset_delset (&rght_exprs);
1978  break;
1979  }
1980 
1981  xasl = add_uncorrelated (env, xasl, merge);
1982 
1983  /* filter out already applied terms */
1984  bitset_difference (&predset, &(plan->plan_un.join.join_terms));
1985  if (IS_OUTER_JOIN_TYPE (join_type))
1986  {
1987  bitset_difference (&predset, &(plan->plan_un.join.during_join_terms));
1988  }
1989 
1990  /* set referenced segments */
1991  bitset_assign (&plan_segs, &((plan->info)->projected_segs));
1992  for (i = bitset_iterate (&predset, &bi); i != -1; i = bitset_next_member (&bi))
1993  {
1994  term = QO_ENV_TERM (env, i);
1995  bitset_union (&plan_segs, &(QO_TERM_SEGS (term)));
1996  }
1997 
1998  /* generate left name list of projected segs */
1999  bitset_assign (&temp_segs, &((outer->info)->projected_segs));
2000  bitset_intersect (&temp_segs, &plan_segs);
2001  for (i = bitset_iterate (&temp_segs, &bi); i != -1; i = bitset_next_member (&bi))
2002  {
2003  seg_nlist = parser_append_node (pt_point (parser, QO_SEG_PT_NODE (QO_ENV_SEG (env, i))), seg_nlist);
2004  }
2005 
2006  /* generate right name list of projected segs */
2007  bitset_assign (&temp_segs, &((inner->info)->projected_segs));
2008  bitset_intersect (&temp_segs, &plan_segs);
2009  for (i = bitset_iterate (&temp_segs, &bi); i != -1; i = bitset_next_member (&bi))
2010  {
2011  seg_nlist = parser_append_node (pt_point (parser, QO_SEG_PT_NODE (QO_ENV_SEG (env, i))), seg_nlist);
2012  }
2013 
2014  seg_nlen = pt_length_of_list (seg_nlist);
2015 
2016  /* set used column position in name list and filter out unnecessary join edge segs from projected segs */
2017  if (seg_nlen > 0 && seg_nlen < left_nlen + rght_nlen)
2018  {
2019  QFILE_LIST_MERGE_INFO *ls_merge;
2020  int outer_inner, pos = 0, p;
2021  PT_NODE *attr;
2022 
2023  seg_pos_list = (int *) malloc (seg_nlen * sizeof (int));
2024  if (seg_pos_list == NULL)
2025  {
2026  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, seg_nlen * sizeof (int));
2027  xasl = NULL; /* cause error */
2028 
2029  if (left_list)
2030  {
2031  parser_free_tree (parser, left_list);
2032  }
2033  if (rght_list)
2034  {
2035  parser_free_tree (parser, rght_list);
2036  }
2037 
2038  if (seg_nlist)
2039  {
2040  parser_free_tree (parser, seg_nlist);
2041  }
2042 
2043  if (seg_pos_list)
2044  {
2045  free_and_init (seg_pos_list);
2046  }
2047 
2048  bitset_delset (&plan_segs);
2049  bitset_delset (&temp_segs);
2050  bitset_delset (&left_exprs);
2051  bitset_delset (&rght_exprs);
2052  break;
2053  }
2054 
2055  ls_merge = &merge->proc.mergelist.ls_merge;
2056 
2057  p = 0; /* init */
2058  for (attr = seg_nlist; attr; attr = attr->next)
2059  {
2060 
2061  pos = pt_find_attribute (parser, attr, left_list);
2062  if (pos == -1)
2063  { /* not found in left */
2064  pos = pt_find_attribute (parser, attr, rght_list);
2065  if (pos == -1)
2066  { /* not found in right */
2067  break; /* cause error */
2068  }
2069  outer_inner = QFILE_INNER_LIST;
2070  }
2071  else
2072  {
2073  outer_inner = QFILE_OUTER_LIST;
2074  }
2075 
2076  for (i = 0; i < ls_merge->ls_pos_cnt; i++)
2077  {
2078  if (ls_merge->ls_outer_inner_list[i] == outer_inner && ls_merge->ls_pos_list[i] == pos)
2079  { /* found */
2080  seg_pos_list[p] = i; /* save position */
2081  break;
2082  }
2083  }
2084 
2085  if (i >= ls_merge->ls_pos_cnt)
2086  { /* error */
2087  pos = -1;
2088  break; /* cause error */
2089  }
2090 
2091  p++; /* increase */
2092  }
2093 
2094  if (pos == -1)
2095  { /* error */
2096  xasl = NULL; /* cause error */
2097 
2098  if (left_list)
2099  {
2100  parser_free_tree (parser, left_list);
2101  }
2102  if (rght_list)
2103  {
2104  parser_free_tree (parser, rght_list);
2105  }
2106 
2107  if (seg_nlist)
2108  {
2109  parser_free_tree (parser, seg_nlist);
2110  }
2111 
2112  if (seg_pos_list)
2113  {
2114  free_and_init (seg_pos_list);
2115  }
2116 
2117  bitset_delset (&plan_segs);
2118  bitset_delset (&temp_segs);
2119  bitset_delset (&left_exprs);
2120  bitset_delset (&rght_exprs);
2121  break;
2122  }
2123  }
2124 
2125  if (xasl)
2126  {
2127  xasl = init_list_scan_proc (env, xasl, merge, seg_nlist, &predset, seg_pos_list);
2128  xasl = add_fetch_proc (env, xasl, fetches);
2129  xasl = add_subqueries (env, xasl, &new_subqueries);
2130  }
2131 
2132  if (left_list)
2133  {
2134  parser_free_tree (parser, left_list);
2135  }
2136  if (rght_list)
2137  {
2138  parser_free_tree (parser, rght_list);
2139  }
2140 
2141  if (seg_nlist)
2142  {
2143  parser_free_tree (parser, seg_nlist);
2144  }
2145 
2146  if (seg_pos_list)
2147  {
2148  free_and_init (seg_pos_list);
2149  }
2150 
2151  bitset_delset (&plan_segs);
2152  bitset_delset (&temp_segs);
2153  bitset_delset (&left_exprs);
2154  bitset_delset (&rght_exprs);
2155 
2156  }
2157 
2158  /*
2159  * This can be removed after we trust ourselves some more.
2160  */
2161  xasl = check_merge_xasl (env, xasl);
2162  break;
2163 
2164  default:
2165  break;
2166  }
2167 
2168  break;
2169 
2170  case QO_PLANTYPE_FOLLOW:
2171  /*
2172  * Add the fetch proc to the head of the list of fetch procs
2173  * before recursing. This means that it will be later in the
2174  * list than fetch procs that are added during the recursion,
2175  * which means that those fetches will happen earlier at runtime,
2176  * which is exactly what we want. Pass it on down to the inner
2177  * call, since we don't know exactly where we want to stick it
2178  * yet.
2179  */
2180  fetch = make_fetch_proc (env, plan);
2181  fetch = add_fetch_proc (env, fetch, fetches);
2182  fetch = add_subqueries (env, fetch, &new_subqueries);
2183  make_outer_instnum (env, plan->plan_un.follow.head, plan);
2184  xasl = gen_outer (env, plan->plan_un.follow.head, &EMPTY_SET, inner_scans, fetch, xasl);
2185  break;
2186 
2187  case QO_PLANTYPE_WORST:
2188  xasl = NULL;
2189  break;
2190  }
2191 
2192  bitset_delset (&taj_terms);
2193  bitset_delset (&predset);
2194  bitset_delset (&fake_subqueries);
2195  bitset_delset (&new_subqueries);
2196 
2197  return xasl;
2198 }
2199 
2200 /*
2201  * gen_inner () -
2202  * return: XASL_NODE *
2203  * env(in): The optimizer environment
2204  * plan(in): The (sub)plan to generate code for
2205  * predset(in): The predicates being pushed down from above
2206  * subqueries(in): The subqueries inherited from enclosing plans
2207  * inner_scans(in): A list of inner scan procs to be put on this scan's
2208  * scan_ptr list
2209  * fetches(in): A list of fetch procs to be run every time plan produces
2210  * a new row
2211  */
2212 static XASL_NODE *
2213 gen_inner (QO_ENV * env, QO_PLAN * plan, BITSET * predset, BITSET * subqueries, XASL_NODE * inner_scans,
2214  XASL_NODE * fetches)
2215 {
2216  XASL_NODE *scan, *listfile, *fetch;
2217  PT_NODE *namelist;
2218  BITSET new_subqueries;
2219 
2220  /*
2221  * All of the rationale about ordering, etc. presented in the
2222  * comments in gen_outer also applies here.
2223  */
2224 
2225  scan = NULL;
2226  bitset_init (&new_subqueries, env);
2227  bitset_assign (&new_subqueries, subqueries);
2228  bitset_union (&new_subqueries, &(plan->subqueries));
2229 
2230  switch (plan->plan_type)
2231  {
2232  case QO_PLANTYPE_SCAN:
2233  /*
2234  * For nl-join and idx-join, we push join edge to sarg term of
2235  * inner scan to filter out unsatisfied records earlier.
2236  */
2237  bitset_union (&(plan->sarged_terms), predset);
2238 
2239  scan = init_class_scan_proc (env, scan, plan);
2240  scan = add_scan_proc (env, scan, inner_scans);
2241  scan = add_fetch_proc (env, scan, fetches);
2242  scan = add_subqueries (env, scan, &new_subqueries);
2243  break;
2244 
2245  case QO_PLANTYPE_FOLLOW:
2246 #if 1
2247  /*
2248  * We have to take care of any sargs that have been passed down
2249  * from above. Go ahead and destructively union them into this
2250  * plan's sarg set: no one will ever look at the plan again
2251  * anyway.
2252  */
2253  bitset_union (&(plan->sarged_terms), predset);
2254  fetch = make_fetch_proc (env, plan);
2255  fetch = add_fetch_proc (env, fetch, fetches);
2256  fetch = add_subqueries (env, fetch, &new_subqueries);
2257  /*
2258  * Now proceed on with inner generation, passing the augmented
2259  * list of fetch procs.
2260  */
2261  scan = gen_inner (env, plan->plan_un.follow.head, &EMPTY_SET, &EMPTY_SET, inner_scans, fetch);
2262  break;
2263 #else
2264  /* Fall through */
2265 #endif
2266 
2267  case QO_PLANTYPE_JOIN:
2268  /*
2269  * These aren't supposed to show up, but if they do just take the
2270  * conservative approach of treating them like a sort and
2271  * whacking their results into a temporary file, and then scan
2272  * that file.
2273  */
2274  case QO_PLANTYPE_SORT:
2275  /* check for sort type */
2276  QO_ASSERT (env, plan->plan_un.sort.sort_type == SORT_TEMP);
2277 
2278  namelist = make_namelist_from_projected_segs (env, plan);
2279  listfile = make_buildlist_proc (env, namelist);
2280  listfile = gen_outer (env, plan, &EMPTY_SET, NULL, NULL, listfile);
2281  scan = make_scan_proc (env);
2282  scan = init_list_scan_proc (env, scan, listfile, namelist, predset, NULL);
2283  if (namelist)
2284  {
2285  parser_free_tree (env->parser, namelist);
2286  }
2287  scan = add_scan_proc (env, scan, inner_scans);
2288  scan = add_fetch_proc (env, scan, fetches);
2289  scan = add_subqueries (env, scan, &new_subqueries);
2290  scan = add_uncorrelated (env, scan, listfile);
2291  break;
2292 
2293  case QO_PLANTYPE_WORST:
2294  /*
2295  * This case should never arise.
2296  */
2297  scan = NULL;
2298  break;
2299  }
2300 
2301  bitset_delset (&new_subqueries);
2302 
2303  return scan;
2304 }
2305 
2306 /*
2307  * preserve_info () -
2308  * return: XASL_NODE *
2309  * env(in): The optimizer environment
2310  * plan(in): The plan from which the xasl tree was generated
2311  * xasl(in): The generated xasl tree
2312  */
2313 static XASL_NODE *
2314 preserve_info (QO_ENV * env, QO_PLAN * plan, XASL_NODE * xasl)
2315 {
2316  QO_SUMMARY *summary;
2318  PT_NODE *select;
2319 
2320  if (xasl != NULL)
2321  {
2322  parser = QO_ENV_PARSER (env);
2323  select = QO_ENV_PT_TREE (env);
2324  summary = (QO_SUMMARY *) parser_alloc (parser, sizeof (QO_SUMMARY));
2325  if (summary)
2326  {
2327  summary->fixed_cpu_cost = plan->fixed_cpu_cost;
2328  summary->fixed_io_cost = plan->fixed_io_cost;
2329  summary->variable_cpu_cost = plan->variable_cpu_cost;
2330  summary->variable_io_cost = plan->variable_io_cost;
2331  summary->cardinality = (plan->info)->cardinality;
2332  summary->xasl = xasl;
2333  select->info.query.q.select.qo_summary = summary;
2334  }
2335  else
2336  {
2337  xasl = NULL;
2338  }
2339 
2340  /* save info for derived table size estimation */
2341  if (plan != NULL && xasl != NULL)
2342  {
2343  xasl->projected_size = (plan->info)->projected_size;
2344  xasl->cardinality = (plan->info)->cardinality;
2345  }
2346  }
2347 
2348  return xasl;
2349 }
2350 
2351 /*
2352  * qo_to_xasl () -
2353  * return: XASL_NODE *
2354  * plan(in): The (already optimized) select statement to generate code for
2355  * xasl(in): The XASL block for the root of the plan
2356  *
2357  * Note: Create an XASL tree from the QO_PLAN tree associated with
2358  * 'select'. In essence, this takes the entity specs from the
2359  * from part of 'select' and produces a collection of access
2360  * specs that will do the right thing. It also distributes the
2361  * predicates in the where part across those access specs. The
2362  * caller shouldn't have to do anything for the from part or the
2363  * where part, but it must still take care of all of the other
2364  * grunge, such as setting up the code for the select list
2365  * expressions, etc.
2366  */
2367 xasl_node *
2368 qo_to_xasl (QO_PLAN * plan, xasl_node * xasl)
2369 {
2370  QO_ENV *env;
2371  XASL_NODE *lastxasl;
2372 
2373  if (plan && xasl && (env = (plan->info)->env))
2374  {
2375  xasl = gen_outer (env, plan, &EMPTY_SET, NULL, NULL, xasl);
2376 
2377  lastxasl = xasl;
2378  while (lastxasl)
2379  {
2380  /*
2381  * Don't consider only scan pointers here; it's quite
2382  * possible that the correlated subqueries might depend on
2383  * values retrieved by a fetch proc that lives on an fptr.
2384  */
2385  if (lastxasl->scan_ptr)
2386  {
2387  lastxasl = lastxasl->scan_ptr;
2388  }
2389  else if (lastxasl->fptr_list)
2390  {
2391  lastxasl = lastxasl->fptr_list;
2392  }
2393  else
2394  {
2395  break;
2396  }
2397  }
2398  (void) pt_set_dptr (env->parser, env->pt_tree->info.query.q.select.list, lastxasl, MATCH_ALL);
2399 
2400  xasl = preserve_info (env, plan, xasl);
2401  }
2402  else
2403  {
2404  xasl = NULL;
2405  }
2406 
2407  if (xasl == NULL)
2408  {
2409  int level;
2410 
2412 
2414  if (PLAN_DUMP_ENABLED (level))
2415  {
2416  fprintf (stderr, "*** XASL generation failed ***\n");
2417  }
2418 #if defined(CUBRID_DEBUG)
2419  else
2420  {
2421  fprintf (stderr, "*** XASL generation failed ***\n");
2422  fprintf (stderr, "*** %s ***\n", er_msg ());
2423  }
2424 #endif /* CUBRID_DEBUG */
2425  }
2426 
2427  return xasl;
2428 }
2429 
2430 /*
2431  * qo_plan_iscan_sort_list () - get after index scan PT_SORT_SPEC list
2432  * return: SORT_LIST *
2433  * plan(in): QO_PLAN
2434  */
2435 PT_NODE *
2437 {
2438  return plan->iscan_sort_list;
2439 }
2440 
2441 /*
2442  * qo_plan_skip_orderby () - check the plan info for order by
2443  * return: true/false
2444  * plan(in): QO_PLAN
2445  */
2446 bool
2448 {
2449  return ((plan->plan_type == QO_PLANTYPE_SORT
2450  && (plan->plan_un.sort.sort_type == SORT_DISTINCT
2451  || plan->plan_un.sort.sort_type == SORT_ORDERBY)) ? false : true);
2452 }
2453 
2454 /*
2455  * qo_plan_skip_groupby () - check the plan info for order by
2456  * return: true/false
2457  * plan(in): QO_PLAN
2458  */
2459 bool
2461 {
2462  return (plan->plan_type == QO_PLANTYPE_SCAN && plan->plan_un.scan.index
2463  && plan->plan_un.scan.index->head->groupby_skip) ? true : false;
2464 }
2465 
2466 /*
2467  * qo_is_index_covering_scan () - check the plan info for covering index scan
2468  * return: true/false
2469  * plan(in): QO_PLAN
2470  */
2471 bool
2473 {
2474  assert (plan != NULL);
2475  assert (plan->info != NULL);
2476  assert (plan->info->env != NULL);
2477 
2478  if (qo_is_interesting_order_scan (plan))
2479  {
2480  if (plan->plan_un.scan.index_cover == true)
2481  {
2482  assert (plan->plan_un.scan.index->head);
2483  assert (plan->plan_un.scan.index->head->cover_segments);
2484 
2485  assert (!qo_is_prefix_index (plan->plan_un.scan.index->head));
2486 
2487  return true;
2488  }
2489  }
2490 
2491  return false;
2492 }
2493 
2494 /*
2495  * qo_is_index_iss_scan () - check the plan info for index skip scan
2496  * return: true/false
2497  * plan(in): QO_PLAN
2498  */
2499 bool
2501 {
2502  assert (plan != NULL);
2503  assert (plan->info != NULL);
2504  assert (plan->info->env != NULL);
2505 
2506  if (qo_is_interesting_order_scan (plan))
2507  {
2508  if (plan->plan_un.scan.index_iss == true)
2509  {
2510  assert (plan->plan_un.scan.index->head);
2511  assert (plan->plan_un.scan.index->head->is_iss_candidate);
2512 
2513  assert (QO_ENTRY_MULTI_COL (plan->plan_un.scan.index->head));
2514  assert (plan->plan_un.scan.index_loose == false);
2516  assert (!qo_is_filter_index (plan->plan_un.scan.index->head));
2517 
2518  return true;
2519  }
2520  }
2521 
2522  return false;
2523 }
2524 
2525 /*
2526  * qo_is_index_loose_scan () - check the plan info for loose index scan
2527  * return: true/false
2528  * plan(in): QO_PLAN
2529  */
2530 bool
2532 {
2533  assert (plan != NULL);
2534  assert (plan->info != NULL);
2535  assert (plan->info->env != NULL);
2536 
2537  if (qo_is_iscan (plan))
2538  {
2539  if (plan->plan_un.scan.index_loose == true)
2540  {
2541  assert (plan->plan_un.scan.index->head);
2542  assert (plan->plan_un.scan.index->head->ils_prefix_len > 0);
2543 
2544  assert (QO_ENTRY_MULTI_COL (plan->plan_un.scan.index->head));
2545  assert (plan->plan_un.scan.index_cover == true);
2546 
2547  assert (!qo_is_prefix_index (plan->plan_un.scan.index->head));
2548  assert (plan->plan_un.scan.index_iss == false);
2550 
2551  return true;
2552  }
2553  }
2554 
2555  return false;
2556 }
2557 
2558 /*
2559  * qo_is_index_mro_scan () - check the plan info for multi range opt scan
2560  * return: true/false
2561  * plan(in): QO_PLAN
2562  */
2563 bool
2565 {
2566  assert (plan != NULL);
2567  assert (plan->info != NULL);
2568  assert (plan->info->env != NULL);
2569 
2570  if (qo_is_interesting_order_scan (plan))
2571  {
2573  {
2574  assert (plan->plan_un.scan.index->head);
2575 
2576  assert (QO_ENTRY_MULTI_COL (plan->plan_un.scan.index->head));
2577  assert (plan->plan_un.scan.index_iss == false);
2578  assert (plan->plan_un.scan.index_loose == false);
2579  assert (!qo_is_filter_index (plan->plan_un.scan.index->head));
2580 
2581  return true;
2582  }
2583  }
2584 
2585  return false;
2586 }
2587 
2588 /*
2589  * qo_plan_multi_range_opt () - check the plan info for multi range opt
2590  * return: true/false
2591  * plan(in): QO_PLAN
2592  */
2593 bool
2595 {
2596  assert (plan != NULL);
2597  assert (plan->info != NULL);
2598  assert (plan->info->env != NULL);
2599 
2600  if (plan != NULL && plan->multi_range_opt_use == PLAN_MULTI_RANGE_OPT_USE)
2601  {
2602 #if !defined(NDEBUG)
2603  if (qo_is_interesting_order_scan (plan))
2604  {
2605  assert (plan->plan_un.scan.index->head);
2606 
2607  assert (QO_ENTRY_MULTI_COL (plan->plan_un.scan.index->head));
2608  assert (plan->plan_un.scan.index_iss == false);
2609  assert (plan->plan_un.scan.index_loose == false);
2610  assert (!qo_is_filter_index (plan->plan_un.scan.index->head));
2611  }
2612 #endif
2613 
2614  return true;
2615  }
2616 
2617  return false;
2618 }
2619 
2620 /******************************************************************************
2621  * qo_xasl support functions
2622  *****************************************************************************/
2623 
2624 /*
2625  * qo_get_xasl_index_info () -
2626  * return: QO_XASL_INDEX_INFO structure which contains index information
2627  * needed for XASL generation
2628  * env(in): The environment
2629  * plan(in): The plan from which to initialize the scan proc
2630  *
2631  * Note: The term expression array <term_exprs> is returned in index
2632  * definition order. i.e. For multi-column indexes, you can create
2633  * a sequence key from the expression array in the order that they
2634  * are returned.
2635  */
2636 static QO_XASL_INDEX_INFO *
2638 {
2639  int nterms, nsegs, nkfterms, multi_term_num;;
2640  QO_NODE_INDEX_ENTRY *ni_entryp;
2641  QO_INDEX_ENTRY *index_entryp;
2642  QO_XASL_INDEX_INFO *index_infop;
2643  int t, i, j, pos;
2644  BITSET_ITERATOR iter;
2645  QO_TERM *termp;
2646  BITSET multi_col_segs, multi_col_range_segs, index_segs;
2647 
2648  if (!qo_is_interesting_order_scan (plan))
2649  {
2650  return NULL; /* give up */
2651  }
2652 
2653  assert (plan->plan_un.scan.index != NULL);
2654 
2655  bitset_init (&multi_col_segs, env);
2656  bitset_init (&multi_col_range_segs, env);
2657  bitset_init (&index_segs, env);
2658 
2659  /* if no index scan terms, no index scan */
2660  nterms = bitset_cardinality (&(plan->plan_un.scan.terms));
2661  nkfterms = bitset_cardinality (&(plan->plan_un.scan.kf_terms));
2662 
2663  /* pointer to QO_NODE_INDEX_ENTRY structure in QO_PLAN */
2664  ni_entryp = plan->plan_un.scan.index;
2665  /* pointer to linked list of index node, 'head' field(QO_INDEX_ENTRY structure) of QO_NODE_INDEX_ENTRY */
2666  index_entryp = (ni_entryp)->head;
2667  /* number of indexed segments */
2668  nsegs = index_entryp->nsegs; /* nsegs == nterms ? */
2669 
2670  /* support also full range indexes */
2671  if (nterms <= 0 && nkfterms <= 0 && bitset_cardinality (&(plan->sarged_terms)) == 0)
2672  {
2673  if (qo_is_filter_index (index_entryp) || qo_is_index_loose_scan (plan) || qo_is_iscan_from_groupby (plan)
2674  || qo_is_iscan_from_orderby (plan)
2676  {
2677  /* Do not return if: 1. filtered index. 2. skip group by or skip order by 3. loose scan. 4. scan for b-tree
2678  * node info or key info. */
2679  ;
2680  }
2681  else
2682  { /* is invalid case */
2683  assert (false);
2684  return NULL; /* give up */
2685  }
2686  }
2687 
2688  /* allocate QO_XASL_INDEX_INFO structure */
2689  index_infop = (QO_XASL_INDEX_INFO *) malloc (sizeof (QO_XASL_INDEX_INFO));
2690  if (index_infop == NULL)
2691  {
2693  goto error;
2694  }
2695 
2696  if (qo_is_index_iss_scan (plan))
2697  {
2698  assert (index_entryp->is_iss_candidate);
2699 
2700  /* allow space for the first element (NULL actually), for instance in term_exprs */
2701  nterms++;
2702  }
2703 
2704  /* check multi column index term */
2705  multi_term_num =
2706  qo_get_multi_col_range_segs (env, plan, index_entryp, &multi_col_segs, &multi_col_range_segs, &index_segs);
2707  if (multi_term_num != -1)
2708  {
2709  /* case of term having multiple columns */
2710  termp = QO_ENV_TERM (env, multi_term_num);
2711  if (!bitset_subset (&index_segs, &multi_col_segs))
2712  {
2713  /* need to add sarg term (data filter) */
2714  index_infop->need_copy_multi_range_term = multi_term_num;
2715  index_infop->need_copy_to_sarg_term = true;
2716  }
2717  else if (!bitset_subset (&multi_col_range_segs, &multi_col_segs)
2719  {
2720  /* need to add key filter term (index key filter) */
2721  index_infop->need_copy_multi_range_term = multi_term_num;
2722  index_infop->need_copy_to_sarg_term = false;
2723  }
2724  else
2725  {
2726  /* don't need to force-copy any filter */
2727  index_infop->need_copy_multi_range_term = -1;
2728  index_infop->need_copy_to_sarg_term = false;
2729  }
2730  /* add multi column term's segs ex) index(a,b,c), (a,b) in .. and c = 1 : nterms = 2 + 2 -1 */
2731  nterms = nterms + bitset_cardinality (&multi_col_range_segs) - 1;
2732  }
2733  else
2734  {
2735  index_infop->need_copy_multi_range_term = -1;
2736  index_infop->need_copy_to_sarg_term = false;
2737  }
2738 
2739  if (nterms == 0)
2740  {
2741  index_infop->nterms = 0;
2742  index_infop->term_exprs = NULL;
2743  index_infop->multi_col_pos = NULL;
2744  index_infop->ni_entry = ni_entryp;
2745  return index_infop;
2746  }
2747 
2748  index_infop->nterms = nterms;
2749  index_infop->term_exprs = (PT_NODE **) malloc (nterms * sizeof (PT_NODE *));
2750  index_infop->multi_col_pos = (int *) malloc (nterms * sizeof (int));
2751  if (index_infop->term_exprs == NULL)
2752  {
2754  goto error;
2755  }
2756 
2757  if (qo_is_index_iss_scan (plan))
2758  {
2759  assert (index_entryp->is_iss_candidate);
2760 
2761  index_infop->term_exprs[0] = NULL;
2762  index_infop->multi_col_pos[0] = -1;
2763  }
2764 
2765  index_infop->ni_entry = ni_entryp;
2766 
2767  /* Make 'term_expr[]' array from the given index terms in order of the 'seg_idx[]' array of the associated index. */
2768 
2769  /* for all index scan terms */
2770  for (t = bitset_iterate (&(plan->plan_un.scan.terms), &iter); t != -1; t = bitset_next_member (&iter))
2771  {
2772  /* pointer to QO_TERM denoted by number 't' */
2773  termp = QO_ENV_TERM (env, t);
2774 
2776  {
2777  /* Find the matching segment in the segment index array to determine the array position to store the expression.
2778  * We're using the 'index_seg[]' array of the term to find its segment index */
2779  pos = -1;
2780  for (i = 0; i < termp->can_use_index && pos == -1; i++)
2781  {
2782  for (j = 0; j < nsegs; j++)
2783  {
2784  if (i >= (int) (sizeof (termp->index_seg) / sizeof (termp->index_seg[0])))
2785  {
2787  goto error;
2788  }
2789 
2790  if ((index_entryp->seg_idxs[j]) == QO_SEG_IDX (termp->index_seg[i]))
2791  {
2792  pos = j;
2793  break;
2794  }
2795  }
2796  }
2797 
2798  /* always, pos != -1 and 0 <= pos < nterms */
2799  assert (pos >= 0 && pos < nterms);
2800  if (pos < 0 || pos >= nterms)
2801  {
2802  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, "pos >= 0 and pos < nterms");
2803  goto error;
2804  }
2805 
2806  /* if the index is Index Skip Scan, the first column should have never been found in a term */
2807  assert (!qo_is_index_iss_scan (plan) || pos != 0);
2808  index_infop->term_exprs[pos] = QO_TERM_PT_EXPR (termp);
2809  index_infop->multi_col_pos[pos] = -1;
2810  }
2811  else
2812  {
2813  /* case of multi column term */
2814  /* not need can_use_index's iteration because multi col term having other node's segments isn't indexable */
2815  /* ex) (a.col1,a.col2) in ((a.col1,b.col2)) is not indexable */
2816  for (i = 0; i < termp->multi_col_cnt; i++)
2817  {
2818  pos = -1;
2819  for (j = 0; j < nsegs; j++)
2820  {
2821  if ((index_entryp->seg_idxs[j]) == (termp->multi_col_segs[i]))
2822  {
2823  pos = j;
2824  break;
2825  }
2826  }
2827  /* if the index is Index Skip Scan, the first column should have never been found in a term */
2828  assert (!qo_is_index_iss_scan (plan) || pos != 0);
2829 
2830  if (pos != -1 && BITSET_MEMBER (multi_col_range_segs, index_entryp->seg_idxs[pos]))
2831  {
2832  /* always, pos != -1 and 0 <= pos < nterms */
2833  assert (pos >= 0 && pos < nterms);
2834  if (pos < 0 || pos >= nterms)
2835  {
2836  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, "pos >= 0 and pos < nterms");
2837  goto error;
2838  }
2839 
2840  index_infop->term_exprs[pos] = QO_TERM_PT_EXPR (termp);
2841  index_infop->multi_col_pos[pos] = i;
2842  }
2843  }
2844  }
2845  }
2846 
2847  bitset_delset (&multi_col_segs);
2848  bitset_delset (&multi_col_range_segs);
2849  bitset_delset (&index_segs);
2850  /* return QO_XASL_INDEX_INFO */
2851  return index_infop;
2852 
2853 error:
2854  /* malloc error */
2855  qo_free_xasl_index_info (env, index_infop);
2856  return NULL;
2857 }
2858 
2859 /*
2860  * qo_free_xasl_index_info () -
2861  * return: void
2862  * env(in): The environment
2863  * info(in): Information structure (QO_XASL_INDEX_INFO)
2864  *
2865  * Note: Free the memory occupied by the QO_XASL_INDEX_INFO
2866  */
2867 static void
2869 {
2870  if (info)
2871  {
2872  if (info->term_exprs)
2873  {
2874  free_and_init (info->term_exprs);
2875  }
2876  /* DEALLOCATE (env, info->term_exprs); */
2877  if (info->multi_col_pos)
2878  {
2879  free_and_init (info->multi_col_pos);
2880  }
2881  /* DEALLOCATE (env, info->multi_col_pos); */
2882  free_and_init (info);
2883  /* DEALLOCATE(env, info); */
2884  }
2885 }
2886 
2887 /*
2888  * qo_xasl_get_num_terms () - Return the number of terms in the array
2889  * return: int
2890  * info(in): Pointer to info structure
2891  */
2892 int
2894 {
2895  return info->nterms;
2896 }
2897 
2898 /*
2899  * qo_xasl_get_terms () - Return a point to the NULL terminated list
2900  * of TERM expressions
2901  * return: PT_NODE **
2902  * info(in): Pointer to info structure
2903  */
2904 PT_NODE **
2906 {
2907  return info->term_exprs;
2908 }
2909 
2910 /*
2911  * qo_add_hq_iterations_access_spec () - adds hierarchical query iterations
2912  * access spec on single table
2913  * return:
2914  * plan(in):
2915  * xasl(in):
2916  */
2917 xasl_node *
2919 {
2921  QO_ENV *env;
2922  PT_NODE *class_spec;
2923  PT_NODE *key_pred = NULL;
2924  PT_NODE *access_pred = NULL;
2925  PT_NODE *if_pred = NULL;
2926  QO_XASL_INDEX_INFO *index_info;
2927 
2928  if (!plan)
2929  {
2930  return NULL;
2931  }
2932 
2933  if (plan->plan_type == QO_PLANTYPE_SORT)
2934  {
2935  QO_PLAN *subplan = plan->plan_un.sort.subplan;
2936  while (subplan && subplan->plan_type == QO_PLANTYPE_SORT)
2937  {
2938  subplan = subplan->plan_un.sort.subplan;
2939  }
2940  if (subplan && subplan->plan_type == QO_PLANTYPE_SCAN)
2941  {
2942  plan = subplan;
2943  }
2944  else
2945  {
2946  return NULL;
2947  }
2948  }
2949  else if (plan->plan_type != QO_PLANTYPE_SCAN)
2950  {
2951  return NULL;
2952  }
2953 
2954  class_spec = plan->plan_un.scan.node->entity_spec;
2955  env = plan->info->env;
2956 
2957  parser = QO_ENV_PARSER (env);
2958 
2959  index_info = qo_get_xasl_index_info (env, plan);
2960  make_pred_from_plan (env, plan, &key_pred, &access_pred, index_info, NULL);
2961 
2962  xasl->spec_list = pt_to_spec_list (parser, class_spec, key_pred, access_pred, plan, index_info, NULL, NULL);
2963 
2964  if_pred = make_if_pred_from_plan (env, plan);
2965  if (if_pred)
2966  {
2967  xasl->if_pred = pt_to_pred_expr (parser, if_pred);
2968  }
2969 
2970  /* free pointer node list */
2971  parser_free_tree (parser, key_pred);
2972  parser_free_tree (parser, access_pred);
2973  parser_free_tree (parser, if_pred);
2974 
2975  qo_free_xasl_index_info (env, index_info);
2976 
2977  if (xasl->spec_list == NULL)
2978  {
2979  return NULL;
2980  }
2981 
2982  return xasl;
2983 }
2984 
2985 /*
2986  * regu_ptr_list_create () - creates and initializes a REGU_PTR_LIST - a linked
2987  * list of POINTERS to REGU VARIBLES
2988  * return: a new node, or NULL on error
2989  */
2990 static REGU_PTR_LIST
2992 {
2993  REGU_PTR_LIST p;
2994 
2995  p = (REGU_PTR_LIST) db_private_alloc (NULL, sizeof (struct regu_ptr_list_node));
2996  if (!p)
2997  {
2998  return NULL;
2999  }
3000 
3001  p->next = NULL;
3002  p->var_p = NULL;
3003 
3004  return p;
3005 }
3006 
3007 /*
3008  * regu_ptr_list_free () - iterates over a linked list of regu var pointers
3009  * and frees each node (the containing node, NOT the
3010  * actual REGU_VARIABLE).
3011  * list(in): the REGU_PTR_LIST. It can be NULL.
3012  * return:
3013  */
3014 static void
3016 {
3017  REGU_PTR_LIST next;
3018 
3019  while (list)
3020  {
3021  next = list->next;
3022  db_private_free (NULL, list);
3023  list = next;
3024  }
3025 }
3026 
3027 /*
3028  * regu_ptr_list_add_regu () - adds a pointer to a regu variable to the list,
3029  * initializing the list if required.
3030  *
3031  * regu(in): REGU_VAR ptr to add to the head of the list
3032  * list(in): the initial list. It can be NULL - in this case it will be initialised.
3033  * return: the list with the added element, or NULL on error.
3034  */
3035 static REGU_PTR_LIST
3037 {
3038  REGU_PTR_LIST node;
3039 
3040  if (!var_p)
3041  {
3042  return list;
3043  }
3044 
3045  node = (REGU_PTR_LIST) db_private_alloc (NULL, sizeof (struct regu_ptr_list_node));
3046  if (!node)
3047  {
3048  regu_ptr_list_free (list);
3049  return NULL;
3050  }
3051 
3052  node->next = list;
3053  node->var_p = var_p;
3054 
3055  return node;
3056 }
3057 
3058 static bool
3060 {
3061  if (var_p == NULL)
3062  {
3063  return true;
3064  }
3065 
3066  if (var_p->type == TYPE_DBVAL)
3067  {
3068  return true;
3069  }
3070  else if (var_p->type == TYPE_POS_VALUE)
3071  {
3072  return true;
3073  }
3074  else if (var_p->type == TYPE_INARITH && var_p->value.arithptr)
3075  {
3076  struct arith_list_node *aptr = var_p->value.arithptr;
3077 
3080  }
3081 
3082  return false;
3083 }
3084 
3085 /*
3086  * qo_get_limit_from_eval_term () - get lower and upper limits from an
3087  * eval term involving instnum
3088  * return: true on success.
3089  * parser(in):
3090  * pred(in): the predicate expression.
3091  * lower(out): lower limit node
3092  * upper(out): upper limit node
3093  *
3094  * Note: handles terms of the form:
3095  * instnum rel_op value/hostvar
3096  * value/hostvar rel_op instnum
3097  */
3098 static bool
3100 {
3101  REGU_VARIABLE *lhs, *rhs;
3102  REL_OP op;
3103  PT_NODE *node_one = NULL;
3105  REGU_VARIABLE *regu_one, *regu_low;
3106 
3107  if (pred == NULL || pred->type != T_EVAL_TERM || pred->pe.m_eval_term.et_type != T_COMP_EVAL_TERM)
3108  {
3109  return false;
3110  }
3111 
3112  lhs = pred->pe.m_eval_term.et.et_comp.lhs;
3113  rhs = pred->pe.m_eval_term.et.et_comp.rhs;
3114  op = pred->pe.m_eval_term.et.et_comp.rel_op;
3115 
3116  if (!lhs || !rhs)
3117  {
3118  return false;
3119  }
3120  if (op != R_LE && op != R_LT && op != R_GE && op != R_GT && op != R_EQ)
3121  {
3122  return false;
3123  }
3124 
3125  /* the TYPE_CONSTANT regu variable must be instnum, otherwise it would not be accepted by the parser */
3126 
3127  /* switch the ops to transform into instnum rel_op value/hostvar */
3128  if (rhs->type == TYPE_CONSTANT)
3129  {
3130  rhs = pred->pe.m_eval_term.et.et_comp.lhs;
3131  lhs = pred->pe.m_eval_term.et.et_comp.rhs;
3132  switch (op)
3133  {
3134  case R_LE:
3135  op = R_GE;
3136  break;
3137  case R_LT:
3138  op = R_GT;
3139  break;
3140  case R_GE:
3141  op = R_LE;
3142  break;
3143  case R_GT:
3144  op = R_LT;
3145  break;
3146  default:
3147  break;
3148  }
3149  }
3150 
3151  if (lhs->type != TYPE_CONSTANT || !qo_validate_regu_var_for_limit (rhs))
3152  {
3153  return false;
3154  }
3155 
3156  /* Bring every accepted relation to a form similar to lower < rownum <= upper. */
3157  switch (op)
3158  {
3159  case R_EQ:
3160  /* decrement node value for lower, but remember current value for upper */
3161  node_one = pt_make_integer_value (parser, 1);
3162  if (!node_one)
3163  {
3164  return false;
3165  }
3166 
3167  if (!(regu_one = pt_to_regu_variable (parser, node_one, UNBOX_AS_VALUE))
3168  || !(regu_low = pt_make_regu_arith (rhs, regu_one, NULL, T_SUB, dom_bigint)))
3169  {
3170  parser_free_node (parser, node_one);
3171  return false;
3172  }
3173  regu_low->domain = dom_bigint;
3174 
3175  *lower = regu_ptr_list_add_regu (regu_low, *lower);
3176  *upper = regu_ptr_list_add_regu (rhs, *upper);
3177  break;
3178 
3179  case R_LE:
3180  *upper = regu_ptr_list_add_regu (rhs, *upper);
3181  break;
3182 
3183  case R_LT:
3184  /* decrement node value */
3185  node_one = pt_make_integer_value (parser, 1);
3186  if (!node_one)
3187  {
3188  return false;
3189  }
3190 
3191  if (!(regu_one = pt_to_regu_variable (parser, node_one, UNBOX_AS_VALUE))
3192  || !(regu_low = pt_make_regu_arith (rhs, regu_one, NULL, T_SUB, dom_bigint)))
3193  {
3194  parser_free_node (parser, node_one);
3195  return false;
3196  }
3197  regu_low->domain = dom_bigint;
3198 
3199  *upper = regu_ptr_list_add_regu (regu_low, *upper);
3200  break;
3201 
3202  case R_GE:
3203  /* decrement node value for lower */
3204  node_one = pt_make_integer_value (parser, 1);
3205  if (!node_one)
3206  {
3207  return false;
3208  }
3209 
3210  if (!(regu_one = pt_to_regu_variable (parser, node_one, UNBOX_AS_VALUE))
3211  || !(regu_low = pt_make_regu_arith (rhs, regu_one, NULL, T_SUB, dom_bigint)))
3212  {
3213  parser_free_node (parser, node_one);
3214  return false;
3215  }
3216  regu_low->domain = dom_bigint;
3217 
3218  *lower = regu_ptr_list_add_regu (regu_low, *lower);
3219  break;
3220 
3221  case R_GT:
3222  /* leave node value as it is */
3223  *lower = regu_ptr_list_add_regu (rhs, *lower);
3224  break;
3225 
3226  default:
3227  break;
3228  }
3229 
3230  if (node_one)
3231  {
3232  parser_free_node (parser, node_one);
3233  }
3234 
3235  return true;
3236 }
3237 
3238 /*
3239  * qo_get_limit_from_instnum_pred () - get lower and upper limits from an
3240  * instnum predicate
3241  * return: true if successful
3242  * parser(in):
3243  * pred(in): the predicate expression
3244  * lower(out): lower limit node
3245  * upper(out): upper limit node
3246  */
3247 static bool
3249 {
3250  if (pred == NULL)
3251  {
3252  return false;
3253  }
3254 
3255  if (pred->type == T_PRED && pred->pe.m_pred.bool_op == B_AND)
3256  {
3257  return (qo_get_limit_from_instnum_pred (parser, pred->pe.m_pred.lhs, lower, upper)
3258  && qo_get_limit_from_instnum_pred (parser, pred->pe.m_pred.rhs, lower, upper));
3259  }
3260 
3261  if (pred->type == T_EVAL_TERM)
3262  {
3263  return qo_get_limit_from_eval_term (parser, pred, lower, upper);
3264  }
3265 
3266  return false;
3267 }
3268 
3269 /*
3270  * qo_get_key_limit_from_instnum () - creates a keylimit node from an
3271  * instnum predicate, if possible.
3272  * return: a new node, or NULL if a keylimit node cannot be
3273  * initialized (not necessarily an error)
3274  * parser(in): the parser context
3275  * plan (in): the query plan
3276  * xasl (in): the full XASL node
3277  */
3278 QO_LIMIT_INFO *
3280 {
3281  REGU_PTR_LIST lower = NULL, upper = NULL, ptr = NULL;
3282  QO_LIMIT_INFO *limit_infop = NULL;
3284 
3285  if (xasl == NULL || xasl->instnum_pred == NULL || plan == NULL)
3286  {
3287  return NULL;
3288  }
3289 
3290  switch (plan->plan_type)
3291  {
3292  case QO_PLANTYPE_SCAN:
3293  if (!qo_is_interesting_order_scan (plan))
3294  {
3295  return NULL;
3296  }
3297  break;
3298 
3299  case QO_PLANTYPE_JOIN:
3300  /* only allow inner joins */
3301  if (plan->plan_un.join.join_type != JOIN_INNER)
3302  {
3303  return NULL;
3304  }
3305  break;
3306 
3307  default:
3308  return NULL;
3309  }
3310 
3311  /* get lower and upper limits */
3312  if (!qo_get_limit_from_instnum_pred (parser, xasl->instnum_pred, &lower, &upper))
3313  {
3314  return NULL;
3315  }
3316  /* not having upper limit is not helpful */
3317  if (upper == NULL)
3318  {
3319  regu_ptr_list_free (lower);
3320  return NULL;
3321  }
3322 
3323  limit_infop = (QO_LIMIT_INFO *) db_private_alloc (NULL, sizeof (QO_LIMIT_INFO));
3324  if (limit_infop == NULL)
3325  {
3326  regu_ptr_list_free (lower);
3327  regu_ptr_list_free (upper);
3328  return NULL;
3329  }
3330 
3331  limit_infop->lower = limit_infop->upper = NULL;
3332 
3333 
3334  /* upper limit */
3335  limit_infop->upper = upper->var_p;
3336  ptr = upper->next;
3337  while (ptr)
3338  {
3339  limit_infop->upper = pt_make_regu_arith (limit_infop->upper, ptr->var_p, NULL, T_LEAST, dom_bigint);
3340  if (!limit_infop->upper)
3341  {
3342  regu_ptr_list_free (upper);
3343  regu_ptr_list_free (lower);
3344  db_private_free (NULL, limit_infop);
3345  return NULL;
3346  }
3347 
3348  limit_infop->upper->domain = dom_bigint;
3349  ptr = ptr->next;
3350  }
3351  regu_ptr_list_free (upper);
3352 
3353  if (lower)
3354  {
3355  limit_infop->lower = lower->var_p;
3356  ptr = lower->next;
3357  while (ptr)
3358  {
3359  limit_infop->lower = pt_make_regu_arith (limit_infop->lower, ptr->var_p, NULL, T_GREATEST, dom_bigint);
3360  if (!limit_infop->lower)
3361  {
3362  regu_ptr_list_free (lower);
3363  db_private_free (NULL, limit_infop);
3364  return NULL;
3365  }
3366 
3367  limit_infop->lower->domain = dom_bigint;
3368  ptr = ptr->next;
3369  }
3370  regu_ptr_list_free (lower);
3371  }
3372 
3373  return limit_infop;
3374 }
3375 
3376 /*
3377  * qo_get_key_limit_from_ordbynum () - creates a keylimit node from an
3378  * orderby_num predicate, if possible.
3379  * return: a new node, or NULL if a keylimit node cannot be
3380  * initialized (not necessarily an error)
3381  * parser(in): the parser context
3382  * plan (in): the query plan
3383  * xasl (in): the full XASL node
3384  * ignore_lower (in): generate key limit even if ordbynum has a lower limit
3385  */
3386 QO_LIMIT_INFO *
3388 {
3389  REGU_PTR_LIST lower = NULL, upper = NULL, ptr = NULL;
3390  QO_LIMIT_INFO *limit_infop;
3392 
3393  if (xasl == NULL || xasl->ordbynum_pred == NULL)
3394  {
3395  return NULL;
3396  }
3397 
3398  /* get lower and upper limits */
3399  if (!qo_get_limit_from_instnum_pred (parser, xasl->ordbynum_pred, &lower, &upper))
3400  {
3401  return NULL;
3402  }
3403  /* having a lower limit, or not having upper limit is not helpful */
3404  if (upper == NULL || (lower != NULL && !ignore_lower))
3405  {
3406  regu_ptr_list_free (lower);
3407  regu_ptr_list_free (upper);
3408  return NULL;
3409  }
3410 
3411  limit_infop = (QO_LIMIT_INFO *) db_private_alloc (NULL, sizeof (QO_LIMIT_INFO));
3412  if (!limit_infop)
3413  {
3414  regu_ptr_list_free (lower);
3415  regu_ptr_list_free (upper);
3416  return NULL;
3417  }
3418 
3419  limit_infop->lower = limit_infop->upper = NULL;
3420 
3421  /* upper limit */
3422  limit_infop->upper = upper->var_p;
3423  ptr = upper->next;
3424  while (ptr)
3425  {
3426  limit_infop->upper = pt_make_regu_arith (limit_infop->upper, ptr->var_p, NULL, T_LEAST, dom_bigint);
3427  if (!limit_infop->upper)
3428  {
3429  regu_ptr_list_free (upper);
3430  regu_ptr_list_free (lower);
3431  db_private_free (NULL, limit_infop);
3432  return NULL;
3433  }
3434 
3435  limit_infop->upper->domain = dom_bigint;
3436  ptr = ptr->next;
3437  }
3438 
3439  regu_ptr_list_free (upper);
3440  regu_ptr_list_free (lower);
3441 
3442  return limit_infop;
3443 }
3444 
3445 /*
3446  * qo_check_iscan_for_multi_range_opt () - check that current index scan can
3447  * use multi range key-limit
3448  * optimization
3449  *
3450  * return : true/false
3451  * plan (in) : index scan plan
3452  *
3453  * Note: The optimization requires a series of conditions to be met:
3454  * For single table case:
3455  * - valid order by for condition
3456  * -> the upper limit has to be less than multi_range_opt_limit
3457  * system parameter
3458  * -> the expression should look like: LIMIT n,
3459  ORDERBY_NUM </<= n,
3460  * n > ORDERBY_NUM
3461  * or AND operator on ORDERBY_NUM valid expressions.
3462  * -> lower limit is not allowed
3463  * - index scan with no data filter
3464  * - order by columns should occupy consecutive positions in index and
3465  * the ordering should match all columns (or all should be reversed)
3466  * - index access keys have multiple key ranges, but only one range
3467  * column
3468  * - The generic case that uses multi range optimization is the
3469  * following:
3470  * SELECT ... FROM table
3471  * WHERE col_1 = ? AND col_2 = ? AND ...
3472  * AND col_(j) IN (?,?,...)
3473  * AND col_(j+1) = ? AND ... AND col_(p-1) = ?
3474  * ORDER BY col_(p) [ASC/DESC] [, col_(p2) [ASC/DESC], ...]
3475  * FOR ordbynum_pred / LIMIT n
3476  */
3477 bool
3479 {
3480  QO_ENV *env = NULL;
3481  bool can_optimize = 0;
3482  PT_NODE *col = NULL, *query = NULL, *select_list = NULL;
3483  int error = NO_ERROR;
3484  bool multi_range_optimize = false;
3485  int first_col_idx_pos = -1, i = 0;
3486  PT_NODE *orderby_nodes = NULL, *point = NULL, *name = NULL;
3488  bool reverse = false;
3489  PT_NODE *order_by = NULL;
3490  PT_MISC_TYPE all_distinct;
3491 
3492 
3493  if (plan == NULL)
3494  {
3495  return false;
3496  }
3497 
3498  if (!qo_is_iscan (plan))
3499  {
3500  return false;
3501  }
3502 
3503  if (QO_NODE_IS_CLASS_HIERARCHY (plan->plan_un.scan.node))
3504  {
3505  /* for now, multi range optimization can only work on one index, therefore class hierarchies are not accepted */
3506  return false;
3507  }
3508 
3509  assert (plan->info->env && plan->info->env->parser);
3510  env = plan->info->env;
3511  parser = env->parser;
3512 
3513  query = QO_ENV_PT_TREE (env);
3514  if (!PT_IS_SELECT (query))
3515  {
3516  return false;
3517  }
3518  if ((query->info.query.q.select.hint & PT_HINT_NO_MULTI_RANGE_OPT) != 0)
3519  {
3520  /* NO_MULTI_RANGE_OPT was hinted */
3521  return false;
3522  }
3523  if (pt_has_aggregate (parser, query))
3524  {
3525  // CBRD-22696
3526  //
3527  // MRO XASL is flawed when query has aggregate. MRO depends on order by list, which is generated based on
3528  // query's select list. Then it uses pointers from XASL outptr_list, which is normally also generated based
3529  // on query's select list.
3530  //
3531  // In case of group by and/or aggregates, XASL outptr_list is used as input list for group by/aggregate. As a
3532  // consequence, MRO is broken; sometimes it will fallback to normal index scan (because pointers do not match),
3533  // but sometimes a safe-guard is hit (when order by position number is not found in outptr_list).
3534  //
3535  // until a proper fix is found, MRO is disabled for aggregate queries.
3536  return false;
3537  }
3538  all_distinct = query->info.query.all_distinct;
3539  order_by = query->info.query.order_by;
3540 
3541  if (order_by == NULL || all_distinct == PT_DISTINCT)
3542  {
3543  return false;
3544  }
3545 
3546  if (query->info.query.orderby_for == NULL)
3547  {
3548  return false;
3549  }
3550 
3551  select_list = pt_get_select_list (parser, query);
3552  assert (select_list != NULL);
3553 
3554  /* create a list of pointers to the names referenced in order by */
3555  for (col = order_by; col != NULL; col = col->next)
3556  {
3557  i = col->info.sort_spec.pos_descr.pos_no;
3558  if (i <= 0)
3559  {
3560  goto exit;
3561  }
3562  name = select_list;
3563  while (--i > 0)
3564  {
3565  name = name->next;
3566  if (name == NULL)
3567  {
3568  goto exit;
3569  }
3570  }
3571  if (!PT_IS_NAME_NODE (name))
3572  {
3573  goto exit;
3574  }
3575  point = pt_point (parser, name);
3576  orderby_nodes = parser_append_node (point, orderby_nodes);
3577  }
3578 
3579  /* verify that the index used for scan contains all order by columns in the right order and with the right ordering
3580  * (or reversed ordering) */
3581  error =
3582  qo_check_plan_index_for_multi_range_opt (orderby_nodes, order_by, plan, &can_optimize, &first_col_idx_pos,
3583  &reverse);
3584  if (error != NO_ERROR || !can_optimize)
3585  {
3586  goto exit;
3587  }
3588 
3589  /* check scan terms and key filter terms to verify that multi range optimization is applicable */
3590  error = qo_check_terms_for_multiple_range_opt (plan, first_col_idx_pos, &can_optimize);
3591  if (error != NO_ERROR || !can_optimize)
3592  {
3593  goto exit;
3594  }
3595 
3596  /* make sure that correlated subqueries may not affect the results obtained with multiple range optimization */
3597  can_optimize = qo_check_subqueries_for_multi_range_opt (plan, first_col_idx_pos);
3598  if (!can_optimize)
3599  {
3600  goto exit;
3601  }
3602 
3603  /* check a valid range */
3605  {
3606  goto exit;
3607  }
3608 
3609  /* all conditions were met, so multi range optimization can be applied */
3610  multi_range_optimize = true;
3611 
3612  plan->plan_un.scan.index->head->use_descending = reverse;
3613  plan->plan_un.scan.index->head->first_sort_column = first_col_idx_pos;
3614  plan->use_iscan_descending = reverse;
3615 
3616 exit:
3617  if (orderby_nodes != NULL)
3618  {
3619  parser_free_tree (parser, orderby_nodes);
3620  }
3621  return multi_range_optimize;
3622 }
3623 
3624 /*
3625  * qo_check_plan_index_for_multi_range_opt () - check if the index of index
3626  * scan plan can use multi range
3627  * key-limit optimization
3628  *
3629  * return : error code
3630  * orderby_nodes (in) : list of pointer to the names of order by columns
3631  * orderby_sort_list (in) : list of PT_SORT_SPEC for the order by columns
3632  * plan (in) : current plan to check
3633  * is_valid (out) : true/false
3634  * first_col_idx_pos (out) : position in index for the first sort column
3635  * reverse (out) : true if the index has to be reversed in order to
3636  * use multiple range optimization, false otherwise
3637  *
3638  * NOTE: In order to be compatible with multi range optimization, the index of
3639  * index scan plan must meet the next conditions:
3640  * - index should cover all order by columns and their positions in
3641  * index should be consecutive (in the same order as in the order by
3642  * clause).
3643  * - column ordering should either match in both order by clause and
3644  * index, or should all be reversed.
3645  */
3646 static int
3647 qo_check_plan_index_for_multi_range_opt (PT_NODE * orderby_nodes, PT_NODE * orderby_sort_list, QO_PLAN * plan,
3648  bool * is_valid, int *first_col_idx_pos, bool * reverse)
3649 {
3650  int i = 0, seg_idx = -1;
3651  QO_INDEX_ENTRY *index_entryp = NULL;
3652  QO_ENV *env = NULL;
3653  PT_NODE *orderby_node = NULL;
3654  PT_NODE *orderby_sort_column = NULL;
3655  PT_NODE *n = NULL, *save_next = NULL;
3656  TP_DOMAIN *key_type = NULL;
3657 
3658  assert (plan != NULL && orderby_nodes != NULL && is_valid != NULL && first_col_idx_pos != NULL && reverse != NULL);
3659 
3660  *is_valid = false;
3661  *reverse = false;
3662  *first_col_idx_pos = -1;
3663 
3664  if (!qo_is_iscan (plan))
3665  {
3666  return NO_ERROR;
3667  }
3668  if (plan->plan_un.scan.index == NULL || plan->plan_un.scan.index->head == NULL)
3669  {
3670  return NO_ERROR;
3671  }
3672  if (plan->info->env == NULL)
3673  {
3674  return NO_ERROR;
3675  }
3676 
3677  env = plan->info->env;
3678  index_entryp = plan->plan_un.scan.index->head;
3679 
3680  key_type = index_entryp->key_type;
3681  if (key_type == NULL || (TP_DOMAIN_TYPE (key_type) != DB_TYPE_MIDXKEY))
3682  {
3683  return NO_ERROR;
3684  }
3685  key_type = key_type->setdomain;
3686 
3687  /* look for the first order by column */
3688  orderby_node = orderby_nodes;
3689  CAST_POINTER_TO_NODE (orderby_node);
3690  assert (orderby_node->node_type == PT_NAME);
3691 
3692  orderby_sort_column = orderby_sort_list;
3693  assert (orderby_sort_column->node_type == PT_SORT_SPEC);
3694 
3695  for (i = 0; i < index_entryp->nsegs; i++, key_type = key_type->next)
3696  {
3697  if (!key_type)
3698  {
3699  return NO_ERROR;
3700  }
3701  seg_idx = index_entryp->seg_idxs[i];
3702  if (seg_idx < 0)
3703  {
3704  continue;
3705  }
3706  n = QO_SEG_PT_NODE (QO_ENV_SEG (env, seg_idx));
3708  if (n && n->node_type == PT_NAME && pt_name_equal (env->parser, orderby_node, n))
3709  {
3710  if (i == 0)
3711  {
3712  /* MRO cannot apply */
3713  return NO_ERROR;
3714  }
3715  if (key_type->is_desc != (orderby_sort_column->info.sort_spec.asc_or_desc == PT_DESC))
3716  {
3717  /* order in index does not match order in order by clause, but reversed index may work */
3718  *reverse = true;
3719  }
3720  break;
3721  }
3722  }
3723  if (i == index_entryp->nsegs)
3724  {
3725  /* order by node was not found */
3726  return NO_ERROR;
3727  }
3728 
3729  if (index_entryp->first_sort_column != -1)
3730  {
3731  assert (index_entryp->first_sort_column == i);
3732  }
3733 
3734  *first_col_idx_pos = i;
3735  /* order by node was found, check that all nodes occupy consecutive positions in index */
3736  for (orderby_node = orderby_nodes->next, i = i + 1, key_type = key_type->next, orderby_sort_column =
3737  orderby_sort_list->next; orderby_node != NULL && orderby_sort_column != NULL && i < index_entryp->nsegs;
3738  i++, orderby_sort_column = orderby_sort_column->next, key_type = key_type->next)
3739  {
3740  if (key_type == NULL)
3741  {
3742  return NO_ERROR;
3743  }
3744  seg_idx = index_entryp->seg_idxs[i];
3745  if (seg_idx < 0)
3746  {
3747  return NO_ERROR;
3748  }
3749 
3750  save_next = orderby_node->next;
3751  CAST_POINTER_TO_NODE (orderby_node);
3752  n = QO_SEG_PT_NODE (QO_ENV_SEG (env, seg_idx));
3754  if (n == NULL || n->node_type != PT_NAME || !pt_name_equal (env->parser, orderby_node, n))
3755  {
3756  /* order by columns do not match the columns in index */
3757  return NO_ERROR;
3758  }
3759  if ((*reverse ? !key_type->is_desc : key_type->is_desc) !=
3760  (orderby_sort_column->info.sort_spec.asc_or_desc == PT_DESC))
3761  {
3762  /* normally, key_type->is_desc must match sort order == PT_DESC, if reversed, !key_type->is_desc must match
3763  * instead. */
3764  return NO_ERROR;
3765  }
3766  orderby_node = save_next;
3767  }
3768  if (orderby_node != NULL)
3769  {
3770  /* there are order by columns left */
3771  return NO_ERROR;
3772  }
3773  /* all segments in index matched columns in order by list */
3774  *is_valid = true;
3775 
3776  return NO_ERROR;
3777 }
3778 
3779 /*
3780  * qo_check_plan_for_multiple_ranges_limit_opt () - check the plan to find out
3781  * if multiple ranges key
3782  * limit optimization can be
3783  * used
3784  *
3785  * return : error_code
3786  * parser(in) : parser context
3787  * plan(in) : plan to check
3788  * idx_col(in) : first sort column position in index
3789  * can_optimize(out) : true/false if optimization is allowed/not allowed
3790  *
3791  * Note: Check that all columns that come before the first sort column (on
3792  * the left side of the sort column) in the index are either in an
3793  * equality term, or in a key list term. Only one column should be in
3794  * a key list term.
3795  * Also check all terms in the environment to see if there is any
3796  * data filter
3797  */
3798 static int
3799 qo_check_terms_for_multiple_range_opt (QO_PLAN * plan, int first_sort_col_idx, bool * can_optimize)
3800 {
3801  int t, i, j, pos, s, seg_idx;
3802  BITSET_ITERATOR iter_t, iter_s;
3803  QO_TERM *termp = NULL;
3804  QO_ENV *env = NULL;
3805  QO_INDEX_ENTRY *index_entryp = NULL;
3806  QO_NODE *node_of_plan = NULL;
3807  int *used_cols = NULL;
3808  int kl_terms = 0;
3809 
3810  assert (can_optimize != NULL);
3811 
3812  *can_optimize = false;
3813 
3814  if (plan == NULL || plan->info == NULL || plan->plan_un.scan.index == NULL || !qo_is_interesting_order_scan (plan))
3815  {
3816  return NO_ERROR;
3817  }
3818 
3819  env = plan->info->env;
3820  if (env == NULL)
3821  {
3822  return NO_ERROR;
3823  }
3824 
3825  index_entryp = plan->plan_un.scan.index->head;
3826  if (index_entryp == NULL)
3827  {
3828  return NO_ERROR;
3829  }
3830 
3831  node_of_plan = plan->plan_un.scan.node;
3832  if (node_of_plan == NULL)
3833  {
3834  return NO_ERROR;
3835  }
3836 
3837  /* index columns that are used in terms */
3838  used_cols = (int *) malloc (first_sort_col_idx * sizeof (int));
3839  if (!used_cols)
3840  {
3841  return ER_FAILED;
3842  }
3843  for (i = 0; i < first_sort_col_idx; i++)
3844  {
3845  used_cols[i] = 0;
3846  }
3847 
3848  /* check all index scan terms */
3849  for (t = bitset_iterate (&(plan->plan_un.scan.terms), &iter_t); t != -1; t = bitset_next_member (&iter_t))
3850  {
3851  termp = QO_ENV_TERM (env, t);
3853 
3854  pos = -1;
3855  for (i = 0; i < termp->can_use_index && i < 2 && pos == -1; i++)
3856  {
3857  for (j = 0; j < index_entryp->nsegs; j++)
3858  {
3859  if ((index_entryp->seg_idxs[j] == QO_SEG_IDX (termp->index_seg[i])))
3860  {
3861  pos = j;
3862  break;
3863  }
3864  }
3865  }
3866  if (pos == -1)
3867  {
3868  free_and_init (used_cols);
3869  return NO_ERROR;
3870  }
3871 
3872  if (pos < first_sort_col_idx)
3873  {
3874  used_cols[pos]++;
3875  /* only helpful if term is equality or key list */
3876  switch (QO_TERM_PT_EXPR (termp)->info.expr.op)
3877  {
3878  case PT_EQ:
3879  break;
3880  case PT_IS_IN:
3881  case PT_EQ_SOME:
3882  kl_terms++;
3883  break;
3884  case PT_RANGE:
3885  {
3886  PT_NODE *between_and;
3887 
3888  between_and = QO_TERM_PT_EXPR (termp)->info.expr.arg2;
3889  if (PT_IS_EXPR_NODE (between_and) && between_and->info.expr.op == PT_BETWEEN_EQ_NA)
3890  {
3891  kl_terms++;
3892  }
3893  else
3894  {
3895  free_and_init (used_cols);
3896  return NO_ERROR;
3897  }
3898  }
3899  break;
3900  default:
3901  free_and_init (used_cols);
3902  return NO_ERROR;
3903  }
3904  }
3905  }
3906 
3907  /* check key list terms */
3908  if (kl_terms > 1)
3909  {
3910  free_and_init (used_cols);
3911  return NO_ERROR;
3912  }
3913 
3914  /* check all key filter terms */
3915  for (t = bitset_iterate (&(plan->plan_un.scan.kf_terms), &iter_t); t != -1; t = bitset_next_member (&iter_t))
3916  {
3917  termp = QO_ENV_TERM (env, t);
3919 
3920  pos = -1;
3921  for (i = 0; i < termp->can_use_index && i < 2 && pos == -1; i++)
3922  {
3923  for (j = 0; j < index_entryp->nsegs; j++)
3924  {
3925  if ((index_entryp->seg_idxs[j] == QO_SEG_IDX (termp->index_seg[i])))
3926  {
3927  pos = j;
3928  break;
3929  }
3930  }
3931  }
3932  if (pos == -1)
3933  {
3934  if (termp->can_use_index == 0)
3935  {
3936  continue;
3937  }
3938  free_and_init (used_cols);
3939  return NO_ERROR;
3940  }
3941 
3942  if (pos < first_sort_col_idx)
3943  {
3944  /* for key filter terms we are only interested if it is an eq term */
3945  if (QO_TERM_PT_EXPR (termp)->info.expr.op == PT_EQ)
3946  {
3947  used_cols[pos]++;
3948  }
3949  }
3950  }
3951 
3952  /* check used columns */
3953  for (i = 0; i < first_sort_col_idx; i++)
3954  {
3955  if (used_cols[i] == 0)
3956  {
3957  free_and_init (used_cols);
3958  return NO_ERROR;
3959  }
3960  }
3961  free_and_init (used_cols);
3962 
3963  /* check all segments in all terms in environment for data filter */
3964  for (t = 0; t < env->nterms; t++)
3965  {
3966  termp = QO_ENV_TERM (env, t);
3968  {
3969  return NO_ERROR;
3970  }
3971 
3972  for (s = bitset_iterate (&(termp->segments), &iter_s); s != -1; s = bitset_next_member (&iter_s))
3973  {
3974  bool found = false;
3975  if (QO_SEG_HEAD (QO_ENV_SEG (env, s)) != node_of_plan)
3976  {
3977  continue;
3978  }
3979  seg_idx = s;
3980 
3981  for (i = 0; i < index_entryp->nsegs; i++)
3982  {
3983  if (seg_idx == index_entryp->seg_idxs[i])
3984  {
3985  found = true;
3986  break;
3987  }
3988  }
3989  if (!found)
3990  {
3991  /* data filter */
3992  return NO_ERROR;
3993  }
3994  }
3995  }
3996 
3997  *can_optimize = true;
3998  return NO_ERROR;
3999 }
4000 
4001 /*
4002  * qo_check_subqueries_for_multi_range_opt () - check that there are not
4003  * subqueries that may invalidate
4004  * multiple range optimization
4005  *
4006  * return : false if invalidated, true otherwise
4007  * plan (in) : the plan that refers to the table that has the
4008  * order by columns
4009  * sort_col_idx_pos (in) : position in index for the first sort column
4010  *
4011  * NOTE: If there are terms containing correlated subqueries, and if they
4012  * refer to the node of the sort plan, then the affected segments must
4013  * appear in index before the first sort column (and the segment must
4014  * not belong to the range term).
4015  */
4016 static bool
4017 qo_check_subqueries_for_multi_range_opt (QO_PLAN * plan, int sort_col_idx_pos)
4018 {
4019  QO_ENV *env = NULL;
4020  QO_SUBQUERY *subq = NULL;
4021  int i, s, t, seg_idx, i_seg_idx, ts;
4022  QO_NODE *node_of_plan = NULL;
4023  BITSET_ITERATOR iter_t, iter_ts;
4024  QO_TERM *term = NULL;
4025 
4026  assert (plan != NULL && plan->info->env != NULL && plan->plan_type == QO_PLANTYPE_SCAN
4027  && plan->plan_un.scan.index != NULL);
4028 
4029  env = plan->info->env;
4030  node_of_plan = plan->plan_un.scan.node;
4031 
4032  /* for each sub-query */
4033  for (s = 0; s < env->nsubqueries; s++)
4034  {
4035  subq = QO_ENV_SUBQUERY (env, s);
4036 
4037  /* for each term this sub-query belongs to */
4038  for (t = bitset_iterate (&(subq->terms), &iter_t); t != -1; t = bitset_next_member (&iter_t))
4039  {
4040  term = QO_ENV_TERM (env, t);
4041 
4042  for (ts = bitset_iterate (&(term->segments), &iter_ts); ts != -1; ts = bitset_next_member (&iter_ts))
4043  {
4044  bool found = false;
4045  if (QO_SEG_HEAD (QO_ENV_SEG (env, t)) != node_of_plan)
4046  {
4047  continue;
4048  }
4049  seg_idx = ts;
4050  /* try to find the segment in index */
4051  for (i = 0; i < sort_col_idx_pos; i++)
4052  {
4053  i_seg_idx = plan->plan_un.scan.index->head->seg_idxs[i];
4054  if (i_seg_idx == seg_idx)
4055  {
4056  if (qo_check_seg_belongs_to_range_term (plan, env, seg_idx))
4057  {
4058  return false;
4059  }
4060  break;
4061  }
4062  }
4063  if (!found)
4064  {
4065  /* the segment was not found before the first sort column */
4066  return false;
4067  }
4068  }
4069  }
4070  }
4071  return true;
4072 }
4073 
4074 /*
4075  * qo_check_seg_belongs_to_range_term () - checks the segment if it is a range
4076  * term
4077  *
4078  * return : true or false
4079  * subplan (in) : the subplan possibly containing the RANGE expression
4080  * env (in) : optimizer environment
4081  * seg_idx (in) : index of the segment that needs checking
4082  *
4083  * NOTE: Returns true if the specified subplan contains a term that
4084  * references the given segment in a RANGE expression
4085  * (t.i in (1,2,3) would be an example).
4086  * Used in keylimit for multiple key ranges in joins optimization.
4087  * Scan terms, key filter terms and also sarged terms must all be
4088  * checked to cover all cases.
4089  */
4090 static bool
4091 qo_check_seg_belongs_to_range_term (QO_PLAN * subplan, QO_ENV * env, int seg_idx)
4092 {
4093  int t, u;
4094  BITSET_ITERATOR iter, iter_s;
4095 
4096  assert (subplan->plan_type == QO_PLANTYPE_SCAN);
4097  if (subplan->plan_type != QO_PLANTYPE_SCAN)
4098  {
4099  return false;
4100  }
4101 
4102  for (t = bitset_iterate (&(subplan->plan_un.scan.terms), &iter); t != -1; t = bitset_next_member (&iter))
4103  {
4104  QO_TERM *termp = QO_ENV_TERM (env, t);
4105  BITSET *segs = &(QO_TERM_SEGS (termp));
4106  if (!segs)
4107  {
4108  continue;
4109  }
4110  for (u = bitset_iterate (segs, &iter_s); u != -1; u = bitset_next_member (&iter_s))
4111  {
4112  if (u == seg_idx)
4113  {
4114  PT_NODE *node = QO_TERM_PT_EXPR (termp);
4115  if (!node)
4116  {
4117  continue;
4118  }
4119 
4120  switch (node->info.expr.op)
4121  {
4122  case PT_IS_IN:
4123  case PT_EQ_SOME:
4124  case PT_RANGE:
4125  return true;
4126  default:
4127  continue;
4128  }
4129  }
4130  }
4131  }
4132  for (t = bitset_iterate (&(subplan->plan_un.scan.kf_terms), &iter); t != -1; t = bitset_next_member (&iter))
4133  {
4134  QO_TERM *termp = QO_ENV_TERM (env, t);
4135  BITSET *segs = &(QO_TERM_SEGS (termp));
4136  if (!segs)
4137  {
4138  continue;
4139  }
4140  for (u = bitset_iterate (segs, &iter_s); u != -1; u = bitset_next_member (&iter_s))
4141  {
4142  if (u == seg_idx)
4143  {
4144  PT_NODE *node = QO_TERM_PT_EXPR (termp);
4145  if (!node)
4146  {
4147  continue;
4148  }
4149 
4150  switch (node->info.expr.op)
4151  {
4152  case PT_IS_IN:
4153  case PT_EQ_SOME:
4154  case PT_RANGE:
4155  return true;
4156  default:
4157  continue;
4158  }
4159  }
4160  }
4161  }
4162  for (t = bitset_iterate (&(subplan->sarged_terms), &iter); t != -1; t = bitset_next_member (&iter))
4163  {
4164  QO_TERM *termp = QO_ENV_TERM (env, t);
4165  BITSET *segs = &(QO_TERM_SEGS (termp));
4166  if (!segs)
4167  {
4168  continue;
4169  }
4170  for (u = bitset_iterate (segs, &iter_s); u != -1; u = bitset_next_member (&iter_s))
4171  {
4172  if (u == seg_idx)
4173  {
4174  PT_NODE *node = QO_TERM_PT_EXPR (termp);
4175  if (!node)
4176  {
4177  continue;
4178  }
4179 
4180  switch (node->info.expr.op)
4181  {
4182  case PT_IS_IN:
4183  case PT_EQ_SOME:
4184  case PT_RANGE:
4185  return true;
4186  default:
4187  continue;
4188  }
4189  }
4190  }
4191  }
4192  return false;
4193 }
4194 
4195 /*
4196  * qo_check_join_for_multi_range_opt () - check if join plan can make use of
4197  * multi range key-limit optimization
4198  *
4199  * return : true/false
4200  * plan (in) : join plan
4201  *
4202  * NOTE: The current join plan has to meet a series of conditions in order
4203  * to use the multi range optimization:
4204  * - Has at least an index scan subplan that can make use of multi
4205  * range optimization (as if there would be no joins)
4206  * - The sort plan (that uses multi range optimization) edges:
4207  * - Segments used to join other "outer-more" scans must also belong
4208  * to index (no data filter).
4209  * - Segments use to join other "inner-more" scans must belong to
4210  * index (no data filter), they must be positioned before the first
4211  * sorting column, and they cannot be in a range term (in order
4212  * to avoid filtering the results obtained after top n sorting).
4213  */
4214 bool
4216 {
4217  QO_PLAN *sort_plan = NULL;
4218  int error = NO_ERROR;
4219  bool can_optimize = true;
4220 
4221  /* verify that this is a valid join for multi range optimization */
4222  if (plan == NULL || plan->plan_type != QO_PLANTYPE_JOIN || plan->plan_un.join.join_type != JOIN_INNER
4223  || plan->plan_un.join.join_method == QO_JOINMETHOD_MERGE_JOIN)
4224  {
4225  return false;
4226  }
4227 
4228  assert (plan->info->env && plan->info->env->pt_tree);
4229  if (!PT_IS_SELECT (plan->info->env->pt_tree))
4230  {
4231  return false;
4232  }
4233  if (((QO_ENV_PT_TREE (plan->info->env))->info.query.q.select.hint & PT_HINT_NO_MULTI_RANGE_OPT) != 0)
4234  {
4235  /* NO_MULTI_RANGE_OPT was hinted */
4236  return false;
4237  }
4238 
4239  /* first must find an index scan subplan that can apply multi range optimization */
4240  error = qo_find_subplan_using_multi_range_opt (plan, &sort_plan, NULL);
4241  if (error != NO_ERROR || sort_plan == NULL)
4242  {
4243  /* error finding subplan or no subplan was found */
4244  return false;
4245  }
4246 
4247  /* check all join conditions */
4248  error = qo_check_subplans_for_multi_range_opt (NULL, plan, sort_plan, &can_optimize, NULL);
4249  if (error != NO_ERROR || !can_optimize)
4250  {
4251  return false;
4252  }
4253 
4254  /* all conditions are met, multi range optimization may be used */
4255  return true;
4256 }
4257 
4258 /*
4259  * qo_check_subplans_for_multi_range_opt () - verify that join conditions do
4260  * not invalidate the multi range
4261  * optimization
4262  *
4263  * return : error code
4264  * parent (in) : join node that contains sub-plans
4265  * plan (in) : current plan to verify
4266  * sortplan (in) : the plan that refers to the order by table
4267  * is_valid (out) : is_valid is true if optimization can be applied
4268  * otherwise it is set on false
4269  * sort_col_idx_pos (in) : position in index for the first sort column
4270  * seen (in/out) : flag to remember that the sort plan was passed.
4271  * all scan plans that are met after this flag was set
4272  * are potential suspect scans ("to the right" of the
4273  * order by table
4274  *
4275  * NOTE: 1. *seen should be false when the function is called for root plan or
4276  * it should be left as NULL.
4277  * 2. checks all sub-plans at the right of sort plan in the join chain.
4278  * the sub-plans in the left can invalidate the optimization only if
4279  * the join term acts as data filter, which was already checked at a
4280  * previous step (see qo_check_terms_for_multiple_range_opt).
4281  * Check the comment on qo_check_join_for_multi_range_opt for more
4282  * details.
4283  */
4284 static int
4285 qo_check_subplans_for_multi_range_opt (QO_PLAN * parent, QO_PLAN * plan, QO_PLAN * sortplan, bool * is_valid,
4286  bool * seen)
4287 {
4288  int error = NO_ERROR;
4289  bool dummy = false;
4290 
4291  if (seen == NULL)
4292  {
4293  seen = &dummy;
4294  }
4295 
4296  if (plan->plan_type == QO_PLANTYPE_SCAN)
4297  {
4298  if (*seen)
4299  {
4300  if (parent == NULL)
4301  {
4302  *is_valid = false;
4303  goto exit;
4304  }
4305  *is_valid = qo_check_subplan_join_cond_for_multi_range_opt (parent, plan, sortplan);
4306  if (*is_valid == true)
4307  {
4308  *is_valid = qo_check_parent_eq_class_for_multi_range_opt (parent, plan, sortplan);
4309  }
4310  return NO_ERROR;
4311  }
4312  if (plan == sortplan)
4313  {
4314  *seen = true;
4315  }
4316  *is_valid = true;
4317  return NO_ERROR;
4318  }
4319  else if (plan->plan_type == QO_PLANTYPE_JOIN)
4320  {
4321  if (qo_plan_multi_range_opt (plan))
4322  {
4323  /* plan->multi_range_opt_use == PLAN_MULTI_RANGE_OPT_USE */
4324  /* already checked and the plan can use multi range opt */
4325  *is_valid = true;
4326  /* sort plan is somewhere in the subtree of this plan */
4327  *seen = true;
4328  return NO_ERROR;
4329  }
4331  {
4332  /* already checked and the plan cannot use multi range opt */
4333  *is_valid = false;
4334  return NO_ERROR;
4335  }
4336  /* this must be the first time current plan is checked for multi range optimization */
4337  error = qo_check_subplans_for_multi_range_opt (plan, plan->plan_un.join.outer, sortplan, is_valid, seen);
4338  if (error != NO_ERROR || !*is_valid)
4339  {
4340  /* mark the plan for future checks */
4342  return error;
4343  }
4344  error = qo_check_subplans_for_multi_range_opt (plan, plan->plan_un.join.inner, sortplan, is_valid, seen);
4345  if (error != NO_ERROR || !*is_valid)
4346  {
4347  /* mark the plan for future checks */
4349  return error;
4350  }
4351  return NO_ERROR;
4352  }
4353 
4354  /* a case we have not foreseen? Be conservative. */
4355  *is_valid = false;
4356 
4357 exit:
4358  return error;
4359 }
4360 
4361 /*
4362  * qo_check_subplan_join_cond_for_multi_range_opt () - validate a given
4363  * subplan for multi range
4364  * key-limit optimization.
4365  *
4366  * return : true if valid, false otherwise
4367  * parent (in) : join plan that contains current subplan
4368  * subplan (in) : the subplan that is verified at current step
4369  * sort_plan (in) : the subplan that refers to the table that has the order by
4370  * columns
4371  * is_outer (in) : The position of sort plan relative to sub-plan in the join
4372  * chain. If true, sort plan must be position to the left in
4373  * the chain (is "outer-more"), otherwise it must be to the
4374  * right ("inner-more").
4375  *
4376  * NOTE: The function checks the join conditions between sub-plan and
4377  * sort-plan. It is supposed that sort-plan is outer and sub-plan is
4378  * inner in this join.
4379  */
4380 static bool
4382 {
4383  QO_ENV *env = NULL;
4384  QO_NODE *node_of_sort_table = NULL, *node_of_subplan = NULL;
4385  BITSET_ITERATOR iter_t, iter_n, iter_segs;
4386  QO_TERM *jt = NULL;
4387  QO_NODE *jn = NULL;
4388  int t, n, seg_idx, k, k_seg_idx;
4389  QO_NODE *seg_node = NULL;
4390  bool is_jterm_relevant;
4391 
4392  assert (parent != NULL && parent->plan_type == QO_PLANTYPE_JOIN);
4393  assert (sort_plan != NULL && sort_plan->plan_un.scan.node != NULL && sort_plan->plan_un.scan.node->info != NULL);
4394  if (sort_plan->plan_un.scan.node->info->n <= 0 || sort_plan->plan_un.scan.index == NULL
4395  || sort_plan->plan_un.scan.index->n <= 0)
4396  {
4397  return false;
4398  }
4399 
4400  env = sort_plan->info->env;
4401  node_of_sort_table = sort_plan->plan_un.scan.node;
4402  node_of_subplan = subplan->plan_un.scan.node;
4403 
4404  assert (node_of_sort_table != NULL && node_of_subplan != NULL);
4405 
4406  /*
4407  * Scan all the parent's join terms: jt.
4408  * If jt is a valid join-term (is a join between sub-plan and sort plan),
4409  * the segment that belong to the sort plan must be positioned in index
4410  * before the first sort column and it must not be in a range term.
4411  */
4412  for (t = bitset_iterate (&(parent->plan_un.join.join_terms), &iter_t); t != -1; t = bitset_next_member (&iter_t))
4413  {
4414  jt = QO_ENV_TERM (env, t);
4415  assert (jt != NULL);
4416 
4417  is_jterm_relevant = false;
4418  for (n = bitset_iterate (&(jt->nodes), &iter_n); n != -1; n = bitset_next_member (&iter_n))
4419  {
4420  jn = QO_ENV_NODE (env, n);
4421 
4422  assert (jn != NULL);
4423 
4424  if (jn == node_of_subplan)
4425  {
4426  is_jterm_relevant = true;
4427  break;
4428  }
4429  }
4430 
4431  if (!is_jterm_relevant)
4432  {
4433  continue;
4434  }
4435 
4436  for (n = bitset_iterate (&(jt->nodes), &iter_n); n != -1; n = bitset_next_member (&iter_n))
4437  {
4438  jn = QO_ENV_NODE (env, n);
4439 
4440  assert (jn != NULL);
4441 
4442  if (jn != node_of_sort_table)
4443  {
4444  continue;
4445  }
4446 
4447  /* there is a join term t that references the nodes used in sub-plan and sort plan. */
4448  for (seg_idx = bitset_iterate (&(jt->segments), &iter_segs); seg_idx != -1;
4449  seg_idx = bitset_next_member (&iter_segs))
4450  {
4451  bool found = false;
4452  seg_node = QO_SEG_HEAD (QO_ENV_SEG (env, seg_idx));
4453  if (seg_node != node_of_sort_table)
4454  {
4455  continue;
4456  }
4457  /* seg node refer to the order by table */
4458  for (k = 0; k < sort_plan->plan_un.scan.index->head->first_sort_column; k++)
4459  {
4460  k_seg_idx = sort_plan->plan_un.scan.index->head->seg_idxs[k];
4461  if (k_seg_idx == seg_idx)
4462  {
4463  /* seg_idx was found before the first sort column */
4464  if (qo_check_seg_belongs_to_range_term (sort_plan, env, seg_idx))
4465  {
4466  return false;
4467  }
4468  found = true;
4469  break;
4470  }
4471  }
4472  if (!found)
4473  {
4474  /* seg_idx was not found before the first sort column */
4475  return false;
4476  }
4477  }
4478  }
4479  }
4480 
4481  return true;
4482 }
4483 
4484 /*
4485  * qo_check_parent_eq_class_for_multi_range_opt () - validate a given subplan
4486  * for multi range key-limit
4487  * optimization.
4488  *
4489  * return : true if valid, false otherwise
4490  * parent (in) : join plan that contains current subplan
4491  * subplan (in) : the subplan that is verified at current step
4492  * sort_plan (in) : the subplan that refers to the table that has the order by
4493  * columns
4494  *
4495  * NOTE: Same as qo_check_subplan_join_cond_for_multi_range_opt, except that
4496  * it checks the EQCLASSES.
4497  */
4498 static bool
4500 {
4501  QO_ENV *env = NULL;
4502  QO_NODE *node_of_sort_table = NULL, *node_of_crt_table = NULL, *node = NULL;
4503  int eq_idx, t, k, seg_idx, k_seg_idx;
4504  QO_EQCLASS *eq = NULL;
4505  bool is_eqclass_relevant = false;
4506  BITSET_ITERATOR iter_t;
4507 
4508  assert (parent != NULL && parent->plan_type == QO_PLANTYPE_JOIN);
4509  assert (subplan != NULL && subplan->plan_type == QO_PLANTYPE_SCAN);
4510  assert (sort_plan != NULL && sort_plan->plan_un.scan.node != NULL && sort_plan->plan_un.scan.node->info != NULL);
4511  if (sort_plan->plan_un.scan.node->info->n <= 0 || sort_plan->plan_un.scan.index == NULL
4512  || sort_plan->plan_un.scan.index->n <= 0)
4513  {
4514  return false;
4515  }
4516 
4517  env = parent->info->env;
4518  node_of_sort_table = sort_plan->plan_un.scan.node;
4519  node_of_crt_table = subplan->plan_un.scan.node;
4520 
4521  for (eq_idx = 0; eq_idx < env->neqclasses; eq_idx++)
4522  {
4523  eq = QO_ENV_EQCLASS (env, eq_idx);
4524  is_eqclass_relevant = false;
4525 
4526  for (t = bitset_iterate (&QO_EQCLASS_SEGS (eq), &iter_t); t != -1; t = bitset_next_member (&iter_t))
4527  {
4528  node = QO_SEG_HEAD (QO_ENV_SEG (env, t));
4529  if (node == node_of_crt_table)
4530  {
4531  is_eqclass_relevant = true;
4532  break;
4533  }
4534  }
4535 
4536  if (!is_eqclass_relevant)
4537  {
4538  continue;
4539  }
4540 
4541  /* here: we have an equivalence class that has a segment belonging to our current class. Must see if it also has
4542  * segments belonging to the sort table: iterate again over it. */
4543  for (t = bitset_iterate (&QO_EQCLASS_SEGS (eq), &iter_t); t != -1; t = bitset_next_member (&iter_t))
4544  {
4545  bool found = false;
4546  node = QO_SEG_HEAD (QO_ENV_SEG (env, t));
4547  if (node != node_of_sort_table)
4548  {
4549  continue;
4550  }
4551 
4552  seg_idx = t;
4553  /* try to find the segment in the index that is used when scanning the order by table - take that info from
4554  * the subplan (sortplan) rather than from the node info, because the node info lists all the indexes, not
4555  * only those that are used at this particular scan. */
4556  for (k = 0; k < sort_plan->plan_un.scan.index->head->first_sort_column; k++)
4557  {
4558  k_seg_idx = sort_plan->plan_un.scan.index->head->seg_idxs[k];
4559  if (k_seg_idx == seg_idx)
4560  {
4561  /* we found the segment before the first sort column */
4562  if (qo_check_seg_belongs_to_range_term (sort_plan, env, seg_idx))
4563  {
4564  return false;
4565  }
4566  found = true;
4567  break;
4568  }
4569  }
4570  if (!found)
4571  {
4572  /* seg_idx was not found before the first sort column */
4573  return false;
4574  }
4575  }
4576  }
4577 
4578  return true;
4579 }
4580 
4581 /*
4582  * qo_find_subplan_using_multi_range_opt () - finds an index scan plan that
4583  * may use multi range key-limit
4584  * optimization.
4585  *
4586  * return : error code
4587  * plan (in) : current node in plan tree
4588  * result (out) : plan with multi range optimization
4589  * join_idx (out) : the position of the optimized plan in join chain
4590  *
4591  * NOTE : Leave result or join_idx NULL if they are not what you are looking
4592  * for.
4593  */
4594 int
4595 qo_find_subplan_using_multi_range_opt (QO_PLAN * plan, QO_PLAN ** result, int *join_idx)
4596 {
4597  int error = NO_ERROR;
4598 
4599  if (result != NULL)
4600  {
4601  *result = NULL;
4602  }
4603 
4604  if (plan == NULL)
4605  {
4606  return NO_ERROR;
4607  }
4608 
4609  if (plan->plan_type == QO_PLANTYPE_JOIN && plan->plan_un.join.join_type == JOIN_INNER)
4610  {
4611  if (join_idx != NULL)
4612  {
4613  *join_idx++;
4614  }
4615  error = qo_find_subplan_using_multi_range_opt (plan->plan_un.join.outer, result, join_idx);
4616  if (error != NO_ERROR || (result != NULL && *result != NULL))
4617  {
4618  return NO_ERROR;
4619  }
4620  if (join_idx != NULL)
4621  {
4622  *join_idx++;
4623  }
4624  return qo_find_subplan_using_multi_range_opt (plan->plan_un.join.inner, result, join_idx);
4625  }
4626  else if (qo_is_interesting_order_scan (plan))
4627  {
4628  if (qo_plan_multi_range_opt (plan))
4629  {
4630  if (result != NULL)
4631  {
4632  *result = plan;
4633  }
4634  }
4635  return NO_ERROR;
4636  }
4637  return NO_ERROR;
4638 }
4639 
4640 /*
4641  * make_sort_limit_proc () - make sort limit xasl node
4642  * return : xasl proc on success, NULL on error
4643  * env (in) : optimizer environment
4644  * plan (in) : query plan
4645  * namelist (in) : list of segments referenced by nodes in the plan
4646  * xasl (in) : top xasl
4647  */
4648 static XASL_NODE *
4649 make_sort_limit_proc (QO_ENV * env, QO_PLAN * plan, PT_NODE * namelist, XASL_NODE * xasl)
4650 {
4652  XASL_NODE *listfile = NULL;
4653  PT_NODE *new_order_by = NULL, *node_list = NULL;
4654  PT_NODE *order_by, *statement;
4655 
4656  parser = QO_ENV_PARSER (env);
4657  statement = QO_ENV_PT_TREE (env);
4658  order_by = statement->info.query.order_by;
4659 
4660  if (xasl->ordbynum_val == NULL)
4661  {
4662  /* If orderbynum_val is NULL, we're probably somewhere in a subplan and orderbynum_val is set for the upper XASL
4663  * level. Try to find the ORDERBY_NUM node and use the node->etc pointer which is set to the orderby_num val */
4664  if (statement->info.query.orderby_for == NULL)
4665  {
4666  /* we should not create a sort_limit proc without an orderby_for predicate. */
4667  assert_release (false);
4668  listfile = NULL;
4669  goto cleanup;
4670  }
4671 
4673  NULL);
4674  if (xasl->ordbynum_val == NULL)
4675  {
4676  assert_release (false);
4677  listfile = NULL;
4678  goto cleanup;
4679  }
4680  }
4681  /* make o copy of the namelist to extend it with expressions from the ORDER BY clause. The extended list will be used
4682  * to generate the internal listfile scan but will not be used for the actual XASL node. */
4683  node_list = parser_copy_tree_list (parser, namelist);
4684  if (node_list == NULL)
4685  {
4686  listfile = NULL;
4687  goto cleanup;
4688  }
4689 
4690  /* set new SORT_SPEC list based on the position of items in the node_list */
4691  new_order_by = pt_set_orderby_for_sort_limit_plan (parser, statement, node_list);
4692  if (new_order_by == NULL)
4693  {
4694  listfile = NULL;
4695  goto cleanup;
4696  }
4697 
4698  statement->info.query.order_by = new_order_by;
4699 
4700  listfile = make_buildlist_proc (env, node_list);
4701  listfile = gen_outer (env, plan->plan_un.sort.subplan, &EMPTY_SET, NULL, NULL, listfile);
4702  listfile = add_sort_spec (env, listfile, plan, xasl->ordbynum_val, false);
4703 
4704 cleanup:
4705  if (node_list != NULL)
4706  {
4707  parser_free_tree (parser, node_list);
4708  }
4709  if (new_order_by != NULL)
4710  {
4711  parser_free_tree (parser, new_order_by);
4712  }
4713 
4714  statement->info.query.order_by = order_by;
4715 
4716  return listfile;
4717 }
4718 
4719 /*
4720  * qo_get_orderby_num_upper_bound_node () - get the node which represents the
4721  * upper bound predicate of an
4722  * orderby_num predicate
4723  * return : node or NULL
4724  * parser (in) : parser context
4725  * orderby_for (in) : orderby_for predicate list
4726  * is_new_node (in/out) : if a new node was created, free_node is set to true
4727  * and caller must free the returned node
4728  *
4729  * Note: A NULL return indicates that this function either found no upper
4730  * bound or that it found several predicates which specify an upper bound
4731  * for the ORDERBY_NUM predicate.
4732  */
4733 static PT_NODE *
4735 {
4736  PT_NODE *left = NULL, *right = NULL;
4737  PT_NODE *save_next;
4738  PT_OP_TYPE op;
4739  bool free_left = false, free_right = false;
4740  *is_new_node = false;
4741 
4742  if (orderby_for == NULL || !PT_IS_EXPR_NODE (orderby_for) || orderby_for->or_next != NULL)
4743  {
4744  /* orderby_for must be an expression containing only AND predicates */
4745  assert (false);
4746  return NULL;
4747  }
4748 
4749  /* Ranges for ORDERBY_NUM predicates have already been merged (see qo_reduce_order_by). If the code below finds more
4750  * than one upper bound, this is an error. */
4751  if (orderby_for->next != NULL)
4752  {
4753  save_next = orderby_for->next;
4754  orderby_for->next = NULL;
4755 
4756  right = save_next;
4757  left = orderby_for;
4758 
4759  left = qo_get_orderby_num_upper_bound_node (parser, left, &free_left);
4760  right = qo_get_orderby_num_upper_bound_node (parser, right, &free_right);
4761 
4762  orderby_for->next = save_next;
4763 
4764  if (left != NULL)
4765  {
4766  if (right != NULL)
4767  {
4768  /* There should be exactly one upper bound */
4769  if (free_left)
4770  {
4771  parser_free_tree (parser, left);
4772  }
4773  if (free_right)
4774  {
4775  parser_free_tree (parser, right);
4776  }
4777  return NULL;
4778  }
4779  *is_new_node = free_left;
4780  return left;
4781  }
4782  else
4783  {
4784  /* If right is NULL, the orderby_num pred is invalid and we messed something up somewhere. If it is not NULL,
4785  * this is the node we are looking for. */
4786  *is_new_node = free_right;
4787  return right;
4788  }
4789  }
4790 
4791  op = orderby_for->info.expr.op;
4792  /* look for orderby_num < argument */
4793  if (PT_IS_EXPR_NODE (orderby_for->info.expr.arg1) && orderby_for->info.expr.arg1->info.expr.op == PT_ORDERBY_NUM)
4794  {
4795  left = orderby_for->info.expr.arg1;
4796  right = orderby_for->info.expr.arg2;
4797  }
4798  else
4799  {
4800  left = orderby_for->info.expr.arg2;
4801  right = orderby_for->info.expr.arg1;
4802  if (!PT_IS_EXPR_NODE (left) || left->info.expr.op != PT_ORDERBY_NUM)
4803  {
4804  /* could not find ORDERBY_NUM argument */
4805  return NULL;
4806  }
4807 
4808  /* Verify operator. If LE, LT then reverse it. */
4809  switch (op)
4810  {
4811  case PT_LE:
4812  op = PT_GE;
4813  break;
4814  case PT_LT:
4815  op = PT_GT;
4816  break;
4817  case PT_GE:
4818  op = PT_LE;
4819  break;
4820  case PT_GT:
4821  op = PT_LT;
4822  break;
4823  default:
4824  break;
4825  }
4826  }
4827 
4828  if (op == PT_LE || op == PT_LT)
4829  {
4830  return orderby_for;
4831  }
4832 
4833  if (op == PT_BETWEEN)
4834  {
4835  /* construct new predicate for ORDERBY_NUM from BETWEEN expr. */
4836  PT_NODE *new_node;
4837 
4838  if (!PT_IS_EXPR_NODE (right) || right->info.expr.op != PT_BETWEEN_AND)
4839  {
4840  return NULL;
4841  }
4842 
4843  new_node = parser_new_node (parser, PT_EXPR);
4844  if (new_node == NULL)
4845  {
4846  return NULL;
4847  }
4848  new_node->info.expr.op = PT_LE;
4849 
4850  new_node->info.expr.arg1 = parser_copy_tree (parser, left);
4851  if (new_node->info.expr.arg1 == NULL)
4852  {
4853  parser_free_tree (parser, new_node);
4854  return NULL;
4855  }
4856 
4857  new_node->info.expr.arg2 = parser_copy_tree (parser, right->info.expr.arg2);
4858  if (new_node->info.expr.arg2 == NULL)
4859  {
4860  parser_free_tree (parser, new_node);
4861  return NULL;
4862  }
4863 
4864  *is_new_node = true;
4865  return new_node;
4866  }
4867 
4868  /* Any other comparison operator is unusable */
4869  return NULL;
4870 }
4871 
4872 /*
4873  * qo_get_multi_col_range_segs () -
4874  * return:
4875  * env(in): The optimizer environment
4876  * plan(in): Query plan
4877  * qo_index_infop(in):
4878  * multi_col_segs(out): (a,b) in ... a,b's segment number bit
4879  * multi_col_range_segs(out): range segments in multiple column term
4880  *
4881  * Note: return multiple column term's number
4882  * output are multi column term's segments and range key filter segments and index col segments
4883  */
4884 static int
4886  BITSET * multi_col_segs, BITSET * multi_col_range_segs, BITSET * index_segs)
4887 {
4888  BITSET_ITERATOR iter;
4889  QO_TERM *termp = NULL;
4890  int multi_term = -1;
4891 
4892  /* find term having multiple columns ex) (col1,col2) in ... */
4893  for (multi_term = bitset_iterate (&(plan->plan_un.scan.terms), &iter); multi_term != -1;
4894  multi_term = bitset_next_member (&iter))
4895  {
4896  termp = QO_ENV_TERM (env, multi_term);
4898  {
4899  bitset_assign (multi_col_segs, &(QO_TERM_SEGS (termp)));
4900  break;
4901  }
4902  }
4903 
4904  if (index_entryp)
4905  {
4906  bitset_assign (index_segs, &(index_entryp->index_segs));
4907  }
4908  bitset_assign (multi_col_range_segs, &(plan->plan_un.scan.multi_col_range_segs));
4909 
4910  return multi_term;
4911 }
double fixed_cpu_cost
bool qo_check_join_for_multi_range_opt(QO_PLAN *plan)
QPROC_SINGLE_FETCH single_fetch
Definition: query_list.h:339
PT_NODE * pt_get_numbering_node_etc(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
int nsubqueries
Definition: query_graph.h:896
pred_expr * lhs
PT_NODE ** qo_xasl_get_terms(QO_XASL_INDEX_INFO *info)
#define pt_is_expr_node(n)
Definition: parse_tree.h:261
bool qo_is_iscan(QO_PLAN *plan)
PT_NODE * order_by
Definition: parse_tree.h:2769
static XASL_NODE * add_scan_proc(QO_ENV *env, XASL_NODE *xasl, XASL_NODE *scan)
OUTPTR_LIST * outptr_list
Definition: xasl.h:968
bool qo_is_index_loose_scan(QO_PLAN *plan)
ACCESS_SPEC_TYPE * pt_to_spec_list(PARSER_CONTEXT *parser, PT_NODE *spec, PT_NODE *where_key_part, PT_NODE *where_part, QO_PLAN *plan, QO_XASL_INDEX_INFO *index_part, PT_NODE *src_derived_tbl, PT_NODE *where_hash_part)
PT_NODE * next
Definition: parse_tree.h:3447
QO_INFO * info
SORT_LIST * orderby_list
Definition: xasl.h:957
#define QO_TERM_SUBQUERIES(t)
Definition: query_graph.h:726
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: parse_tree.h:2829
#define ER_FAILED_ASSERTION
Definition: error_code.h:695
static XASL_NODE * make_fetch_proc(QO_ENV *env, QO_PLAN *plan)
#define NO_ERROR
Definition: error_code.h:46
bool is_iss_candidate
Definition: query_graph.h:155
#define QO_TERM_MULTI_COLL_PRED
Definition: query_graph.h:745
int neqclasses
Definition: query_graph.h:894
struct qo_plan::@100::@103 sort
PT_NODE * pt_set_orderby_for_sort_limit_plan(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *nodes_list)
XASL_NODE * fptr_list
Definition: xasl.h:984
UINTPTR id
Definition: parse_tree.h:2144
struct qo_summary * qo_summary
Definition: parse_tree.h:2703
#define XASL_CLEAR_FLAG(x, f)
Definition: xasl.h:497
XASL_NODE * ptqo_to_list_scan_proc(PARSER_CONTEXT *parser, XASL_NODE *xasl, PROC_TYPE proc_type, XASL_NODE *listfile, PT_NODE *namelist, PT_NODE *pred, int *poslist)
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
BITSET nodes
Definition: query_graph.h:608
SORT_LIST * ptqo_single_orderby(PARSER_CONTEXT *parser)
bool cover_segments
Definition: query_graph.h:140
#define BITSET_CLEAR(s)
Definition: query_bitset.h:68
static void regu_ptr_list_free(REGU_PTR_LIST list)
static PT_NODE * qo_get_orderby_num_upper_bound_node(PARSER_CONTEXT *parser, PT_NODE *orderby_for, bool *is_new_node)
void qo_get_optimization_param(void *, QO_PARAM,...)
Definition: query_graph.c:269
#define QO_ASSERT(env, cond)
Definition: optimizer.h:52
void * parser_alloc(const PARSER_CONTEXT *parser, const int length)
Definition: parse_tree.c:951
REGU_VARIABLE * rightptr
Definition: regu_var.hpp:129
bool qo_check_iscan_for_multi_range_opt(QO_PLAN *plan)
#define QO_TERM_IDX(t)
Definition: query_graph.h:723
PRED_EXPR * if_pred
Definition: xasl.h:978
#define QO_TERM_IS_FLAGED(t, f)
Definition: query_graph.h:749
Definition: query_graph.h:209
bool qo_is_iscan_from_orderby(QO_PLAN *plan)
static XASL_NODE * add_uncorrelated(QO_ENV *env, XASL_NODE *xasl, XASL_NODE *sub)
int bitset_intersects(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:295
PT_MISC_TYPE
Definition: parse_tree.h:983
void qo_expr_segs(QO_ENV *env, PT_NODE *pt_expr, BITSET *result)
Definition: query_graph.c:2734
PRED_EXPR * pt_to_pred_expr_with_arg(PARSER_CONTEXT *parser, PT_NODE *node_list, int *argp)
int bitset_iterate(const BITSET *s, BITSET_ITERATOR *si)
Definition: query_bitset.c:464
#define QO_ENV_PARSER(env)
Definition: query_graph.h:964
#define ER_FAILED
Definition: error_code.h:47
TYPE_EVAL_TERM et_type
#define IS_OUTER_JOIN_TYPE(t)
Definition: query_list.h:42
int nsegs
Definition: query_graph.h:119
bool multi_range_opt_candidate
Definition: query_graph.h:954
struct tp_domain * setdomain
Definition: object_domain.h:82
union xasl_node::@155 proc
PT_SPEC_INFO spec
Definition: parse_tree.h:3346
#define QO_SEG_HEAD(seg)
Definition: query_graph.h:510
PT_NODE * pt_get_select_list(PARSER_CONTEXT *parser, PT_NODE *query)
Definition: query_result.c:404
bool qo_is_interesting_order_scan(QO_PLAN *plan)
SORT_LIST * pt_to_orderby(PARSER_CONTEXT *parser, PT_NODE *order_list, PT_NODE *root)
static void make_outer_instnum(QO_ENV *env, QO_PLAN *outer, QO_PLAN *plan)
double fixed_io_cost
Definition: optimizer.h:111
REGU_VARIABLE * leftptr
Definition: regu_var.hpp:128
static bool qo_check_seg_belongs_to_range_term(QO_PLAN *subplan, QO_ENV *env, int seg_idx)
QFILE_LIST_MERGE_INFO ls_merge
Definition: xasl.h:363
PT_NODE * node
Definition: query_graph.h:766
int can_use_index
Definition: query_graph.h:663
int bitset_is_empty(const BITSET *s)
Definition: query_bitset.c:318
#define assert_release(e)
Definition: error_manager.h:96
XASL_NODE * pt_skeleton_buildlist_proc(PARSER_CONTEXT *parser, PT_NODE *namelist)
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
static PT_NODE * make_if_pred_from_plan(QO_ENV *env, QO_PLAN *plan)
void pt_set_isleaf_node_etc(PARSER_CONTEXT *parser, PT_NODE *node_list, DB_VALUE **isleaf_valp)
void bitset_difference(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:224
XASL_NODE * inner_xasl
Definition: xasl.h:359
#define QO_TERM_PT_EXPR(t)
Definition: query_graph.h:724
REGU_VARIABLE * orderby_limit
Definition: xasl.h:960
PT_NODE * pt_tree
Definition: query_graph.h:863
#define QO_ENV_SUBQUERY(env, n)
Definition: query_graph.h:962
static int is_normal_access_term(QO_TERM *)
union pt_query_info::@124 q
char * pt_alloc_packing_buf(int size)
PT_NODE * pt_right_part(const PT_NODE *expr)
static int is_totally_after_join_term(QO_TERM *)
int first_sort_column
Definition: query_graph.h:143
static REGU_PTR_LIST regu_ptr_list_create()
int projected_size
Definition: xasl.h:1034
SM_FUNCTION_INFO * func_index_info
Definition: class_object.h:541
void pt_set_level_node_etc(PARSER_CONTEXT *parser, PT_NODE *node_list, DB_VALUE **level_valp)
MERGELIST_PROC_NODE mergelist
Definition: xasl.h:1021
XASL_NODE * ptqo_to_scan_proc(PARSER_CONTEXT *parser, QO_PLAN *plan, XASL_NODE *xasl, PT_NODE *spec, PT_NODE *where_key_part, PT_NODE *where_part, QO_XASL_INDEX_INFO *info, PT_NODE *where_hash_part)
XASL_NODE * aptr_list
Definition: xasl.h:974
SM_CLASS_CONSTRAINT * constraints
Definition: query_graph.h:108
bool qo_is_seq_scan(QO_PLAN *plan)
static XASL_NODE * add_after_join_predicate(QO_ENV *, XASL_NODE *, PT_NODE *)
PROC_TYPE type
Definition: xasl.h:953
REL_OP
#define QO_TERM_MULTI_COLL_CONST
Definition: query_graph.h:746
struct qo_plan::@100::@104 join
static void qo_free_xasl_index_info(QO_ENV *env, QO_XASL_INDEX_INFO *info)
JOIN_TYPE
Definition: query_list.h:32
regu_variable_node * lhs
ACCESS_SPEC_TYPE * inner_spec_list
Definition: xasl.h:360
QO_SUBQUERY * subqueries
Definition: query_graph.h:869
PT_NODE * qo_plan_iscan_sort_list(QO_PLAN *plan)
static XASL_NODE * init_class_scan_proc(QO_ENV *env, XASL_NODE *xasl, QO_PLAN *plan)
static bool qo_get_limit_from_eval_term(PARSER_CONTEXT *parser, PRED_EXPR *pred, REGU_PTR_LIST *lower, REGU_PTR_LIST *upper)
static int qo_check_subplans_for_multi_range_opt(QO_PLAN *parent, QO_PLAN *plan, QO_PLAN *sortplan, bool *is_valid, bool *seen)
SORT_ORDER s_order
Definition: query_list.h:417
static XASL_NODE * add_access_spec(QO_ENV *, XASL_NODE *, QO_PLAN *)
static bool qo_check_parent_eq_class_for_multi_range_opt(QO_PLAN *parent, QO_PLAN *subplan, QO_PLAN *sort_plan)
void pt_set_connect_by_operator_node_etc(PARSER_CONTEXT *parser, PT_NODE *node_list, XASL_NODE *xasl)
#define PT_PRED_ARG_ORDBYNUM_CONTINUE
VAL_LIST * val_list
Definition: xasl.h:972
PRED_EXPR * ordbynum_pred
Definition: xasl.h:958
TP_DOMAIN * pt_xasl_node_to_domain(PARSER_CONTEXT *parser, const PT_NODE *node)
static XASL_NODE * check_merge_xasl(QO_ENV *env, XASL_NODE *xasl)
int(* ELIGIBILITY_FN)(QO_TERM *)
int qo_find_subplan_using_multi_range_opt(QO_PLAN *plan, QO_PLAN **result, int *join_idx)
static XASL_NODE * add_if_predicate(QO_ENV *, XASL_NODE *, PT_NODE *)
#define QO_TERM_CLASS(t)
Definition: query_graph.h:716
static int qo_check_terms_for_multiple_range_opt(QO_PLAN *plan, int first_sort_col_idx, bool *can_optimize)
bool qo_is_iscan_from_groupby(QO_PLAN *plan)
PT_NODE * or_next
Definition: parse_tree.h:3448
XASL_NODE * pt_remove_xasl(XASL_NODE *xasl_list, XASL_NODE *remove)
static void mark_access_as_outer_join(PARSER_CONTEXT *parser, XASL_NODE *xasl)
static XASL_NODE * make_buildlist_proc(QO_ENV *env, PT_NODE *namelist)
XASL_NODE * next
Definition: xasl.h:952
regu_variable_node * lower
Definition: optimizer.h:144
bool qo_plan_skip_groupby(QO_PLAN *plan)
TP_DOMAIN * key_type
Definition: query_graph.h:116
#define PT_IS_SELECT(n)
Definition: parse_tree.h:284
TP_DOMAIN * tp_domain_resolve_default(DB_TYPE type)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
ACCESS_SPEC_TYPE * next
Definition: xasl.h:935
static int is_follow_if_term(QO_TERM *)
int bitset_subset(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:263
PT_NODE * arg2
Definition: parse_tree.h:2198
cubxasl::pred_expr * pred
Definition: regu_var.hpp:133
static XASL_NODE * preserve_info(QO_ENV *env, QO_PLAN *plan, XASL_NODE *xasl)
XASL_NODE * outer_xasl
Definition: xasl.h:356
#define CAST_POINTER_TO_NODE(p)
Definition: parse_tree.h:607
static bool qo_validate_regu_var_for_limit(REGU_VARIABLE *var_p)
#define assert(x)
int ordbynum_flag
Definition: xasl.h:961
static bool qo_check_subqueries_for_multi_range_opt(QO_PLAN *plan, int sort_col_idx_pos)
#define QO_TERM_TAIL(t)
Definition: query_graph.h:722
void bitset_delset(BITSET *s)
Definition: query_bitset.c:571
static int path_access_term(QO_TERM *term)
void bitset_assign(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:120
XASL_NODE * dptr_list
Definition: xasl.h:976
PT_POINTER_INFO pointer
Definition: parse_tree.h:3359
PT_MISC_TYPE asc_or_desc
Definition: parse_tree.h:2830
static XASL_NODE * make_sort_limit_proc(QO_ENV *env, QO_PLAN *plan, PT_NODE *namelist, XASL_NODE *xasl)
#define QO_IS_PATH_TERM(t)
Definition: query_graph.h:583
#define QO_SEG_IDX(seg)
Definition: query_graph.h:519
void bitset_union(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:176
struct sort_list * next
Definition: query_list.h:415
comp_eval_term et_comp
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
unsigned int BITSET
Definition: esql_misc.h:94
QO_SEGMENT * index_seg[2]
Definition: query_graph.h:664
static void make_pred_from_plan(QO_ENV *env, QO_PLAN *plan, PT_NODE **key_access_pred, PT_NODE **access_pred, QO_XASL_INDEX_INFO *qo_index_infop, PT_NODE **hash_pred)
union cubxasl::pred_expr::@185 pe
struct qo_plan::@100::@105 follow
BITSET EMPTY_SET
Definition: query_bitset.c:64
#define QO_NODE_IS_CLASS_HIERARCHY(node)
Definition: query_graph.h:411
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
PARSER_CONTEXT * parser
Definition: query_graph.h:856
PT_NODE * parser_copy_tree(PARSER_CONTEXT *parser, const PT_NODE *tree)
#define PT_IS_VALUE_QUERY(n)
Definition: parse_tree.h:476
BITSET nodes
Definition: query_graph.h:773
bool qo_plan_multi_range_opt(QO_PLAN *plan)
bool top_rooted
QO_LIMIT_INFO * qo_get_key_limit_from_instnum(PARSER_CONTEXT *parser, QO_PLAN *plan, xasl_node *xasl)
static bool qo_get_limit_from_instnum_pred(PARSER_CONTEXT *parser, PRED_EXPR *pred, REGU_PTR_LIST *lower, REGU_PTR_LIST *upper)
union qo_plan::@100 plan_un
static bool qo_check_subplan_join_cond_for_multi_range_opt(QO_PLAN *parent, QO_PLAN *subplan, QO_PLAN *sort_plan)
#define TP_DOMAIN_TYPE(dom)
XASL_NODE * pt_to_fetch_proc(PARSER_CONTEXT *parser, PT_NODE *spec, PT_NODE *pred)
static PT_NODE * make_namelist_from_projected_segs(QO_ENV *env, QO_PLAN *plan)
static void cleanup(int signo)
Definition: broker.c:717
#define PT_SET_VALUE_QUERY(n)
Definition: parse_tree.h:479
xasl_node * qo_add_hq_iterations_access_spec(QO_PLAN *plan, xasl_node *xasl)
SP_PARSER_CTX * parser
double variable_io_cost
Definition: optimizer.h:112
PT_NODE * arg1
Definition: parse_tree.h:2197
DB_VALUE * isleaf_val
Definition: xasl.h:991
#define NULL
Definition: freelistheap.h:34
XASL_NODE * pt_append_xasl(XASL_NODE *to, XASL_NODE *from_list)
const char * er_msg(void)
bool use_iscan_descending
int nterms
Definition: query_graph.h:895
if(extra_options)
Definition: dynamic_load.c:958
regu_variable_node * rhs
bool pt_check_ordby_num_for_multi_range_opt(PARSER_CONTEXT *parser, PT_NODE *query, bool *mro_candidate, bool *cannot_eval)
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: query_list.h:416
static int success()
double cardinality
Definition: optimizer.h:113
static XASL_NODE * add_sort_spec(QO_ENV *, XASL_NODE *, QO_PLAN *, DB_VALUE *, bool)
XASL_NODE * pt_gen_simple_merge_plan(PARSER_CONTEXT *parser, PT_NODE *select_node, QO_PLAN *plan, XASL_NODE *xasl)
void bitset_intersect(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:200
double fixed_cpu_cost
Definition: optimizer.h:111
#define QO_SEG_PT_NODE(seg)
Definition: query_graph.h:509
QO_PLAN_ULTI_RANGE_OPT_USE multi_range_opt_use
XASL_NODE * pt_to_instnum_pred(PARSER_CONTEXT *parser, XASL_NODE *xasl, PT_NODE *pred)
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
DB_VALUE * value
Definition: regu_var.hpp:127
static int is_after_join_term(QO_TERM *)
int pt_find_attribute(PARSER_CONTEXT *parser, const PT_NODE *name, const PT_NODE *attributes)
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
bool qo_is_index_iss_scan(QO_PLAN *plan)
static PT_NODE * make_pred_from_bitset(QO_ENV *env, BITSET *predset, ELIGIBILITY_FN safe)
bool qo_is_index_covering_scan(QO_PLAN *plan)
QO_LIMIT_INFO * qo_get_key_limit_from_ordbynum(PARSER_CONTEXT *parser, QO_PLAN *plan, xasl_node *xasl, bool ignore_lower)
PT_QUERY_INFO query
Definition: parse_tree.h:3325
static PT_NODE * make_instnum_pred_from_plan(QO_ENV *env, QO_PLAN *plan)
bool pt_has_aggregate(PARSER_CONTEXT *parser, PT_NODE *node)
#define cmp
Definition: mprec.h:351
bool qo_plan_skip_orderby(QO_PLAN *plan)
static int is_normal_if_term(QO_TERM *)
BITSET terms
Definition: query_graph.h:782
int bitset_next_member(BITSET_ITERATOR *si)
Definition: query_bitset.c:478
PT_NODE * pt_make_integer_value(PARSER_CONTEXT *parser, const int value_int)
static REGU_PTR_LIST regu_ptr_list_add_regu(REGU_VARIABLE *var_p, REGU_PTR_LIST list)
PRED_EXPR * after_join_pred
Definition: xasl.h:977
PT_NODE * parser_append_node(PT_NODE *node, PT_NODE *list)
static XASL_NODE * gen_outer(QO_ENV *, QO_PLAN *, BITSET *, XASL_NODE *, XASL_NODE *, XASL_NODE *)
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
static void error(const char *msg)
Definition: gencat.c:331
#define QO_ENTRY_MULTI_COL(entry)
Definition: query_graph.h:187
BITSET index_segs
Definition: query_graph.h:181
void parser_free_node(const PARSER_CONTEXT *parser, PT_NODE *node)
Definition: parse_tree.c:869
#define XASL_SKIP_ORDERBY_LIST
Definition: xasl.h:478
VAL_LIST * pt_to_val_list(PARSER_CONTEXT *parser, UINTPTR id)
BITSET subqueries
struct regu_ptr_list_node * REGU_PTR_LIST
Definition: regu_var.hpp:234
double cardinality
Definition: xasl.h:1030
PT_SORT_SPEC_INFO sort_spec
Definition: parse_tree.h:3343
#define ARG_FILE_LINE
Definition: error_manager.h:44
bool qo_is_prefix_index(QO_INDEX_ENTRY *ent)
Definition: query_graph.c:9203
regu_variable_node * upper
Definition: optimizer.h:145
struct qo_plan::@100::@102 scan
#define QO_TERM_SELECTIVITY(t)
Definition: query_graph.h:719
bool pt_name_equal(PARSER_CONTEXT *parser, const PT_NODE *name1, const PT_NODE *name2)
VAL_LIST * outer_val_list
Definition: xasl.h:358
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
PT_NODE * iscan_sort_list
#define QO_TERM_NON_IDX_SARG_COLL
Definition: query_graph.h:744
void pt_set_dptr(PARSER_CONTEXT *parser, PT_NODE *node, XASL_NODE *xasl, UINTPTR id)
double variable_cpu_cost
DB_VALUE * level_val
Definition: xasl.h:988
static int qo_check_plan_index_for_multi_range_opt(PT_NODE *orderby_nodes, PT_NODE *orderby_sort_list, QO_PLAN *plan, bool *is_valid, int *first_col_idx_pos, bool *reverse)
xasl_node * xasl
Definition: optimizer.h:114
DB_VALUE * ordbynum_val
Definition: xasl.h:959
#define QO_IS_FAKE_TERM(t)
Definition: query_graph.h:585
XASL_NODE * scan_ptr
Definition: xasl.h:985
#define free_and_init(ptr)
Definition: memory_alloc.h:147
ACCESS_SPEC_TYPE * spec_list
Definition: xasl.h:970
#define PT_IS_EXPR_NODE(n)
Definition: parse_tree.h:305
#define BITSET_MEMBER(s, x)
Definition: query_bitset.h:70
REGU_VARIABLE * pt_make_regu_arith(const REGU_VARIABLE *arg1, const REGU_VARIABLE *arg2, const REGU_VARIABLE *arg3, const OPERATOR_TYPE op, const TP_DOMAIN *domain)
PT_NODE * pt_point(PARSER_CONTEXT *parser, const PT_NODE *in_tree)
PT_OP_TYPE
Definition: parse_tree.h:1320
BITSET sarged_terms
PT_NODE * connect_by
Definition: parse_tree.h:2689
#define MATCH_ALL
PRED_EXPR * pt_to_pred_expr(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE ** term_exprs
Definition: query_graph.h:981
class regu_variable_node REGU_VARIABLE
Definition: regu_var.hpp:64
static XASL_NODE * add_subqueries(QO_ENV *env, XASL_NODE *xasl, BITSET *)
#define QO_TERM_RANK(t)
Definition: query_graph.h:720
int * seg_idxs
Definition: query_graph.h:122
#define QO_ENV_NODE(env, n)
Definition: query_graph.h:958
#define QFILE_INNER_LIST
Definition: query_list.h:492
#define QO_ENV_EQCLASS(env, n)
Definition: query_graph.h:959
#define QO_ENV_TERM(env, n)
Definition: query_graph.h:960
#define QO_ENV_SEG(env, n)
Definition: query_graph.h:957
int i
Definition: dynamic_load.c:954
struct qo_node_index_entry * ni_entry
Definition: query_graph.h:987
static int bitset_has_path(QO_ENV *env, BITSET *predset)
void pt_set_iscycle_node_etc(PARSER_CONTEXT *parser, PT_NODE *node_list, DB_VALUE **iscycle_valp)
REGU_VARIABLE * var_p
Definition: regu_var.hpp:238
PT_NODE * list
Definition: parse_tree.h:2685
PT_OP_TYPE op
Definition: parse_tree.h:2200
struct tp_domain * next
Definition: object_domain.h:74
PRED_EXPR * instnum_pred
Definition: xasl.h:979
#define QO_TERM_SEGS(t)
Definition: query_graph.h:718
static QO_XASL_INDEX_INFO * qo_get_xasl_index_info(QO_ENV *env, QO_PLAN *plan)
void bitset_init(BITSET *s, QO_ENV *env)
Definition: query_bitset.c:557
#define PT_SPEC_SPECIAL_INDEX_SCAN(spec_)
Definition: parse_tree.h:656
TYPE_PRED_EXPR type
PT_NODE * orderby_for
Definition: parse_tree.h:2770
static XASL_NODE * gen_inner(QO_ENV *, QO_PLAN *, BITSET *, BITSET *, XASL_NODE *, XASL_NODE *)
#define pt_is_function(n)
Definition: parse_tree.h:262
int bitset_cardinality(const BITSET *s)
Definition: query_bitset.c:393
static XASL_NODE * add_fetch_proc(QO_ENV *env, XASL_NODE *xasl, XASL_NODE *proc)
bool qo_is_index_mro_scan(QO_PLAN *plan)
void pt_set_qprior_node_etc(PARSER_CONTEXT *parser, PT_NODE *node_list, XASL_NODE *xasl)
#define XASL_ORDBYNUM_FLAG_SCAN_CONTINUE
Definition: xasl.h:456
REGU_VARIABLE * thirdptr
Definition: regu_var.hpp:130
#define QFILE_OUTER_LIST
Definition: query_list.h:491
int need_copy_multi_range_term
Definition: query_graph.h:991
static XASL_NODE * init_list_scan_proc(QO_ENV *env, XASL_NODE *xasl, XASL_NODE *list, PT_NODE *namelist, BITSET *predset, int *poslist)
bool qo_is_filter_index(QO_INDEX_ENTRY *ent)
Definition: query_graph.c:9228
#define QO_ENV_PT_TREE(env)
Definition: query_graph.h:965
static int is_always_true(QO_TERM *)
double variable_io_cost
#define QO_NODE_ENTITY_SPEC(node)
Definition: query_graph.h:381
union cubxasl::eval_term::@184 et
int bitset_first_member(const BITSET *s)
Definition: query_bitset.c:514
PT_NODE * pt_left_part(const PT_NODE *expr)
#define QO_NODE_SEGS(node)
Definition: query_graph.h:391
QO_ENV * env
QPROC_SINGLE_FETCH single_fetch
Definition: xasl.h:933
void bitset_add(BITSET *dst, int x)
Definition: query_bitset.c:138
pred_expr * rhs
QO_PLANTYPE plan_type
ACCESS_SPEC_TYPE * outer_spec_list
Definition: xasl.h:357
int pt_length_of_list(const PT_NODE *list)
Definition: query_graph.h:99
static int qo_get_multi_col_range_segs(QO_ENV *env, QO_PLAN *plan, QO_INDEX_ENTRY *index_entryp, BITSET *multi_col_segs, BITSET *multi_col_range_segs, BITSET *index_segs)
QO_INDEX_ENTRY * head
Definition: query_graph.h:212
PT_SELECT_INFO select
Definition: parse_tree.h:2781
TP_DOMAIN * domain
Definition: regu_var.hpp:175
VAL_LIST * inner_val_list
Definition: xasl.h:361
#define PLAN_DUMP_ENABLED(level)
Definition: optimizer.h:84
static XASL_NODE * make_scan_proc(QO_ENV *env)
DB_VALUE * iscycle_val
Definition: xasl.h:993
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)
#define PT_IS_NAME_NODE(n)
Definition: parse_tree.h:320
double variable_cpu_cost
Definition: optimizer.h:112
BITSET segments
Definition: query_graph.h:614
PT_NODE * parser_copy_tree_list(PARSER_CONTEXT *parser, PT_NODE *tree)
xasl_node * qo_to_xasl(QO_PLAN *plan, xasl_node *xasl)
const char ** p
Definition: dynamic_load.c:945
REGU_VARIABLE * pt_to_regu_variable(PARSER_CONTEXT *parser, PT_NODE *node, UNBOX unbox)
double fixed_io_cost
XASL_NODE * ptqo_to_merge_list_proc(PARSER_CONTEXT *parser, XASL_NODE *left, XASL_NODE *right, JOIN_TYPE join_type)
#define QO_EQCLASS_SEGS(e)
Definition: query_graph.h:556
static XASL_NODE * make_mergelist_proc(QO_ENV *env, QO_PLAN *plan, XASL_NODE *left, PT_NODE *left_list, BITSET *left_exprs, PT_NODE *left_elist, XASL_NODE *rght, PT_NODE *rght_list, BITSET *rght_exprs, PT_NODE *rght_elist)
int qo_xasl_get_num_terms(QO_XASL_INDEX_INFO *info)
REGU_PTR_LIST next
Definition: regu_var.hpp:237
int * multi_col_segs
Definition: query_graph.h:703
static int path_if_term(QO_TERM *term)
int multi_col_cnt
Definition: query_graph.h:704