CUBRID Engine  latest
query_planner.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  * query_planner.c - Plan descriptors
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <assert.h>
31 #if !defined(WINDOWS)
32 #include <values.h>
33 #endif /* !WINDOWS */
34 #include "jansson.h"
35 
36 #include "parser.h"
37 #include "object_primitive.h"
38 #include "optimizer.h"
39 #include "query_planner.h"
40 #include "query_graph.h"
41 #include "environment_variable.h"
42 #include "misc_string.h"
43 #include "system_parameter.h"
44 #include "parser.h"
45 #include "parser_message.h"
46 #include "intl_support.h"
47 #include "storage_common.h"
48 #include "xasl_analytic.hpp"
49 #include "xasl_generation.h"
50 #include "schema_manager.h"
51 #include "network_interface_cl.h"
52 #include "dbtype.h"
53 #include "regu_var.hpp"
54 
55 #define INDENT_INCR 4
56 #define INDENT_FMT "%*c"
57 #define TITLE_WIDTH 7
58 #define TITLE_FMT "%-" __STR(TITLE_WIDTH) "s"
59 #define INDENTED_TITLE_FMT INDENT_FMT TITLE_FMT
60 #define __STR(n) __VAL(n)
61 #define __VAL(n) #n
62 #define SORT_SPEC_FMT(spec) \
63  "%d %s %s", (spec)->pos_descr.pos_no + 1, \
64  ((spec)->s_order == S_ASC ? "asc" : "desc"), \
65  ((spec)->s_nulls == S_NULLS_FIRST ? "nulls first" : "nulls last")
66 
67 #define VALID_INNER(plan) (plan->well_rooted || \
68  (plan->plan_type == QO_PLANTYPE_SORT))
69 
70 #define FUDGE_FACTOR 0.7
71 #define ISCAN_OVERHEAD_FACTOR 1.2
72 #define TEMP_SETUP_COST 5.0
73 #define NONGROUPED_SCAN_COST 0.1
74 
75 #define qo_scan_walk qo_generic_walk
76 #define qo_worst_walk qo_generic_walk
77 
78 #define qo_generic_free NULL
79 #define qo_sort_free qo_generic_free
80 #define qo_follow_free qo_generic_free
81 #define qo_worst_free qo_generic_free
82 
83 #define QO_INFO_INDEX(_M_offset, _bitset) \
84  (_M_offset + (unsigned int)(BITPATTERN(_bitset) & planner->node_mask))
85 
86 #define QO_IS_LIMIT_NODE(env, node) \
87  (BITSET_MEMBER (QO_ENV_SORT_LIMIT_NODES ((env)), QO_NODE_IDX ((node))))
88 
89 typedef enum
91 
92 typedef int (*QO_WALK_FUNCTION) (QO_PLAN *, void *);
93 
94 static int infos_allocated = 0;
95 static int infos_deallocated = 0;
96 
97 static int qo_plans_allocated;
99 static int qo_plans_malloced;
102 static int qo_next_tmpfile;
103 
105 
107 static void qo_scan_free (QO_PLAN *);
108 static void qo_join_free (QO_PLAN *);
109 
110 static void qo_scan_fprint (QO_PLAN *, FILE *, int);
111 static void qo_sort_fprint (QO_PLAN *, FILE *, int);
112 static void qo_join_fprint (QO_PLAN *, FILE *, int);
113 static void qo_follow_fprint (QO_PLAN *, FILE *, int);
114 static void qo_worst_fprint (QO_PLAN *, FILE *, int);
115 
116 static void qo_scan_info (QO_PLAN *, FILE *, int);
117 static void qo_sort_info (QO_PLAN *, FILE *, int);
118 static void qo_join_info (QO_PLAN *, FILE *, int);
119 static void qo_follow_info (QO_PLAN *, FILE *, int);
120 static void qo_worst_info (QO_PLAN *, FILE *, int);
121 
122 void qo_plan_lite_print (QO_PLAN *, FILE *, int);
123 static void qo_plan_del_ref_func (QO_PLAN * plan, void *ignore);
124 
125 static void qo_generic_walk (QO_PLAN *, void (*)(QO_PLAN *, void *), void *, void (*)(QO_PLAN *, void *), void *);
126 static void qo_plan_print_sort_spec_helper (PT_NODE *, bool, FILE *, int);
127 static void qo_plan_print_sort_spec (QO_PLAN *, FILE *, int);
128 static void qo_plan_print_costs (QO_PLAN *, FILE *, int);
129 static void qo_plan_print_projected_segs (QO_PLAN *, FILE *, int);
130 static void qo_plan_print_sarged_terms (QO_PLAN *, FILE *, int);
131 static void qo_plan_print_outer_join_terms (QO_PLAN *, FILE *, int);
132 static void qo_plan_print_subqueries (QO_PLAN *, FILE *, int);
133 static void qo_plan_print_analytic_eval (QO_PLAN *, FILE *, int);
134 static void qo_sort_walk (QO_PLAN *, void (*)(QO_PLAN *, void *), void *, void (*)(QO_PLAN *, void *), void *);
135 static void qo_join_walk (QO_PLAN *, void (*)(QO_PLAN *, void *), void *, void (*)(QO_PLAN *, void *), void *);
136 static void qo_follow_walk (QO_PLAN *, void (*)(QO_PLAN *, void *), void *, void (*)(QO_PLAN *, void *), void *);
137 
138 static void qo_plan_compute_cost (QO_PLAN *);
139 static void qo_plan_compute_subquery_cost (PT_NODE *, double *, double *);
140 static void qo_sscan_cost (QO_PLAN *);
141 static void qo_iscan_cost (QO_PLAN *);
142 static void qo_sort_cost (QO_PLAN *);
143 static void qo_mjoin_cost (QO_PLAN *);
144 static void qo_follow_cost (QO_PLAN *);
145 static void qo_worst_cost (QO_PLAN *);
146 static void qo_zero_cost (QO_PLAN *);
147 
148 static QO_PLAN *qo_top_plan_new (QO_PLAN *);
149 
150 static double log3 (double);
151 
152 static void qo_init_planvec (QO_PLANVEC *);
153 static void qo_uninit_planvec (QO_PLANVEC *);
157 
158 static void qo_info_nodes_init (QO_ENV *);
159 static QO_INFO *qo_alloc_info (QO_PLANNER *, BITSET *, BITSET *, BITSET *, double);
160 static void qo_free_info (QO_INFO *);
161 static void qo_detach_info (QO_INFO *);
162 static void qo_dump_planvec (QO_PLANVEC *, FILE *, int);
163 static void qo_dump_info (QO_INFO *, FILE *);
164 static void qo_dump_planner_info (QO_PLANNER *, QO_PARTITION *, FILE *);
165 
167  BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, int);
168 static double planner_nodeset_join_cost (QO_PLANNER *, BITSET *);
170  BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, int, int *);
171 
173 static QO_PLAN *qo_find_best_plan_on_info (QO_INFO *, QO_EQCLASS *, double);
175 static int qo_check_plan_on_info (QO_INFO *, QO_PLAN *);
176 static int qo_examine_idx_join (QO_INFO *, JOIN_TYPE, QO_INFO *, QO_INFO *, BITSET *, BITSET *, BITSET *);
177 static int qo_examine_nl_join (QO_INFO *, JOIN_TYPE, QO_INFO *, QO_INFO *, BITSET *, BITSET *, BITSET *, BITSET *,
178  BITSET *, int, BITSET *);
180  BITSET *);
182 static int qo_examine_follow (QO_INFO *, QO_TERM *, QO_INFO *, BITSET *, BITSET *);
183 static void qo_compute_projected_segs (QO_PLANNER *, BITSET *, BITSET *, BITSET *);
185 
186 
188 static void qo_clean_planner (QO_PLANNER *);
192 static void sort_partitions (QO_PLANNER *);
195  BITSET *, BITSET *, BITSET *, BITSET *);
196 static void qo_generate_seq_scan (QO_INFO *, QO_NODE *);
200 static void qo_plan_add_to_free_list (QO_PLAN *, void *ignore);
201 static void qo_nljoin_cost (QO_PLAN *);
202 static void qo_plans_teardown (QO_ENV * env);
203 static void qo_plans_init (QO_ENV * env);
204 static void qo_plan_walk (QO_PLAN *, void (*)(QO_PLAN *, void *), void *, void (*)(QO_PLAN *, void *), void *);
205 static QO_PLAN *qo_plan_finalize (QO_PLAN *);
208 static void qo_plan_fprint (QO_PLAN *, FILE *, int, const char *);
215 static void qo_plan_free (QO_PLAN *);
216 static QO_PLAN *qo_plan_malloc (QO_ENV *);
217 static const char *qo_term_string (QO_TERM *);
218 static QO_PLAN *qo_worst_new (QO_ENV *);
219 static QO_PLAN *qo_cp_new (QO_INFO *, QO_PLAN *, QO_PLAN *, BITSET *, BITSET *);
220 static QO_PLAN *qo_follow_new (QO_INFO *, QO_PLAN *, QO_TERM *, BITSET *, BITSET *);
222  BITSET *, BITSET *, BITSET *);
224 static QO_PLAN *qo_seq_scan_new (QO_INFO *, QO_NODE *);
226 static int qo_has_is_not_null_term (QO_NODE * node);
227 
228 static bool qo_validate_index_term_notnull (QO_ENV * env, QO_INDEX_ENTRY * index_entryp);
229 static bool qo_validate_index_attr_notnull (QO_ENV * env, QO_INDEX_ENTRY * index_entryp, PT_NODE * col);
230 static int qo_validate_index_for_orderby (QO_ENV * env, QO_NODE_INDEX_ENTRY * ni_entryp);
231 static int qo_validate_index_for_groupby (QO_ENV * env, QO_NODE_INDEX_ENTRY * ni_entryp);
232 static PT_NODE *qo_search_isnull_key_expr (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
233 static bool qo_check_orderby_skip_descending (QO_PLAN * plan);
234 static bool qo_check_groupby_skip_descending (QO_PLAN * plan, PT_NODE * list);
235 static PT_NODE *qo_plan_compute_iscan_sort_list (QO_PLAN * root, PT_NODE * group_by, bool * is_index_w_prefix);
236 
237 static int qo_walk_plan_tree (QO_PLAN * plan, QO_WALK_FUNCTION f, void *arg);
238 static void qo_set_use_desc (QO_PLAN * plan);
239 static int qo_set_orderby_skip (QO_PLAN * plan, void *arg);
240 static int qo_validate_indexes_for_orderby (QO_PLAN * plan, void *arg);
241 static int qo_unset_multi_range_optimization (QO_PLAN * plan, void *arg);
242 static bool qo_plan_is_orderby_skip_candidate (QO_PLAN * plan);
243 static bool qo_is_sort_limit (QO_PLAN * plan);
244 
245 static json_t *qo_plan_scan_print_json (QO_PLAN * plan);
246 static json_t *qo_plan_sort_print_json (QO_PLAN * plan);
247 static json_t *qo_plan_join_print_json (QO_PLAN * plan);
248 static json_t *qo_plan_follow_print_json (QO_PLAN * plan);
249 static json_t *qo_plan_print_json (QO_PLAN * plan);
250 
251 static void qo_plan_scan_print_text (FILE * fp, QO_PLAN * plan, int indent);
252 static void qo_plan_sort_print_text (FILE * fp, QO_PLAN * plan, int indent);
253 static void qo_plan_join_print_text (FILE * fp, QO_PLAN * plan, int indent);
254 static void qo_plan_follow_print_text (FILE * fp, QO_PLAN * plan, int indent);
255 static void qo_plan_print_text (FILE * fp, QO_PLAN * plan, int indent);
256 
257 static bool qo_index_has_bit_attr (QO_INDEX_ENTRY * index_entryp);
258 
260  "sscan",
262  qo_scan_walk,
263  qo_scan_free,
266  qo_scan_info,
267  "Sequential scan"
268 };
269 
271  "iscan",
273  qo_scan_walk,
274  qo_scan_free,
277  qo_scan_info,
278  "Index scan"
279 };
280 
282  "temp",
284  qo_sort_walk,
285  qo_sort_free,
286  qo_sort_cost,
287  qo_sort_cost,
288  qo_sort_info,
289  "Sort"
290 };
291 
293  "nl-join",
295  qo_join_walk,
296  qo_join_free,
299  qo_join_info,
300  "Nested-loop join"
301 };
302 
304  "idx-join",
306  qo_join_walk,
307  qo_join_free,
310  qo_join_info,
311  "Correlated-index join"
312 };
313 
315  "m-join",
317  qo_join_walk,
318  qo_join_free,
321  qo_join_info,
322  "Merge join"
323 };
324 
326  "follow",
333  "Object fetch"
334 };
335 
337  "set_follow",
344  "Set fetch"
345 };
346 
348  "worst",
355  "Bogus"
356 };
357 
367  &qo_worst_plan_vtbl
368 };
369 
370 #define DEFAULT_NULL_SELECTIVITY (double) 0.01
371 #define DEFAULT_EXISTS_SELECTIVITY (double) 0.1
372 #define DEFAULT_SELECTIVITY (double) 0.1
373 #define DEFAULT_EQUAL_SELECTIVITY (double) 0.001
374 #define DEFAULT_EQUIJOIN_SELECTIVITY (double) 0.001
375 #define DEFAULT_COMP_SELECTIVITY (double) 0.1
376 #define DEFAULT_BETWEEN_SELECTIVITY (double) 0.01
377 #define DEFAULT_IN_SELECTIVITY (double) 0.01
378 #define DEFAULT_RANGE_SELECTIVITY (double) 0.1
379 
380 /* Structural equivalence classes for expressions */
381 
382 typedef enum PRED_CLASS
383 {
391 } PRED_CLASS;
392 
393 static double qo_or_selectivity (QO_ENV * env, double lhs_sel, double rhs_sel);
394 
395 static double qo_and_selectivity (QO_ENV * env, double lhs_sel, double rhs_sel);
396 
397 static double qo_not_selectivity (QO_ENV * env, double sel);
398 
399 static double qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr);
400 
401 static double qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr);
402 
403 static double qo_between_selectivity (QO_ENV * env, PT_NODE * pt_expr);
404 
405 static double qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr);
406 
407 static double qo_all_some_in_selectivity (QO_ENV * env, PT_NODE * pt_expr);
408 
409 static PRED_CLASS qo_classify (PT_NODE * attr);
410 
411 static int qo_index_cardinality (QO_ENV * env, PT_NODE * attr);
412 
413 /*
414  * log3 () -
415  * return:
416  * n(in):
417  */
418 static double
419 log3 (double n)
420 {
421  static int initialized = 0;
422  static double ln3;
423 
424 
425  if (!initialized)
426  {
427  /*
428  * I could check ln3 against 0, but I prefer to avoid the
429  * floating point loads and comparison.
430  */
431  ln3 = log (3.0);
432  initialized++;
433  }
434 
435  return log (n) / ln3;
436 }
437 
438 /*
439  * qo_plan_malloc () -
440  * return:
441  * env(in):
442  */
443 static QO_PLAN *
445 {
446  QO_PLAN *plan;
447 
449  if (qo_plan_free_list)
450  {
451  plan = qo_plan_free_list;
452  qo_plan_free_list = plan->plan_un.free.link;
453  }
454  else
455  {
457  plan = (QO_PLAN *) malloc (sizeof (QO_PLAN));
458  if (plan == NULL)
459  {
461  return NULL;
462  }
463  }
464 
465  bitset_init (&(plan->sarged_terms), env);
466  bitset_init (&(plan->subqueries), env);
467 
468  plan->has_sort_limit = false;
469  plan->use_iscan_descending = false;
470 
471  return plan;
472 }
473 
474 
475 /*
476  * qo_term_string () -
477  * return:
478  * term(in):
479  */
480 static const char *
482 {
483  static char buf[257];
484  char *p;
485  BITSET_ITERATOR bi;
486  int i;
487  QO_ENV *env;
488  const char *separator;
489  PT_NODE *conj, *saved_next = NULL;
490 
491  env = QO_TERM_ENV (term);
492 
493  conj = QO_TERM_PT_EXPR (term);
494  if (conj)
495  {
496  saved_next = conj->next;
497  conj->next = NULL;
498  }
499 
500  switch (QO_TERM_CLASS (term))
501  {
502  case QO_TC_DEP_LINK:
503  sprintf (buf, "table(");
504  p = buf + strlen (buf);
505  separator = "";
506  for (i = bitset_iterate (&(QO_NODE_DEP_SET (QO_TERM_TAIL (term))), &bi); i != -1; i = bitset_next_member (&bi))
507  {
508  sprintf (p, "%s%s", separator, QO_NODE_NAME (QO_ENV_NODE (env, i)));
509  p = buf + strlen (buf);
510  separator = ",";
511  }
512  sprintf (p, ") -> %s", QO_NODE_NAME (QO_TERM_TAIL (term)));
513  p = buf;
514  break;
515 
516  case QO_TC_DEP_JOIN:
517  p = buf;
518  sprintf (p, "dep-join(%s,%s)", QO_NODE_NAME (QO_TERM_HEAD (term)), QO_NODE_NAME (QO_TERM_TAIL (term)));
519  break;
520 
521  case QO_TC_DUMMY_JOIN:
522  p = buf;
523  sprintf (p, "dummy(%s,%s)", QO_NODE_NAME (QO_TERM_HEAD (term)), QO_NODE_NAME (QO_TERM_TAIL (term)));
524  break;
525 
526  default:
527  assert_release (conj != NULL);
528  if (conj)
529  {
531  PT_PRINT_VALUE_FUNC saved_func = parser->print_db_value;
532  unsigned int save_custom = parser->custom_print;
533 
534  parser->custom_print |= PT_CONVERT_RANGE;
535  parser->print_db_value = NULL;
536 
537  p = parser_print_tree (parser, conj);
538 
539  parser->custom_print = save_custom;
540  parser->print_db_value = saved_func;
541  }
542  else
543  {
544  p = buf;
545  buf[0] = '\0';
546  }
547  }
548 
549  /* restore link */
550  if (conj)
551  {
552  conj->next = saved_next;
553  }
554 
555  return p;
556 }
557 
558 
559 /*
560  * qo_plan_compute_cost () -
561  * return:
562  * plan(in):
563  */
564 static void
566 {
567  QO_ENV *env;
568  QO_SUBQUERY *subq;
569  PT_NODE *query;
570  double temp_cpu_cost, temp_io_cost;
571  double subq_cpu_cost, subq_io_cost;
572  int i;
573  BITSET_ITERATOR iter;
574 
575  /* When computing the cost for a WORST_PLAN, we'll get in here without a backing info node; just work around it. */
576  env = plan->info ? (plan->info)->env : NULL;
577  subq_cpu_cost = subq_io_cost = 0.0;
578 
579  /* Compute the costs for all of the subqueries. Each of the pinned subqueries is intended to be evaluated once for
580  * each row produced by this plan; the cost of each such evaluation in the fixed cost of the subquery plus one trip
581  * through the result, i.e.,
582  *
583  * QO_PLAN_FIXED_COST(subplan) + QO_PLAN_ACCESS_COST(subplan)
584  *
585  * The cost info for the subplan has (probably) been squirreled away in a QO_SUMMARY structure reachable from the
586  * original select node.
587  */
588 
589  for (i = bitset_iterate (&(plan->subqueries), &iter); i != -1; i = bitset_next_member (&iter))
590  {
591  subq = env ? &env->subqueries[i] : NULL;
592  query = subq ? subq->node : NULL;
593  qo_plan_compute_subquery_cost (query, &temp_cpu_cost, &temp_io_cost);
594  subq_cpu_cost += temp_cpu_cost;
595  subq_io_cost += temp_io_cost;
596  }
597 
598  /* This computes the specific cost characteristics for each plan. */
599  (*(plan->vtbl)->cost_fn) (plan);
600 
601  /* Now add in the subquery costs; this cost is incurred for each row produced by this plan, so multiply it by the
602  * estimated cardinality and add it to the access cost.
603  */
604  if (plan->info)
605  {
606  plan->variable_cpu_cost += (plan->info)->cardinality * subq_cpu_cost;
607  plan->variable_io_cost += (plan->info)->cardinality * subq_io_cost;
608  }
609 }
610 
611 /*
612  * qo_plan_compute_subquery_cost () -
613  * return:
614  * subquery(in):
615  * subq_cpu_cost(in):
616  * subq_io_cost(in):
617  */
618 static void
619 qo_plan_compute_subquery_cost (PT_NODE * subquery, double *subq_cpu_cost, double *subq_io_cost)
620 {
621  QO_SUMMARY *summary;
622  double arg1_cpu_cost, arg1_io_cost, arg2_cpu_cost, arg2_io_cost;
623 
624  *subq_cpu_cost = *subq_io_cost = 0.0; /* init */
625 
626  if (subquery == NULL)
627  {
628  /* This case is selected when a subquery wasn't optimized for some reason.
629  * just take a guess. ---> NEED MORE CONSIDERATION
630  */
631  *subq_cpu_cost = 5.0;
632  *subq_io_cost = 5.0;
633  return;
634  }
635 
636  switch (subquery->node_type)
637  {
638  case PT_SELECT:
639  summary = (QO_SUMMARY *) subquery->info.query.q.select.qo_summary;
640  if (summary)
641  {
642  *subq_cpu_cost += summary->fixed_cpu_cost + summary->variable_cpu_cost;
643  *subq_io_cost += summary->fixed_io_cost + summary->variable_io_cost;
644  }
645  else
646  {
647  /* it may be unknown error. just take a guess. ---> NEED MORE CONSIDERATION */
648  *subq_cpu_cost = 5.0;
649  *subq_io_cost = 5.0;
650  }
651 
652  /* Here, GROUP BY and ORDER BY cost must be considered. ---> NEED MORE CONSIDERATION */
653  /* ---> under construction <--- */
654  break;
655 
656  case PT_UNION:
657  case PT_INTERSECTION:
658  case PT_DIFFERENCE:
659  qo_plan_compute_subquery_cost (subquery->info.query.q.union_.arg1, &arg1_cpu_cost, &arg1_io_cost);
660  qo_plan_compute_subquery_cost (subquery->info.query.q.union_.arg2, &arg2_cpu_cost, &arg2_io_cost);
661 
662  *subq_cpu_cost = arg1_cpu_cost + arg2_cpu_cost;
663  *subq_io_cost = arg1_io_cost + arg2_io_cost;
664 
665  /* later, sort cost and result-set scan cost must be considered. ---> NEED MORE CONSIDERATION */
666  /* ---> under construction <--- */
667  break;
668 
669  default:
670  /* it is unknown case. just take a guess. ---> NEED MORE CONSIDERATION */
671  *subq_cpu_cost = 5.0;
672  *subq_io_cost = 5.0;
673  break;
674  }
675 
676  return;
677 }
678 
679 /*
680  * qo_walk_plan_tree () - applies a callback to every plan in a plan tree
681  * and stops on errors
682  * return: the error of the first callback function that returns something
683  * other than NO_ERROR, or NO_ERROR.
684  * plan(in): the root of the plan tree to walk
685  * f(in): functor (callback) to apply to each non-null plan
686  * arg(in/out): argument to be used liberally by the callback
687  */
688 static int
690 {
691  int ret = NO_ERROR;
692 
693  if (!plan)
694  {
695  return NO_ERROR;
696  }
697 
698  switch (plan->plan_type)
699  {
700  case QO_PLANTYPE_SCAN:
701  return f (plan, arg);
702 
703  case QO_PLANTYPE_FOLLOW:
704  return qo_walk_plan_tree (plan->plan_un.follow.head, f, arg);
705 
706  case QO_PLANTYPE_SORT:
707  return qo_walk_plan_tree (plan->plan_un.sort.subplan, f, arg);
708 
709  case QO_PLANTYPE_JOIN:
710  ret = qo_walk_plan_tree (plan->plan_un.join.outer, f, arg);
711  if (ret != NO_ERROR)
712  {
713  return ret;
714  }
715 
716  return qo_walk_plan_tree (plan->plan_un.join.inner, f, arg);
717 
718  default:
719  return ER_FAILED;
720  }
721 }
722 
723 /*
724  * qo_set_use_desc () - sets certain plans' use_descending index flag
725  *
726  * return: NO_ERROR
727  * plan(in):
728  *
729  * note: the function only cares about index scans and skips other plan types
730  */
731 static void
733 {
734  switch (plan->plan_type)
735  {
736  case QO_PLANTYPE_SCAN:
737  if (((qo_is_iscan (plan) || qo_is_iscan_from_groupby (plan))
738  && plan->plan_un.scan.index->head->groupby_skip == true)
739  || ((qo_is_iscan (plan) || qo_is_iscan_from_orderby (plan))
740  && plan->plan_un.scan.index->head->orderby_skip == true))
741  {
742  plan->plan_un.scan.index->head->use_descending = true;
743  }
744  break;
745 
746  case QO_PLANTYPE_FOLLOW:
747  qo_set_use_desc (plan->plan_un.follow.head);
748  break;
749 
750  case QO_PLANTYPE_JOIN:
751  qo_set_use_desc (plan->plan_un.join.outer);
752  break;
753 
754  default:
755  break;
756  }
757 }
758 
759 /*
760  * qo_unset_multi_range_optimization () - set all multi_range_opt flags
761  * on all indexes to false
762  *
763  * return : NO_ERROR
764  * plan (in) : current plan
765  * arg (in) : not used
766  */
767 static int
769 {
771  {
772  /* nothing to do */
773  return NO_ERROR;
774  }
775 
776  /* set multi_range_opt to false */
778 
779  if (qo_is_index_mro_scan (plan))
780  {
781  QO_INDEX_ENTRY *index_entryp;
782 
783  index_entryp = plan->plan_un.scan.index->head;
784 
785  /* multi_range_opt may have set the descending order on index */
786  if (index_entryp->use_descending)
787  {
788  /* if descending order is hinted or if skip order by / skip group by are true, leave the index as descending */
789  if (((plan->info->env->pt_tree->info.query.q.select.hint & PT_HINT_USE_IDX_DESC) == 0)
790  && !index_entryp->groupby_skip && !index_entryp->orderby_skip)
791  {
792  /* set use_descending to false */
793  index_entryp->use_descending = false;
794  }
795  }
796  }
797 
798  return NO_ERROR;
799 }
800 
801 /*
802  * qo_set_orderby_skip () - sets certain plans' orderby_skip index flag to the
803  * boolean value given in *arg.
804  *
805  * return: NO_ERROR
806  * plan(in):
807  * arg(in): will be cast to bool* and its values used to set
808  * the orderby_skip property
809  * note: the function only cares about index scans and skips other plan types
810  */
811 static int
812 qo_set_orderby_skip (QO_PLAN * plan, void *arg)
813 {
814  if (qo_is_iscan (plan) || qo_is_iscan_from_orderby (plan))
815  {
816  bool yn = *((bool *) arg);
817  plan->plan_un.scan.index->head->orderby_skip = yn;
818  }
819 
820  return NO_ERROR;
821 }
822 
823 /*
824  * qo_validate_indexes_for_orderby () - wrapper function for
825  * qo_validate_index_for_orderby
826  * used with qo_walk_plan_tree.
827  * return: NO_ERROR or ER_FAILED if the wrapped function returns false
828  * plan(in):
829  * arg(in): not used, must be NULL
830  */
831 static int
833 {
834  if (qo_is_iscan_from_orderby (plan))
835  {
836  if (!qo_validate_index_for_orderby (plan->info->env, plan->plan_un.scan.index))
837  {
838  return ER_FAILED;
839  }
840  }
841 
842  return NO_ERROR;
843 }
844 
845 /*
846  * qo_top_plan_new () -
847  * return:
848  * plan(in):
849  */
850 static QO_PLAN *
852 {
853  QO_ENV *env;
854  PT_NODE *tree, *group_by, *order_by, *orderby_for;
855  PT_MISC_TYPE all_distinct;
857 
858  if (plan == NULL || plan->top_rooted)
859  {
860  return plan; /* is already top-level plan - OK */
861  }
862 
863  if (plan->info == NULL /* worst plan */
864  || (env = (plan->info)->env) == NULL || bitset_cardinality (&((plan->info)->nodes)) < env->Nnodes
865  || /* sub-plan */ (tree = QO_ENV_PT_TREE (env)) == NULL
866  || (parser = QO_ENV_PARSER (env)) == NULL)
867  {
868  return plan; /* do nothing */
869  }
870 
871  QO_ASSERT (env, tree->node_type == PT_SELECT);
872 
873  plan->top_rooted = true; /* mark as top-level plan */
874 
875  if (pt_is_single_tuple (QO_ENV_PARSER (env), tree))
876  { /* one tuple plan */
877  return plan; /* do nothing */
878  }
879 
880  if (qo_plan_multi_range_opt (plan))
881  {
882  /* already found out that multi range optimization can be applied on current plan, skip any other checks */
883  return plan;
884  }
885 
886  all_distinct = tree->info.query.all_distinct;
887  group_by = tree->info.query.q.select.group_by;
888  order_by = tree->info.query.order_by;
889  orderby_for = tree->info.query.orderby_for;
890 
891  if (group_by || (all_distinct == PT_DISTINCT || order_by))
892  {
893 
894  bool groupby_skip, orderby_skip, is_index_w_prefix;
895  bool found_instnum;
896  int t;
897  BITSET_ITERATOR iter;
898  QO_TERM *term;
899 
900  groupby_skip = orderby_skip = false; /* init */
901 
902  for (t = bitset_iterate (&(plan->sarged_terms), &iter); t != -1; t = bitset_next_member (&iter))
903  {
904  term = QO_ENV_TERM (env, t);
906  {
907  break; /* found inst_num() */
908  }
909  } /* for (t = ...) */
910  found_instnum = (t == -1) ? false : true;
911 
912  plan->iscan_sort_list = qo_plan_compute_iscan_sort_list (plan, NULL, &is_index_w_prefix);
913 
914  /* GROUP BY */
915  /* if we have rollup, we do not skip the group by */
916  if (group_by && !group_by->flag.with_rollup)
917  {
918  PT_NODE *group_sort_list = NULL;
919 
920  group_sort_list = qo_plan_compute_iscan_sort_list (plan, group_by, &is_index_w_prefix);
921 
922  if (group_sort_list)
923  {
924  if (found_instnum /* && found_grpynum */ )
925  {
926  ; /* give up */
927  }
928  else
929  {
930  groupby_skip = pt_sort_spec_cover_groupby (parser, group_sort_list, group_by, tree);
931 
932  /* if index plan and can't skip group by, we search that maybe a descending scan can be used. */
933  if (qo_is_interesting_order_scan (plan) && !groupby_skip)
934  {
935  groupby_skip = qo_check_groupby_skip_descending (plan, group_sort_list);
936 
937  if (groupby_skip)
938  {
939  plan->use_iscan_descending = true;
940  }
941  }
942  }
943 
944  parser_free_node (parser, group_sort_list);
945  }
946 
947  if (groupby_skip)
948  {
949  /* if the plan is index_groupby, we validate the plan */
951  {
952  if (!qo_validate_index_for_groupby (plan->info->env, plan->plan_un.scan.index))
953  {
954  /* drop the plan if it wasn't validated */
955  qo_worst_cost (plan);
956  return plan;
957  }
958  }
959  /* if all goes well, we have an indexed plan with group by skip! */
960  if (plan->plan_type == QO_PLANTYPE_SCAN && plan->plan_un.scan.index)
961  {
962  plan->plan_un.scan.index->head->groupby_skip = true;
963  }
964  }
965  else
966  {
967  /* if the order by is not skipped we drop the plan because it didn't helped us */
969  {
970  qo_worst_cost (plan);
971  return plan;
972  }
973 
974  plan = qo_sort_new (plan, QO_UNORDERED, SORT_GROUPBY);
975  assert (plan->iscan_sort_list == NULL);
976  }
977  }
978 
979  /* DISTINCT, ORDER BY */
980  if (all_distinct == PT_DISTINCT || order_by)
981  {
982  if (plan->iscan_sort_list)
983  { /* need to check */
984  if (all_distinct == PT_DISTINCT)
985  {
986  ; /* give up */
987  }
988  else
989  { /* non distinct */
990  if (group_by)
991  {
992  /* we already removed covered ORDER BY in reduce_order_by(). so is not covered ordering */
993  ; /* give up; DO NOT DELETE ME - need future work */
994  }
995  else
996  { /* non group_by */
997  if (found_instnum && orderby_for)
998  {
999  /* at here, we can not merge orderby_num pred with inst_num pred */
1000  ; /* give up; DO NOT DELETE ME - need future work */
1001  }
1002  else if (!is_index_w_prefix && !tree->info.query.q.select.connect_by
1003  && !pt_has_analytic (parser, tree))
1004  {
1005  orderby_skip = pt_sort_spec_cover (plan->iscan_sort_list, order_by);
1006 
1007  /* try using a reverse scan */
1008  if (!orderby_skip)
1009  {
1010  orderby_skip = qo_check_orderby_skip_descending (plan);
1011 
1012  if (orderby_skip)
1013  {
1015  plan->use_iscan_descending = true;
1016  }
1017  }
1018  }
1019  }
1020  }
1021  }
1022 
1023  if (orderby_skip)
1024  {
1025  if (qo_is_iscan_from_groupby (plan))
1026  {
1027  /* group by skipping plan and we have order by skip -> drop */
1028  qo_worst_cost (plan);
1029  return plan;
1030  }
1031 
1032  if (orderby_for)
1033  { /* apply inst_num filter */
1034  ; /* DO NOT DELETE ME - need future work */
1035  }
1036 
1037  /* validate the index orderby plan or subplans */
1039  {
1040  /* drop the plan if it wasn't validated */
1041  qo_worst_cost (plan);
1042  return plan;
1043  }
1044 
1045  /* if all goes well, we have an indexed plan with order by skip: set the flag to all suitable subplans */
1046  {
1047  bool yn = true;
1049  }
1050  }
1051  else
1052  {
1053  /* if the order by is not skipped we drop the plan because it didn't helped us */
1054  if (qo_is_iscan_from_orderby (plan))
1055  {
1056  qo_worst_cost (plan);
1057  return plan;
1058  }
1059 
1060  plan = qo_sort_new (plan, QO_UNORDERED, all_distinct == PT_DISTINCT ? SORT_DISTINCT : SORT_ORDERBY);
1061  }
1062  }
1063  }
1064 
1065  return plan;
1066 }
1067 
1068 /*
1069  * qo_generic_walk () -
1070  * return:
1071  * plan(in):
1072  * child_fn(in):
1073  * child_data(in):
1074  * parent_fn(in):
1075  * parent_data(in):
1076  */
1077 static void
1078 qo_generic_walk (QO_PLAN * plan, void (*child_fn) (QO_PLAN *, void *), void *child_data,
1079  void (*parent_fn) (QO_PLAN *, void *), void *parent_data)
1080 {
1081  if (parent_fn)
1082  {
1083  (*parent_fn) (plan, parent_data);
1084  }
1085 }
1086 
1087 /*
1088  * qo_plan_print_sort_spec_helper () -
1089  * return:
1090  * list(in):
1091  * f(in):
1092  * howfar(in):
1093  */
1094 static void
1095 qo_plan_print_sort_spec_helper (PT_NODE * list, bool is_iscan_asc, FILE * f, int howfar)
1096 {
1097  const char *prefix;
1098  bool is_sort_spec_asc = true;
1099 
1100  if (list == NULL)
1101  {
1102  return;
1103  }
1104 
1105  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "sort: ");
1106 
1107  prefix = "";
1108  for (; list; list = list->next)
1109  {
1110  if (list->info.sort_spec.pos_descr.pos_no < 1)
1111  { /* useless from here */
1112  break;
1113  }
1114  fputs (prefix, f);
1115 
1116  if (list->info.sort_spec.asc_or_desc == PT_ASC)
1117  {
1118  is_sort_spec_asc = true;
1119  }
1120  else
1121  {
1122  is_sort_spec_asc = false;
1123  }
1124 
1125  fprintf (f, "%d %s", list->info.sort_spec.pos_descr.pos_no, (is_sort_spec_asc == is_iscan_asc) ? "asc" : "desc");
1126 
1130  {
1131  fprintf (f, " collate %s",
1133  }
1134  prefix = ", ";
1135  }
1136 }
1137 
1138 /*
1139  * qo_plan_print_sort_spec () -
1140  * return:
1141  * plan(in):
1142  * f(in):
1143  * howfar(in):
1144  */
1145 static void
1146 qo_plan_print_sort_spec (QO_PLAN * plan, FILE * f, int howfar)
1147 {
1148  bool is_iscan_asc = true;
1149 
1150  if (plan->top_rooted != true)
1151  { /* check for top level plan */
1152  return;
1153  }
1154 
1155  is_iscan_asc = plan->use_iscan_descending ? false : true;
1156 
1157  qo_plan_print_sort_spec_helper (plan->iscan_sort_list, is_iscan_asc, f, howfar);
1158 
1159  if (plan->plan_type == QO_PLANTYPE_SORT)
1160  {
1161  QO_ENV *env;
1162  PT_NODE *tree;
1163 
1164  env = (plan->info)->env;
1165  if (env == NULL)
1166  {
1167  assert (false);
1168  return; /* give up */
1169  }
1170  tree = QO_ENV_PT_TREE (env);
1171  if (tree == NULL)
1172  {
1173  assert (false);
1174  return; /* give up */
1175  }
1176 
1177  if (plan->plan_un.sort.sort_type == SORT_GROUPBY && tree->node_type == PT_SELECT)
1178  {
1179  qo_plan_print_sort_spec_helper (tree->info.query.q.select.group_by, true, f, howfar);
1180  }
1181 
1182  if ((plan->plan_un.sort.sort_type == SORT_DISTINCT || plan->plan_un.sort.sort_type == SORT_ORDERBY)
1183  && PT_IS_QUERY (tree))
1184  {
1185  qo_plan_print_sort_spec_helper (tree->info.query.order_by, true, f, howfar);
1186  }
1187  }
1188 }
1189 
1190 /*
1191  * qo_plan_print_costs () -
1192  * return:
1193  * plan(in):
1194  * f(in):
1195  * howfar(in):
1196  */
1197 static void
1198 qo_plan_print_costs (QO_PLAN * plan, FILE * f, int howfar)
1199 {
1200  double fixed = plan->fixed_cpu_cost + plan->fixed_io_cost;
1201  double variable = plan->variable_cpu_cost + plan->variable_io_cost;
1202 
1203  fprintf (f, "\n" INDENTED_TITLE_FMT "%.0f card %.0f", (int) howfar, ' ', "cost:", fixed + variable,
1204  (plan->info)->cardinality);
1205 }
1206 
1207 
1208 /*
1209  * qo_plan_print_projected_segs () -
1210  * return:
1211  * plan(in):
1212  * f(in):
1213  * howfar(in):
1214  */
1215 static void
1216 qo_plan_print_projected_segs (QO_PLAN * plan, FILE * f, int howfar)
1217 {
1218  int sx;
1219  const char *prefix = "";
1220  BITSET_ITERATOR si;
1221 
1222  if (!((plan->info)->env->dump_enable))
1223  {
1224  return;
1225  }
1226 
1227  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "segs:");
1228  for (sx = bitset_iterate (&((plan->info)->projected_segs), &si); sx != -1; sx = bitset_next_member (&si))
1229  {
1230  fputs (prefix, f);
1231  qo_seg_fprint (&(plan->info)->env->segs[sx], f);
1232  prefix = ", ";
1233  }
1234 }
1235 
1236 
1237 /*
1238  * qo_plan_print_sarged_terms () -
1239  * return:
1240  * plan(in):
1241  * f(in):
1242  * howfar(in):
1243  */
1244 static void
1245 qo_plan_print_sarged_terms (QO_PLAN * plan, FILE * f, int howfar)
1246 {
1247  if (!bitset_is_empty (&(plan->sarged_terms)))
1248  {
1249  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "sargs:");
1250  qo_termset_fprint ((plan->info)->env, &plan->sarged_terms, f);
1251  }
1252 }
1253 
1254 /*
1255  * qo_plan_print_outer_join_terms () -
1256  * return:
1257  * plan(in):
1258  * f(in):
1259  * howfar(in):
1260  */
1261 static void
1262 qo_plan_print_outer_join_terms (QO_PLAN * plan, FILE * f, int howfar)
1263 {
1264  if (!bitset_is_empty (&(plan->plan_un.join.during_join_terms)))
1265  {
1266  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "during:");
1267  qo_termset_fprint ((plan->info)->env, &(plan->plan_un.join.during_join_terms), f);
1268  }
1269  if (!bitset_is_empty (&(plan->plan_un.join.after_join_terms)))
1270  {
1271  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "after:");
1272  qo_termset_fprint ((plan->info)->env, &(plan->plan_un.join.after_join_terms), f);
1273  }
1274 }
1275 
1276 
1277 /*
1278  * qo_plan_print_subqueries () -
1279  * return:
1280  * plan(in):
1281  * f(in):
1282  * howfar(in):
1283  */
1284 static void
1285 qo_plan_print_subqueries (QO_PLAN * plan, FILE * f, int howfar)
1286 {
1287  if (!bitset_is_empty (&(plan->subqueries)))
1288  {
1289  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "subqs: ");
1290  bitset_print (&(plan->subqueries), f);
1291  }
1292 }
1293 
1294 /*
1295  * qo_plan_print_analytic_eval () - print evaluation order of analytic
1296  * functions
1297  * return:
1298  * plan(in):
1299  * f(in):
1300  * howfar(in):
1301  */
1302 static void
1303 qo_plan_print_analytic_eval (QO_PLAN * plan, FILE * f, int howfar)
1304 {
1305  ANALYTIC_EVAL_TYPE *eval;
1306  ANALYTIC_TYPE *func;
1307  SORT_LIST *sort;
1308  int i, j, k;
1309  char buf[32];
1310 
1311  if (plan->analytic_eval_list != NULL)
1312  {
1313  fprintf (f, "\n\nAnalytic functions:");
1314 
1315  /* list functions */
1316  for (i = 0, k = 0, eval = plan->analytic_eval_list; eval != NULL; eval = eval->next, k++)
1317  {
1318  /* run info */
1319  sprintf (buf, "run[%d]: ", k);
1320  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', buf);
1321  fprintf (f, "sort with key (");
1322 
1323  /* eval sort list */
1324  for (sort = eval->sort_list; sort != NULL; sort = sort->next)
1325  {
1326  fprintf (f, SORT_SPEC_FMT (sort));
1327  if (sort->next != NULL)
1328  {
1329  fputs (", ", f);
1330  }
1331  }
1332  fputs (")", f);
1333 
1334  for (func = eval->head; func != NULL; func = func->next, i++)
1335  {
1336  /* func info */
1337  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "");
1338  fprintf (f, "func[%d]: ", i);
1339  fputs (fcode_get_lowercase_name (func->function), f);
1340 
1341  /* func partition by */
1342  fputs (" partition by (", f);
1343  for (sort = eval->sort_list, j = func->sort_prefix_size; sort != NULL && j > 0; sort = sort->next, j--)
1344  {
1345  fprintf (f, SORT_SPEC_FMT (sort));
1346  if (sort->next != NULL && j != 1)
1347  {
1348  fputs (", ", f);
1349  }
1350  }
1351 
1352  /* func order by */
1353  fputs (") order by (", f);
1354  for (j = func->sort_list_size - func->sort_prefix_size; sort != NULL && j > 0; sort = sort->next, j--)
1355  {
1356  fprintf (f, SORT_SPEC_FMT (sort));
1357  if (sort->next != NULL && j != 1)
1358  {
1359  fputs (", ", f);
1360  }
1361  }
1362  fputs (")", f);
1363  }
1364  }
1365  }
1366 }
1367 
1368 /*
1369  * qo_scan_new () -
1370  * return:
1371  * info(in):
1372  * node(in):
1373  * scan_method(in):
1374  */
1375 static QO_PLAN *
1376 qo_scan_new (QO_INFO * info, QO_NODE * node, QO_SCANMETHOD scan_method)
1377 {
1378  QO_PLAN *plan;
1379 
1380  plan = qo_plan_malloc (info->env);
1381  if (plan == NULL)
1382  {
1383  return NULL;
1384  }
1385 
1386  plan->info = info;
1387  plan->refcount = 0;
1388  plan->top_rooted = false;
1389  plan->well_rooted = true;
1390  plan->iscan_sort_list = NULL;
1391  plan->analytic_eval_list = NULL;
1392  plan->plan_type = QO_PLANTYPE_SCAN;
1393  plan->order = QO_UNORDERED;
1394 
1395  plan->plan_un.scan.scan_method = scan_method;
1396  plan->plan_un.scan.node = node;
1397 
1398  bitset_assign (&(plan->sarged_terms), &(QO_NODE_SARGS (node)));
1399 
1400  bitset_assign (&(plan->subqueries), &(QO_NODE_SUBQUERIES (node)));
1401  bitset_init (&(plan->plan_un.scan.terms), info->env);
1402  bitset_init (&(plan->plan_un.scan.kf_terms), info->env);
1403  bitset_init (&(plan->plan_un.scan.hash_terms), info->env);
1404  plan->plan_un.scan.index_equi = false;
1405  plan->plan_un.scan.index_cover = false;
1406  plan->plan_un.scan.index_iss = false;
1407  plan->plan_un.scan.index_loose = false;
1408  plan->plan_un.scan.index = NULL;
1409 
1411  bitset_init (&(plan->plan_un.scan.multi_col_range_segs), info->env);
1412 
1413  return plan;
1414 }
1415 
1416 
1417 /*
1418  * qo_scan_free () -
1419  * return:
1420 * plan(in):
1421  */
1422 static void
1424 {
1425  bitset_delset (&(plan->plan_un.scan.terms));
1426  bitset_delset (&(plan->plan_un.scan.kf_terms));
1427  bitset_delset (&(plan->plan_un.scan.hash_terms));
1428  bitset_delset (&(plan->plan_un.scan.multi_col_range_segs));
1429 }
1430 
1431 
1432 /*
1433  * qo_seq_scan_new () -
1434  * return:
1435  * info(in):
1436  * node(in):
1437  */
1438 static QO_PLAN *
1440 {
1441  QO_PLAN *plan;
1442 
1443  plan = qo_scan_new (info, node, QO_SCANMETHOD_SEQ_SCAN);
1444  if (plan == NULL)
1445  {
1446  return NULL;
1447  }
1448 
1449  plan->vtbl = &qo_seq_scan_plan_vtbl;
1450 
1451  assert (bitset_is_empty (&(plan->plan_un.scan.terms)));
1452  assert (bitset_is_empty (&(plan->plan_un.scan.kf_terms)));
1453  assert (plan->plan_un.scan.index_equi == false);
1454  assert (plan->plan_un.scan.index_cover == false);
1455  assert (plan->plan_un.scan.index_iss == false);
1456  assert (plan->plan_un.scan.index_loose == false);
1457  assert (plan->plan_un.scan.index == NULL);
1458 
1459  qo_plan_compute_cost (plan);
1460 
1461  plan = qo_top_plan_new (plan);
1462 
1463  return plan;
1464 }
1465 
1466 
1467 /*
1468  * qo_sscan_cost () -
1469  * return:
1470  * planp(in):
1471  */
1472 static void
1474 {
1475  QO_NODE *nodep;
1476 
1477  nodep = planp->plan_un.scan.node;
1478  planp->fixed_cpu_cost = 0.0;
1479  planp->fixed_io_cost = 0.0;
1480  if (QO_NODE_NCARD (nodep) == 0)
1481  {
1482  planp->variable_cpu_cost = 1.0 * (double) QO_CPU_WEIGHT;
1483  }
1484  else
1485  {
1486  planp->variable_cpu_cost = (double) QO_NODE_NCARD (nodep) * (double) QO_CPU_WEIGHT;
1487  }
1488  planp->variable_io_cost = (double) QO_NODE_TCARD (nodep);
1489 }
1490 
1491 /*
1492  * qo_index_has_bit_attr () - temporary function
1493  * determines if index has any bit/varbit attributes
1494  * return: true/false
1495  * index_entyp(in):
1496  */
1497 static bool
1499 {
1500  TP_DOMAIN *domain;
1501  int col_num = index_entryp->col_num;
1502  int j;
1503 
1504  for (j = 0; j < col_num; j++)
1505  {
1506  domain = index_entryp->constraints->attributes[j]->domain;
1507  if (TP_DOMAIN_TYPE (domain) == DB_TYPE_BIT || TP_DOMAIN_TYPE (domain) == DB_TYPE_VARBIT)
1508  {
1509  return true;
1510  }
1511  }
1512 
1513  return false;
1514 }
1515 
1516 /*
1517  * qo_index_scan_new () -
1518  * return:
1519  * info(in):
1520  * node(in):
1521  * ni_entry(in):
1522  * scan_method(in):
1523  * range_terms(in):
1524  * indexable_terms(in):
1525  */
1526 static QO_PLAN *
1527 qo_index_scan_new (QO_INFO * info, QO_NODE * node, QO_NODE_INDEX_ENTRY * ni_entry, QO_SCANMETHOD scan_method,
1528  BITSET * range_terms, BITSET * indexable_terms)
1529 {
1530  QO_PLAN *plan = NULL;
1531  BITSET_ITERATOR iter;
1532  int t = -1;
1533  QO_ENV *env = info->env;
1534  QO_INDEX_ENTRY *index_entryp = NULL;
1535  QO_TERM *term = NULL;
1536  BITSET index_segs;
1537  BITSET term_segs;
1538  BITSET remaining_terms;
1539  int first_seg;
1540  bool first_col_present = false;
1541 
1542  assert (ni_entry != NULL);
1543  assert (ni_entry->head != NULL);
1544 
1545  assert (scan_method == QO_SCANMETHOD_INDEX_SCAN || scan_method == QO_SCANMETHOD_INDEX_ORDERBY_SCAN
1546  || scan_method == QO_SCANMETHOD_INDEX_GROUPBY_SCAN || scan_method == QO_SCANMETHOD_INDEX_SCAN_INSPECT);
1547 
1548  assert (scan_method != QO_SCANMETHOD_INDEX_SCAN || !(ni_entry->head->force < 0));
1549  assert (scan_method == QO_SCANMETHOD_INDEX_SCAN_INSPECT || range_terms != NULL);
1550 
1551  plan = qo_scan_new (info, node, scan_method);
1552  if (plan == NULL)
1553  {
1554  return NULL;
1555  }
1556 
1557  bitset_init (&index_segs, env);
1558  bitset_init (&term_segs, env);
1559  bitset_init (&remaining_terms, env);
1560 
1561  if (range_terms != NULL)
1562  {
1563  /* remove key-range terms from sarged terms */
1564  bitset_difference (&(plan->sarged_terms), range_terms);
1565  }
1566 
1567  /* remove key-range terms from remaining terms */
1568  if (indexable_terms != NULL)
1569  {
1570  bitset_assign (&remaining_terms, indexable_terms);
1571  bitset_difference (&remaining_terms, range_terms);
1572  }
1573  bitset_union (&remaining_terms, &(plan->sarged_terms));
1574 
1575  /*
1576  * This is, in essence, the selectivity of the index. We
1577  * really need to do a better job of figuring out the cost of
1578  * an indexed scan.
1579  */
1580  plan->vtbl = &qo_index_scan_plan_vtbl;
1581  plan->plan_un.scan.index = ni_entry;
1582 
1583  index_entryp = (plan->plan_un.scan.index)->head;
1584  first_seg = index_entryp->seg_idxs[0];
1585 
1586  if (range_terms != NULL)
1587  {
1588  /* set key-range terms */
1589  bitset_assign (&(plan->plan_un.scan.terms), range_terms);
1590  bitset_assign (&(plan->plan_un.scan.multi_col_range_segs), &(index_entryp->multi_col_range_segs));
1591  for (t = bitset_iterate (range_terms, &iter); t != -1; t = bitset_next_member (&iter))
1592  {
1593  term = QO_ENV_TERM (env, t);
1594 
1595  if (first_seg != -1 && BITSET_MEMBER (QO_TERM_SEGS (term), first_seg))
1596  {
1597  first_col_present = true;
1598  }
1599 
1600  if (!QO_TERM_IS_FLAGED (term, QO_TERM_EQUAL_OP))
1601  {
1602  break;
1603  }
1604  }
1605  }
1606 
1607  if (!bitset_is_empty (&(plan->plan_un.scan.terms)) && t == -1)
1608  {
1609  /* is all equi-cond key-range terms */
1610  plan->plan_un.scan.index_equi = true;
1611  }
1612  else
1613  {
1614  plan->plan_un.scan.index_equi = false;
1615  }
1616 
1617  if (index_entryp->constraints->func_index_info && index_entryp->cover_segments == false)
1618  {
1619  /* do not permit key-filter */
1620  assert (bitset_is_empty (&(plan->plan_un.scan.kf_terms)));
1621  }
1622  else
1623  {
1624  /* all segments consisting in key columns */
1625  for (t = 0; t < index_entryp->nsegs; t++)
1626  {
1627  if ((index_entryp->seg_idxs[t]) != -1)
1628  {
1629  bitset_add (&index_segs, (index_entryp->seg_idxs[t]));
1630  }
1631  }
1632 
1633  for (t = bitset_iterate (&remaining_terms, &iter); t != -1; t = bitset_next_member (&iter))
1634  {
1635  term = QO_ENV_TERM (env, t);
1636 
1638  {
1639  /* term contains a collation that prevents us from using this term as a key range/filter */
1640  continue;
1641  }
1642 
1643  if (!bitset_is_empty (&(QO_TERM_SUBQUERIES (term))))
1644  {
1645  continue; /* term contains correlated subquery */
1646  }
1647 
1648  /* check for no key-range index scan */
1649  if (bitset_is_empty (&(plan->plan_un.scan.terms)))
1650  {
1651  if (qo_is_filter_index (index_entryp) || qo_is_iscan_from_orderby (plan)
1652  || qo_is_iscan_from_groupby (plan))
1653  {
1654  /* filter index has a pre-defined key-range. ordery/groupby scan already checked nullable terms */
1655  ; /* go ahead */
1656  }
1657  else
1658  {
1659  /* do not permit non-indexable term as key-filter */
1660  if (!term->can_use_index)
1661  {
1662  continue;
1663  }
1664  }
1665  }
1666 
1667  bitset_assign (&term_segs, &(QO_TERM_SEGS (term)));
1668  bitset_intersect (&term_segs, &(QO_NODE_SEGS (node)));
1669 
1670  /* if the term is consisted by only the node's segments which appear in scan terms, it will be key-filter.
1671  * otherwise will be data filter
1672  */
1673  if (!bitset_is_empty (&term_segs))
1674  {
1675  if (bitset_subset (&index_segs, &term_segs))
1676  {
1677  bitset_add (&(plan->plan_un.scan.kf_terms), t);
1678  }
1679  }
1680  }
1681 
1682  /* exclude key filter terms from sargs terms */
1683  bitset_difference (&(plan->sarged_terms), &(plan->plan_un.scan.kf_terms));
1684  bitset_difference (&remaining_terms, &(plan->plan_un.scan.kf_terms));
1685  }
1686 
1687  /* check for index cover scan */
1688  plan->plan_un.scan.index_cover = false; /* init */
1689  if (index_entryp->cover_segments)
1690  {
1691  /* do not consider prefix index */
1692  if (qo_is_prefix_index (index_entryp) == false)
1693  {
1694  for (t = bitset_iterate (&remaining_terms, &iter); t != -1; t = bitset_next_member (&iter))
1695  {
1696  term = QO_ENV_TERM (env, t);
1697 
1698  if (!bitset_is_empty (&(QO_TERM_SUBQUERIES (term))))
1699  {
1700  /* term contains correlated subquery */
1701  continue;
1702  }
1703 
1704  break; /* found data-filter */
1705  }
1706 
1707  if (t == -1)
1708  {
1709  /* not found data-filter; mark as covering index scan */
1710  plan->plan_un.scan.index_cover = true;
1711  }
1712  }
1713  }
1714 
1715  assert (!bitset_intersects (&(plan->plan_un.scan.terms), &(plan->plan_un.scan.kf_terms)));
1716 
1717  assert (!bitset_intersects (&(plan->plan_un.scan.terms), &(plan->sarged_terms)));
1718  assert (!bitset_intersects (&(plan->plan_un.scan.kf_terms), &(plan->sarged_terms)));
1719 
1720  assert (!bitset_intersects (&(plan->plan_un.scan.terms), &remaining_terms));
1721  assert (!bitset_intersects (&(plan->plan_un.scan.kf_terms), &remaining_terms));
1722 
1723  bitset_delset (&remaining_terms);
1724  bitset_delset (&term_segs);
1725  bitset_delset (&index_segs);
1726 
1727  /* check for index skip scan */
1728  plan->plan_un.scan.index_iss = false; /* init */
1729  if (index_entryp->is_iss_candidate)
1730  {
1731  assert (!bitset_is_empty (&(plan->plan_un.scan.terms)));
1732  assert (index_entryp->ils_prefix_len == 0);
1733  assert (!qo_is_filter_index (index_entryp));
1734 
1735  if (first_col_present == false)
1736  {
1737  plan->plan_un.scan.index_iss = true;
1738  }
1739  }
1740 
1741  /* check for loose index scan */
1742  plan->plan_un.scan.index_loose = false; /* init */
1743  if (index_entryp->ils_prefix_len > 0)
1744  {
1745  assert (plan->plan_un.scan.index_iss == false);
1746 
1747  /* do not consider prefix index */
1748  if (qo_is_prefix_index (index_entryp) == false)
1749  {
1750  if (scan_method == QO_SCANMETHOD_INDEX_SCAN && qo_is_index_covering_scan (plan)
1751  && !qo_index_has_bit_attr (index_entryp))
1752  {
1753  /* covering index, no key-range, no data-filter; mark as loose index scan */
1754  plan->plan_un.scan.index_loose = true;
1755  }
1756 
1757  /* keep out not good index scan */
1758  if (!qo_is_index_loose_scan (plan))
1759  {
1760  /* check for no key-range, no key-filter index scan */
1761  if (qo_is_iscan (plan) && bitset_is_empty (&(plan->plan_un.scan.terms))
1762  && bitset_is_empty (&(plan->plan_un.scan.kf_terms)))
1763  {
1764  assert (!qo_is_iscan_from_groupby (plan));
1765  assert (!qo_is_iscan_from_orderby (plan));
1766 
1767  /* is not good index scan */
1768  qo_plan_release (plan);
1769  return NULL;
1770  }
1771  }
1772  }
1773  }
1774 
1775  /* check for no key-range, no key-filter index scan */
1776  if (qo_is_iscan (plan) && bitset_is_empty (&(plan->plan_un.scan.terms))
1777  && bitset_is_empty (&(plan->plan_un.scan.kf_terms)) && scan_method != QO_SCANMETHOD_INDEX_SCAN_INSPECT)
1778  {
1779  assert (!qo_is_iscan_from_groupby (plan));
1780  assert (!qo_is_iscan_from_orderby (plan));
1781 
1782  /* check for filter-index, loose index scan */
1783  if (qo_is_filter_index (index_entryp) || qo_is_index_loose_scan (plan))
1784  {
1785  /* filter index has a pre-defined key-range. */
1786  assert (bitset_is_empty (&(plan->plan_un.scan.terms)));
1787 
1788  ; /* go ahead */
1789  }
1790  else
1791  {
1792  assert (false);
1793  qo_plan_release (plan);
1794  return NULL;
1795  }
1796  }
1797 
1799  {
1800  bool dummy;
1801 
1803  plan->iscan_sort_list = qo_plan_compute_iscan_sort_list (plan, NULL, &dummy);
1804  }
1805 
1806  assert (plan->plan_un.scan.index != NULL);
1807 
1808  qo_plan_compute_cost (plan);
1809 
1810  plan = qo_top_plan_new (plan);
1811 
1812  return plan;
1813 }
1814 
1815 /*
1816  * qo_iscan_cost () -
1817  * return:
1818  * planp(in):
1819  */
1820 static void
1822 {
1823  QO_NODE *nodep;
1824  QO_NODE_INDEX_ENTRY *ni_entryp;
1825  QO_ATTR_CUM_STATS *cum_statsp;
1826  QO_INDEX_ENTRY *index_entryp;
1827  double sel, sel_limit, objects, height, leaves, opages;
1828  bool is_null_sel;
1829  double object_IO, index_IO;
1830  QO_TERM *termp;
1831  BITSET_ITERATOR iter;
1832  int i, t, n, pkeys_num;
1833 
1834  nodep = planp->plan_un.scan.node;
1835  ni_entryp = planp->plan_un.scan.index;
1836  index_entryp = (ni_entryp)->head;
1837  cum_statsp = &(ni_entryp)->cum_stats;
1838 
1839  if (index_entryp->force < 0)
1840  {
1841  assert (false);
1842  qo_worst_cost (planp);
1843  return;
1844  }
1845  else if (index_entryp->force > 0)
1846  {
1847  qo_zero_cost (planp);
1848  return;
1849  }
1850 
1851  n = index_entryp->col_num;
1852  if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (index_entryp->constraints->type) && n == index_entryp->nsegs)
1853  {
1854  assert (n > 0);
1855 
1856  for (i = 0; i < n; i++)
1857  {
1858  if (bitset_is_empty (&index_entryp->seg_equal_terms[i]))
1859  {
1860  break;
1861  }
1862  }
1863 
1864  if (i == n)
1865  {
1866  /* When the index is a unique family and all of index columns are specified in the equal conditions, the
1867  * cardinality of the scan will 0 or 1. In this case we will make the scan cost to zero, thus to force the
1868  * optimizer to select this scan.
1869  */
1870  qo_zero_cost (planp);
1871 
1872  index_entryp->all_unique_index_columns_are_equi_terms = true;
1873  return;
1874  }
1875  }
1876 
1877  /* selectivity of the index terms */
1878  sel = 1.0;
1879  is_null_sel = false;
1880 
1881  pkeys_num = MIN (n, cum_statsp->pkeys_size);
1882  assert (pkeys_num <= BTREE_STATS_PKEYS_NUM);
1883 
1884  if (bitset_is_empty (&(planp->plan_un.scan.terms)))
1885  {
1886  assert (!qo_is_index_iss_scan (planp));
1887  }
1888 
1889  sel_limit = 0.0; /* init */
1890 
1891  /* set selectivity limit */
1892  if (pkeys_num > 0 && cum_statsp->pkeys[0] > 1)
1893  {
1894  sel_limit = 1.0 / (double) cum_statsp->pkeys[0];
1895  }
1896  else
1897  {
1898  /* can not use btree partial-key statistics */
1899  if (cum_statsp->keys > 1)
1900  {
1901  sel_limit = 1.0 / (double) cum_statsp->keys;
1902  }
1903  else
1904  {
1905  if (QO_NODE_NCARD (nodep) == 0)
1906  { /* empty class */
1907  sel = 0.0;
1908  is_null_sel = true;
1909  }
1910  else if (QO_NODE_NCARD (nodep) > 1)
1911  {
1912  sel_limit = 1.0 / (double) QO_NODE_NCARD (nodep);
1913  }
1914  }
1915  }
1916 
1917  assert (sel_limit < 1.0);
1918 
1919  /* check lower bound */
1920  if (is_null_sel == false)
1921  {
1922  sel = MAX (sel, sel_limit);
1923  }
1924 
1925  assert ((is_null_sel == false && sel == 1.0) || (is_null_sel == true && sel == 0.0));
1926 
1927  if (!is_null_sel)
1928  {
1929  assert (QO_NODE_NCARD (nodep) > 0);
1930  i = 0;
1931 
1932  for (t = bitset_iterate (&(planp->plan_un.scan.terms), &iter); t != -1; t = bitset_next_member (&iter))
1933  {
1934  termp = QO_ENV_TERM (QO_NODE_ENV (nodep), t);
1935  sel *= QO_TERM_SELECTIVITY (termp);
1936 
1937  /* each term can have multi index column. e.g.) (a,b) in .. */
1938  for (int j = 0; j < index_entryp->col_num; j++)
1939  {
1940  if (BITSET_MEMBER (QO_TERM_SEGS (termp), index_entryp->seg_idxs[j]))
1941  {
1942  i++;
1943  }
1944  }
1945  }
1946  /* check upper bound */
1947  sel = MIN (sel, 1.0);
1948 
1949  sel_limit = 0.0; /* init */
1950 
1951  /* set selectivity limit */
1952  if (i < pkeys_num && cum_statsp->pkeys[i] > 1)
1953  {
1954  sel_limit = 1.0 / (double) cum_statsp->pkeys[i];
1955  }
1956  else
1957  { /* can not use btree partial-key statistics */
1958  if (cum_statsp->keys > 1)
1959  {
1960  sel_limit = 1.0 / (double) cum_statsp->keys;
1961  }
1962  else
1963  {
1964  if (QO_NODE_NCARD (nodep) > 1)
1965  {
1966  sel_limit = 1.0 / (double) QO_NODE_NCARD (nodep);
1967  }
1968  }
1969  }
1970 
1971  assert (sel_limit < 1.0);
1972 
1973  /* check lower bound */
1974  sel = MAX (sel, sel_limit);
1975  }
1976 
1977  assert ((is_null_sel == false) || (is_null_sel == true && sel == 0.0));
1978 
1979  /* number of objects to be selected */
1980  objects = sel * (double) QO_NODE_NCARD (nodep);
1981  /* height of the B+tree */
1982  height = (double) cum_statsp->height - 1;
1983  if (height < 0)
1984  {
1985  height = 0;
1986  }
1987  /* number of leaf pages to be accessed */
1988  leaves = ceil (sel * (double) cum_statsp->leafs);
1989  /* total number of pages occupied by objects */
1990  opages = (double) QO_NODE_TCARD (nodep);
1991  /* I/O cost to access B+tree index */
1992  index_IO = ((ni_entryp)->n * height) + leaves;
1993 
1994  /* Index Skip Scan adds to the index IO cost the K extra BTREE searches it does to fetch the next value for the
1995  * following BTRangeScan
1996  */
1997  if (qo_is_index_iss_scan (planp))
1998  {
1999  if (pkeys_num > 0)
2000  {
2001  assert (cum_statsp->pkeys != NULL);
2002  assert (cum_statsp->pkeys_size != 0);
2003 
2004  /* The btree is scanned an additional K times */
2005  index_IO += cum_statsp->pkeys[0] * ((ni_entryp)->n * height);
2006 
2007  /* K leaves are additionally read */
2008  index_IO += cum_statsp->pkeys[0];
2009  }
2010  }
2011 
2012  /* IO cost to fetch objects */
2013  if (sel < 0.3)
2014  {
2015  /* p = 1.0 (sel - 0.0) + 0.0 */
2016  object_IO = opages * sel;
2017  /* 0.0 <= sel < 0.3; 0 <= object_IO < opages * 0.3 */
2018  }
2019  else if (sel < 0.8)
2020  {
2021  /* p = ((1.0 - 0.6) / (0.8 - 0.3)) (sel - 0.3) + 0.6 = 0.8 sel + 0.36 */
2022  object_IO = opages * (0.8 * sel + 0.36);
2023  /* 0.3 <= selectivity < 0.8; opages * 0.6 <= object_IO < opages * 1.0 */
2024  }
2025  else
2026  {
2027  /* p = 0.0 (sel - 0.0) + 1.0 = 1.0 */
2028  object_IO = opages;
2029  /* 0.8 <= sel <= 1.0; object_IO = opages */
2030  }
2031 
2032  if (object_IO < 1.0)
2033  {
2034  /* at least one page */
2035  object_IO = 1.0;
2036  }
2037  else if ((double) prm_get_integer_value (PRM_ID_PB_NBUFFERS) - index_IO < object_IO)
2038  {
2039  object_IO =
2040  objects * (1.0 - (((double) prm_get_integer_value (PRM_ID_PB_NBUFFERS) - index_IO) / (double) opages));
2041  }
2042 
2043  if (sel < 1.0)
2044  { /* is not Full-Range sel */
2045  object_IO = ceil (FUDGE_FACTOR * object_IO);
2046  }
2047  object_IO = MAX (1.0, object_IO);
2048 
2049  /* index scan requires more CPU cost than sequential scan */
2050 
2051  planp->fixed_cpu_cost = 0.0;
2052  planp->fixed_io_cost = index_IO;
2053  planp->variable_cpu_cost = objects * (double) QO_CPU_WEIGHT *ISCAN_OVERHEAD_FACTOR;
2054  planp->variable_io_cost = object_IO;
2055 
2056  /* one page heap file; reconfig iscan cost */
2057  if (QO_NODE_TCARD (nodep) <= 1)
2058  {
2059  if (QO_NODE_NCARD (nodep) > 1)
2060  { /* index scan is worth */
2061  planp->fixed_io_cost = 0.0;
2062  }
2063  }
2064 }
2065 
2066 
2067 static void
2068 qo_scan_fprint (QO_PLAN * plan, FILE * f, int howfar)
2069 {
2070  bool natural_desc_index = false;
2071 
2072  if (plan->plan_un.scan.node->entity_spec->info.spec.cte_pointer)
2073  {
2074  PT_NODE *spec = plan->plan_un.scan.node->entity_spec;
2076  {
2077  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "recursive CTE: ");
2078  }
2079  else
2080  {
2081  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "simple CTE:");
2082  }
2083  }
2084  else
2085  {
2086  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "class:");
2087  }
2088 
2089  qo_node_fprint (plan->plan_un.scan.node, f);
2090 
2091  if (qo_is_interesting_order_scan (plan))
2092  {
2093  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "index: ");
2094  fprintf (f, "%s ", plan->plan_un.scan.index->head->constraints->name);
2095 
2096  /* print key limit */
2097  if (plan->plan_un.scan.index->head->key_limit)
2098  {
2099  PT_NODE *key_limit = plan->plan_un.scan.index->head->key_limit;
2100  PT_NODE *saved_next = key_limit->next;
2102  PT_PRINT_VALUE_FUNC saved_func = parser->print_db_value;
2103 
2105  if (saved_next)
2106  {
2107  saved_next->next = key_limit;
2108  key_limit->next = NULL;
2109  }
2110  fprintf (f, "keylimit %s ", parser_print_tree_list (parser, saved_next ? saved_next : key_limit));
2111  parser->print_db_value = saved_func;
2112  if (saved_next)
2113  {
2114  key_limit->next = saved_next;
2115  saved_next->next = NULL;
2116  }
2117  }
2118 
2119  qo_termset_fprint ((plan->info)->env, &plan->plan_un.scan.terms, f);
2120 
2121  /* print index covering */
2122  if (qo_is_index_covering_scan (plan))
2123  {
2124  if (bitset_cardinality (&(plan->plan_un.scan.terms)) > 0)
2125  {
2126  fprintf (f, " ");
2127  }
2128  fprintf (f, "(covers)");
2129  }
2130 
2131  if (qo_is_index_iss_scan (plan))
2132  {
2133  fprintf (f, " (index skip scan)");
2134  }
2135 
2136  if (qo_is_index_loose_scan (plan))
2137  {
2138  fprintf (f, " (loose index scan on prefix %d)", plan->plan_un.scan.index->head->ils_prefix_len);
2139  }
2140 
2141  if (qo_plan_multi_range_opt (plan))
2142  {
2143  fprintf (f, " (multi_range_opt)");
2144  }
2145 
2146  if (plan->plan_un.scan.index && plan->plan_un.scan.index->head->use_descending)
2147  {
2148  fprintf (f, " (desc_index)");
2149  natural_desc_index = true;
2150  }
2151 
2152  if (!natural_desc_index && (QO_ENV_PT_TREE (plan->info->env)->info.query.q.select.hint & PT_HINT_USE_IDX_DESC))
2153  {
2154  fprintf (f, " (desc_index forced)");
2155  }
2156 
2157  if (!bitset_is_empty (&(plan->plan_un.scan.kf_terms)))
2158  {
2159  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "filtr: ");
2160  qo_termset_fprint ((plan->info)->env, &(plan->plan_un.scan.kf_terms), f);
2161  }
2162  }
2163 }
2164 
2165 /*
2166  * qo_scan_info () -
2167  * return:
2168  * plan(in):
2169  * f(in):
2170  * howfar(in):
2171  */
2172 static void
2173 qo_scan_info (QO_PLAN * plan, FILE * f, int howfar)
2174 {
2175  QO_NODE *node = plan->plan_un.scan.node;
2176  int i, n = 1;
2177  const char *name;
2178 
2179  fprintf (f, "\n%*c%s(", (int) howfar, ' ', (plan->vtbl)->info_string);
2180  if (QO_NODE_INFO (node))
2181  {
2182  for (i = 0, n = QO_NODE_INFO_N (node); i < n; i++)
2183  {
2184  name = QO_NODE_INFO (node)->info[i].name;
2185  fprintf (f, "%s ", (name ? name : "(anon)"));
2186  }
2187  }
2188  name = QO_NODE_NAME (node);
2189  if (n == 1)
2190  {
2191  fprintf (f, "%s", (name ? name : "(unknown)"));
2192  }
2193  else
2194  {
2195  fprintf (f, "as %s", (name ? name : "(unknown)"));
2196  }
2197 
2198  if (qo_is_iscan (plan) || qo_is_iscan_from_orderby (plan))
2199  {
2200  BITSET_ITERATOR bi;
2201  QO_ENV *env;
2202  int i;
2203  const char *separator;
2204  bool natural_desc_index = false;
2205 
2206  env = (plan->info)->env;
2207  separator = ", ";
2208 
2209  fprintf (f, "%s%s", separator, plan->plan_un.scan.index->head->constraints->name);
2210 
2211  /* print key limit */
2212  if (plan->plan_un.scan.index->head->key_limit)
2213  {
2214  PT_NODE *key_limit = plan->plan_un.scan.index->head->key_limit;
2215  PT_NODE *saved_next = key_limit->next;
2217  PT_PRINT_VALUE_FUNC saved_func = parser->print_db_value;
2219  if (saved_next)
2220  {
2221  saved_next->next = key_limit;
2222  key_limit->next = NULL;
2223  }
2224  fprintf (f, "(keylimit %s) ", parser_print_tree_list (parser, saved_next ? saved_next : key_limit));
2225  parser->print_db_value = saved_func;
2226  if (saved_next)
2227  {
2228  key_limit->next = saved_next;
2229  saved_next->next = NULL;
2230  }
2231  }
2232 
2233  for (i = bitset_iterate (&(plan->plan_un.scan.terms), &bi); i != -1; i = bitset_next_member (&bi))
2234  {
2235  fprintf (f, "%s%s", separator, qo_term_string (QO_ENV_TERM (env, i)));
2236  separator = " and ";
2237  }
2238  if (bitset_cardinality (&(plan->plan_un.scan.kf_terms)) > 0)
2239  {
2240  separator = ", [";
2241  for (i = bitset_iterate (&(plan->plan_un.scan.kf_terms), &bi); i != -1; i = bitset_next_member (&bi))
2242  {
2243  fprintf (f, "%s%s", separator, qo_term_string (QO_ENV_TERM (env, i)));
2244  separator = " and ";
2245  }
2246  fprintf (f, "]");
2247  }
2248 
2249  /* print index covering */
2250  if (qo_is_index_covering_scan (plan))
2251  {
2252  fprintf (f, " (covers)");
2253  }
2254 
2255  if (qo_is_index_iss_scan (plan))
2256  {
2257  fprintf (f, " (index skip scan)");
2258  }
2259 
2260  if (qo_is_index_loose_scan (plan))
2261  {
2262  fprintf (f, " (loose index scan on prefix %d)", plan->plan_un.scan.index->head->ils_prefix_len);
2263  }
2264 
2265  if (qo_plan_multi_range_opt (plan))
2266  {
2267  fprintf (f, " (multi_range_opt)");
2268  }
2269 
2270  if (plan->plan_un.scan.index && plan->plan_un.scan.index->head->use_descending)
2271  {
2272  fprintf (f, " (desc_index)");
2273  natural_desc_index = true;
2274  }
2275 
2276  if (!natural_desc_index && (QO_ENV_PT_TREE (plan->info->env)->info.query.q.select.hint & PT_HINT_USE_IDX_DESC))
2277  {
2278  fprintf (f, " (desc_index forced)");
2279  }
2280  }
2281 
2282  fprintf (f, ")");
2283 }
2284 
2285 
2286 /*
2287  * qo_sort_new () -
2288  * return:
2289  * root(in):
2290  * order(in):
2291  * sort_type(in):
2292  */
2293 static QO_PLAN *
2294 qo_sort_new (QO_PLAN * root, QO_EQCLASS * order, SORT_TYPE sort_type)
2295 {
2296  QO_PLAN *subplan, *plan;
2297 
2298  subplan = root;
2299 
2300  if (sort_type == SORT_TEMP)
2301  { /* is not top-level plan */
2302  /* skip out top-level sort plan */
2303  for (; subplan && subplan->plan_type == QO_PLANTYPE_SORT && subplan->plan_un.sort.sort_type != SORT_LIMIT;
2304  subplan = subplan->plan_un.sort.subplan)
2305  {
2306  if (subplan->top_rooted && subplan->plan_un.sort.sort_type != SORT_TEMP)
2307  {
2308  ; /* skip and go ahead */
2309  }
2310  else
2311  {
2312  break; /* is not top-level sort plan */
2313  }
2314  }
2315 
2316  /* check for dummy sort plan */
2317  if (order == QO_UNORDERED && subplan != NULL && subplan->plan_type == QO_PLANTYPE_SORT)
2318  {
2319  return qo_plan_add_ref (root);
2320  }
2321 
2322  /* skip out empty sort plan */
2323  for (; subplan && subplan->plan_type == QO_PLANTYPE_SORT && subplan->plan_un.sort.sort_type != SORT_LIMIT;
2324  subplan = subplan->plan_un.sort.subplan)
2325  {
2326  if (!bitset_is_empty (&(subplan->sarged_terms)))
2327  {
2328  break;
2329  }
2330  }
2331  }
2332 
2333  if (subplan == NULL)
2334  {
2335  return NULL;
2336  }
2337 
2338  plan = qo_plan_malloc ((subplan->info)->env);
2339  if (plan == NULL)
2340  {
2341  return NULL;
2342  }
2343 
2344  plan->info = subplan->info;
2345  plan->refcount = 0;
2346  plan->top_rooted = subplan->top_rooted;
2347  plan->well_rooted = false;
2348  plan->iscan_sort_list = NULL;
2349  plan->analytic_eval_list = NULL;
2350  plan->order = order;
2351  plan->plan_type = QO_PLANTYPE_SORT;
2352  plan->vtbl = &qo_sort_plan_vtbl;
2353 
2354  plan->plan_un.sort.sort_type = sort_type;
2355  plan->plan_un.sort.subplan = qo_plan_add_ref (subplan);
2356  plan->plan_un.sort.xasl = NULL; /* To be determined later */
2357 
2359  plan->has_sort_limit = (sort_type == SORT_LIMIT);
2360 
2361  qo_plan_compute_cost (plan);
2362 
2363  plan = qo_top_plan_new (plan);
2364 
2365  return plan;
2366 }
2367 
2368 /*
2369  * qo_sort_walk () -
2370  * return:
2371  * plan(in):
2372  * child_fn(in):
2373  * child_data(in):
2374  * parent_fn(in):
2375  * parent_data(in):
2376  */
2377 static void
2378 qo_sort_walk (QO_PLAN * plan, void (*child_fn) (QO_PLAN *, void *), void *child_data,
2379  void (*parent_fn) (QO_PLAN *, void *), void *parent_data)
2380 {
2381  if (child_fn)
2382  {
2383  (*child_fn) (plan->plan_un.sort.subplan, child_data);
2384  }
2385  if (parent_fn)
2386  {
2387  (*parent_fn) (plan, parent_data);
2388  }
2389 }
2390 
2391 static void
2392 qo_sort_fprint (QO_PLAN * plan, FILE * f, int howfar)
2393 {
2394  switch (plan->plan_un.sort.sort_type)
2395  {
2396  case SORT_TEMP:
2397  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "order:");
2398  qo_eqclass_fprint_wrt (plan->order, &(plan->info->nodes), f);
2399  break;
2400 
2401  case SORT_LIMIT:
2402  fprintf (f, "(sort limit)");
2403  break;
2404 
2405  case SORT_GROUPBY:
2406  fprintf (f, "(group by)");
2407  break;
2408 
2409  case SORT_ORDERBY:
2410  fprintf (f, "(order by)");
2411  break;
2412 
2413  case SORT_DISTINCT:
2414  fprintf (f, "(distinct)");
2415  break;
2416 
2417  default:
2418  break;
2419  }
2420 
2421  qo_plan_fprint (plan->plan_un.sort.subplan, f, howfar, "subplan: ");
2422 }
2423 
2424 /*
2425  * qo_sort_info () -
2426  * return:
2427  * plan(in):
2428  * f(in):
2429  * howfar(in):
2430  */
2431 static void
2432 qo_sort_info (QO_PLAN * plan, FILE * f, int howfar)
2433 {
2434 
2435  switch (plan->plan_un.sort.sort_type)
2436  {
2437  case SORT_TEMP:
2438  if (plan->order != QO_UNORDERED)
2439  {
2440 #if 0
2441  /*
2442  * Don't bother printing these out; they're almost always
2443  * superfluous from the standpoint of a naive user trying to
2444  * figure out what's going on.
2445  */
2446  fprintf (f, "\n%*c%s(", (int) howfar, ' ', (plan->vtbl)->info_string);
2447  qo_eqclass_fprint_wrt (plan->order, &(plan->info->nodes), f);
2448  fprintf (f, ")");
2449 #endif
2450  }
2451  break;
2452  case SORT_LIMIT:
2453  fprintf (f, "\n%*c%s(%s)", (int) howfar, ' ', (plan->vtbl)->info_string, "sort limit");
2454  howfar += INDENT_INCR;
2455  break;
2456  case SORT_GROUPBY:
2457  fprintf (f, "\n%*c%s(%s)", (int) howfar, ' ', (plan->vtbl)->info_string, "group by");
2458  howfar += INDENT_INCR;
2459  break;
2460 
2461  case SORT_ORDERBY:
2462  fprintf (f, "\n%*c%s(%s)", (int) howfar, ' ', (plan->vtbl)->info_string, "order by");
2463  howfar += INDENT_INCR;
2464  break;
2465 
2466  case SORT_DISTINCT:
2467  fprintf (f, "\n%*c%s(%s)", (int) howfar, ' ', (plan->vtbl)->info_string, "distinct");
2468  howfar += INDENT_INCR;
2469  break;
2470 
2471  default:
2472  break;
2473  }
2474 
2475  qo_plan_lite_print (plan->plan_un.sort.subplan, f, howfar);
2476 }
2477 
2478 /*
2479  * qo_sort_cost () -
2480  * return:
2481  * planp(in):
2482  */
2483 static void
2485 {
2486  QO_PLAN *subplanp;
2487 
2488  subplanp = planp->plan_un.sort.subplan;
2489 
2490  /* for worst cost */
2491  if (subplanp->fixed_cpu_cost == QO_INFINITY || subplanp->fixed_io_cost == QO_INFINITY
2492  || subplanp->variable_cpu_cost == QO_INFINITY || subplanp->variable_io_cost == QO_INFINITY)
2493  {
2494  qo_worst_cost (planp);
2495  return;
2496  }
2497 
2498  if (subplanp->plan_type == QO_PLANTYPE_SORT && planp->plan_un.sort.sort_type == SORT_TEMP)
2499  {
2500  /* This plan won't actually incur any runtime cost because it won't actually exist (its sort spec will supersede
2501  * the sort spec of the subplan). We can't just clobber the sort spec on the lower plan because it might be
2502  * shared by others.
2503  */
2504  planp->fixed_cpu_cost = subplanp->fixed_cpu_cost;
2505  planp->fixed_io_cost = subplanp->fixed_io_cost;
2506  planp->variable_cpu_cost = subplanp->variable_cpu_cost;
2507  planp->variable_io_cost = subplanp->variable_io_cost;
2508  }
2509  else if (planp->plan_un.sort.sort_type == SORT_LIMIT)
2510  {
2511  if (subplanp->plan_type == QO_PLANTYPE_SORT)
2512  {
2513  /* No sense in having a STOP plan above a SORT plan */
2514  qo_worst_cost (planp);
2515  }
2516 
2517  /* SORT-LIMIT plan has the same cost as the subplan (since actually sorting items in memory is not a big
2518  * drawback. Costs improvements will be applied when we consider joining this plan with other plans
2519  */
2520  planp->fixed_cpu_cost = subplanp->fixed_cpu_cost;
2521  planp->fixed_io_cost = subplanp->fixed_io_cost;
2522  planp->variable_cpu_cost = subplanp->variable_cpu_cost;
2523  planp->variable_io_cost = subplanp->variable_io_cost;
2524  }
2525  else
2526  {
2527  QO_EQCLASS *order;
2528  double objects, pages, result_size;
2529 
2530  order = planp->order;
2531  objects = (subplanp->info)->cardinality;
2532  result_size = objects * (double) (subplanp->info)->projected_size;
2533  pages = result_size / (double) IO_PAGESIZE;
2534  if (pages < 1.0)
2535  {
2536  pages = 1.0;
2537  }
2538 
2539  /* The cost (in io's) of just setting up a list file. This is mostly to discourage the optimizer from choosing
2540  * merge join for joins of little classes.
2541  */
2542  planp->fixed_cpu_cost = subplanp->fixed_cpu_cost + subplanp->variable_cpu_cost + TEMP_SETUP_COST;
2543  planp->fixed_io_cost = subplanp->fixed_io_cost + subplanp->variable_io_cost;
2544  planp->variable_cpu_cost = objects * (double) QO_CPU_WEIGHT;
2545  planp->variable_io_cost = pages;
2546 
2547  if (order != QO_UNORDERED && order != subplanp->order)
2548  {
2549  double sort_io, tcard;
2550 
2551  sort_io = 0.0; /* init */
2552 
2553  if (objects > 1.0)
2554  {
2555  if (pages < (double) prm_get_integer_value (PRM_ID_SR_NBUFFERS))
2556  {
2557  /* We can sort the result in memory without any additional io costs. Assume cpu costs are n*log(n) in
2558  * number of recors.
2559  */
2560  sort_io = (double) QO_CPU_WEIGHT *objects * log2 (objects);
2561  }
2562  else
2563  {
2564  /* There are too many records to permit an in-memory sort, so io costs will be increased. Assume
2565  * that the io costs increase by the number of pages required to hold the intermediate result. CPU
2566  * costs increase as above. Model courtesy of Ender.
2567  */
2568  sort_io = pages * log3 (pages / 4.0);
2569 
2570  /* guess: apply IO caching for big size sort list. Disk IO cost cannot be greater than the 10% number
2571  * of the requested IO pages
2572  */
2573  if (subplanp->plan_type == QO_PLANTYPE_SCAN)
2574  {
2575  tcard = (double) QO_NODE_TCARD (subplanp->plan_un.scan.node);
2576  tcard *= 0.1;
2577  if (pages >= tcard)
2578  { /* big size sort list */
2579  sort_io *= 0.1;
2580  }
2581  }
2582  }
2583  }
2584 
2585  planp->fixed_io_cost += sort_io;
2586  }
2587  }
2588 }
2589 
2590 /*
2591  * qo_join_new () -
2592  * return:
2593  * info(in):
2594  * join_type(in):
2595  * join_method(in):
2596  * outer(in):
2597  * inner(in):
2598  * join_terms(in):
2599  * duj_terms(in):
2600  * afj_terms(in):
2601  * sarged_terms(in):
2602  * pinned_subqueries(in):
2603  */
2604 static QO_PLAN *
2605 qo_join_new (QO_INFO * info, JOIN_TYPE join_type, QO_JOINMETHOD join_method, QO_PLAN * outer, QO_PLAN * inner,
2606  BITSET * join_terms, BITSET * duj_terms, BITSET * afj_terms, BITSET * sarged_terms,
2607  BITSET * pinned_subqueries, BITSET * hash_terms)
2608 {
2609  QO_PLAN *plan = NULL;
2610  QO_NODE *node = NULL;
2611  PT_NODE *spec = NULL;
2612  BITSET sarg_out_terms;
2613 
2614  bitset_init (&sarg_out_terms, info->env);
2615 
2616  if (inner->has_sort_limit && join_method != QO_JOINMETHOD_MERGE_JOIN)
2617  {
2618  /* SORT-LIMIT plans are allowed on inner nodes only for merge joins */
2619  return NULL;
2620  }
2621 
2622  plan = qo_plan_malloc (info->env);
2623  if (plan == NULL)
2624  {
2625  return NULL;
2626  }
2627 
2628  QO_ASSERT (info->env, outer != NULL);
2629  QO_ASSERT (info->env, inner != NULL);
2630 
2631  plan->info = info;
2632  plan->refcount = 0;
2633  plan->top_rooted = false;
2634  plan->well_rooted = false;
2635  plan->iscan_sort_list = NULL;
2636  plan->analytic_eval_list = NULL;
2637  plan->plan_type = QO_PLANTYPE_JOIN;
2639  plan->has_sort_limit = (outer->has_sort_limit || inner->has_sort_limit);
2640 
2641  switch (join_method)
2642  {
2643 
2644  case QO_JOINMETHOD_NL_JOIN:
2646  if (join_method == QO_JOINMETHOD_NL_JOIN)
2647  {
2648  plan->vtbl = &qo_nl_join_plan_vtbl;
2649  }
2650  else
2651  {
2652  plan->vtbl = &qo_idx_join_plan_vtbl;
2653  }
2654  plan->order = QO_UNORDERED;
2655 
2656  /* These checks are necessary because of restrictions in the current XASL implementation of nested loop joins.
2657  * Never put anything on the inner plan that isn't file-based (i.e., a scan of either a heap file or a list
2658  * file).
2659  */
2660  if (!VALID_INNER (inner))
2661  {
2662  inner = qo_sort_new (inner, inner->order, SORT_TEMP);
2663  }
2664  else if (IS_OUTER_JOIN_TYPE (join_type))
2665  {
2666  /* for outer join, if inner plan is a scan of classes in hierarchy */
2667  if (inner->plan_type == QO_PLANTYPE_SCAN && QO_NODE_IS_CLASS_HIERARCHY (inner->plan_un.scan.node))
2668  {
2669  inner = qo_sort_new (inner, inner->order, SORT_TEMP);
2670  }
2671  }
2672 
2673  break;
2674 
2676 
2677  plan->vtbl = &qo_merge_join_plan_vtbl;
2678 #if 0
2679  /* Don't do this anymore; it relies on symmetry, which definitely doesn't apply anymore with the advent of outer
2680  * joins.
2681  */
2682 
2683  /* Arrange to always put the smallest cardinality on the outer term; this may lead to some savings given the
2684  * current merge join implementation.
2685  */
2686  if ((inner->info)->cardinality < (outer->info)->cardinality)
2687  {
2688  QO_PLAN *tmp;
2689  tmp = inner;
2690  inner = outer;
2691  outer = tmp;
2692  }
2693 #endif
2694 
2695  /* The merge join result has the same nominal order as the two subjoins that feed it. However, if it happens
2696  * that none of the segments in that order are to be projected from the result, the result is effectively
2697  * *unordered*. Check for that condition here.
2698  */
2699  plan->order =
2701  &((plan->info)->projected_segs)) ? outer->order : QO_UNORDERED;
2702 
2703  /* The current implementation of merge joins always produces a list file These two checks are necessary because
2704  * of restrictions in the current XASL implementation of merge joins.
2705  */
2706  if (outer->plan_type != QO_PLANTYPE_SORT)
2707  {
2708  outer = qo_sort_new (outer, outer->order, SORT_TEMP);
2709  }
2710  if (inner->plan_type != QO_PLANTYPE_SORT)
2711  {
2712  inner = qo_sort_new (inner, inner->order, SORT_TEMP);
2713  }
2714 
2715  break;
2716  }
2717 
2718  assert (inner != NULL && outer != NULL);
2719  if (inner == NULL || outer == NULL)
2720  {
2721  return NULL;
2722  }
2723 
2724  node = QO_ENV_NODE (info->env, bitset_first_member (&((inner->info)->nodes)));
2725 
2726  assert (node != NULL);
2727  if (node == NULL)
2728  {
2729  return NULL;
2730  }
2731 
2732  /* check for cselect of method */
2733  spec = QO_NODE_ENTITY_SPEC (node);
2734  if (spec && spec->info.spec.flat_entity_list == NULL && spec->info.spec.derived_table_type == PT_IS_CSELECT)
2735  {
2736  /* mark as cselect join */
2737  plan->plan_un.join.join_type = JOIN_CSELECT;
2738  }
2739  else
2740  {
2741  plan->plan_un.join.join_type = join_type;
2742  }
2743 
2744  plan->plan_un.join.join_method = join_method;
2745  plan->plan_un.join.outer = qo_plan_add_ref (outer);
2746  plan->plan_un.join.inner = qo_plan_add_ref (inner);
2747 
2748  bitset_init (&(plan->plan_un.join.join_terms), info->env);
2749  bitset_init (&(plan->plan_un.join.during_join_terms), info->env);
2750  bitset_init (&(plan->plan_un.join.after_join_terms), info->env);
2751  bitset_init (&(plan->plan_un.join.hash_terms), info->env);
2752 
2753  /* set join terms */
2754  bitset_assign (&(plan->plan_un.join.join_terms), join_terms);
2755  /* set hash terms */
2756  bitset_assign (&(plan->plan_un.join.hash_terms), hash_terms);
2757  /* add to out terms */
2758  bitset_union (&sarg_out_terms, &(plan->plan_un.join.join_terms));
2759 
2760  if (IS_OUTER_JOIN_TYPE (join_type))
2761  {
2762  /* set during join terms */
2763  bitset_assign (&(plan->plan_un.join.during_join_terms), duj_terms);
2764  bitset_difference (&(plan->plan_un.join.during_join_terms), &sarg_out_terms);
2765  /* add to out terms */
2766  bitset_union (&sarg_out_terms, &(plan->plan_un.join.during_join_terms));
2767 
2768  /* set after join terms */
2769  bitset_assign (&(plan->plan_un.join.after_join_terms), afj_terms);
2770  bitset_difference (&(plan->plan_un.join.after_join_terms), &sarg_out_terms);
2771  /* add to out terms */
2772  bitset_union (&sarg_out_terms, &(plan->plan_un.join.after_join_terms));
2773  }
2774 
2775  /* set plan's sarged terms */
2776  bitset_assign (&(plan->sarged_terms), sarged_terms);
2777  bitset_difference (&(plan->sarged_terms), &sarg_out_terms);
2778 
2779  /* Make sure that the pinned subqueries and the sargs are placed on the same node: by now the pinned subqueries are
2780  * very likely pinned here precisely because they're used by these sargs. Separating them (so that they get evaluated
2781  * in some different order) will yield incorrect results.
2782  */
2783  bitset_assign (&(plan->subqueries), pinned_subqueries);
2784 
2786  {
2787  bool dummy;
2788 
2790  plan->iscan_sort_list = qo_plan_compute_iscan_sort_list (plan, NULL, &dummy);
2791  }
2792 
2793  qo_plan_compute_cost (plan);
2794 
2795  if (QO_ENV_USE_SORT_LIMIT (info->env) && !plan->has_sort_limit
2796  && bitset_is_equivalent (&info->env->sort_limit_nodes, &info->nodes))
2797  {
2798  /* Consider creating a SORT_LIMIT plan over this plan only if it cannot skip order by. Since we know that we
2799  * already have all ORDER BY nodes in this plan, we can verify orderby_skip at this point
2800  */
2802  {
2803  plan = qo_sort_new (plan, QO_UNORDERED, SORT_LIMIT);
2804  if (plan == NULL)
2805  {
2806  return NULL;
2807  }
2808  }
2809  }
2810 
2811 #if 1 /* MERGE_ALWAYS_MAKES_LISTFILE */
2812  /* This is necessary to get the proper cost model for merge joins, which always build their result into a listfile
2813  * right now. At the moment the cost model for a merge plan just models the cost of producing the result tuples, but
2814  * not storing them into a listfile. We could push the cost into the merge plan itself, I suppose, but a rational
2815  * implementation wouldn't impose this cost, and so I have hope that one day we'll be able to eliminate it.
2816  */
2817  if (join_method == QO_JOINMETHOD_MERGE_JOIN)
2818  {
2819  plan = qo_sort_new (plan, plan->order, SORT_TEMP);
2820  }
2821 #endif /* MERGE_ALWAYS_MAKES_LISTFILE */
2822 
2823  bitset_delset (&sarg_out_terms);
2824 
2825  plan = qo_top_plan_new (plan);
2826 
2827  return plan;
2828 }
2829 
2830 /*
2831  * qo_join_free () -
2832  * return:
2833  * plan(in):
2834  */
2835 static void
2837 {
2838  bitset_delset (&(plan->plan_un.join.join_terms));
2839  bitset_delset (&(plan->plan_un.join.during_join_terms));
2840  bitset_delset (&(plan->plan_un.join.after_join_terms));
2841 }
2842 
2843 /*
2844  * qo_join_walk () -
2845  * return:
2846  * plan(in):
2847  * child_fn(in):
2848  * child_data(in):
2849  * parent_fn(in):
2850  * parent_data(in):
2851  */
2852 static void
2853 qo_join_walk (QO_PLAN * plan, void (*child_fn) (QO_PLAN *, void *), void *child_data,
2854  void (*parent_fn) (QO_PLAN *, void *), void *parent_data)
2855 {
2856  if (child_fn)
2857  {
2858  (*child_fn) (plan->plan_un.join.outer, child_data);
2859  (*child_fn) (plan->plan_un.join.inner, child_data);
2860  }
2861  if (parent_fn)
2862  {
2863  (*parent_fn) (plan, parent_data);
2864  }
2865 }
2866 
2867 /*
2868  * qo_join_fprint () -
2869  * return:
2870  * plan(in):
2871  * f(in):
2872  * howfar(in):
2873  */
2874 static void
2875 qo_join_fprint (QO_PLAN * plan, FILE * f, int howfar)
2876 {
2877  switch (plan->plan_un.join.join_type)
2878  {
2879  case JOIN_INNER:
2880  if (!bitset_is_empty (&(plan->plan_un.join.join_terms)))
2881  {
2882  fputs (" (inner join)", f);
2883  }
2884  else
2885  {
2886  if (plan->plan_un.join.join_method == QO_JOINMETHOD_IDX_JOIN)
2887  {
2888  fputs (" (inner join)", f);
2889  }
2890  else
2891  {
2892  fputs (" (cross join)", f);
2893  }
2894  }
2895  break;
2896  case JOIN_LEFT:
2897  fputs (" (left outer join)", f);
2898  break;
2899  case JOIN_RIGHT:
2900  fputs (" (right outer join)", f);
2901  break;
2902  case JOIN_OUTER: /* not used */
2903  fputs (" (full outer join)", f);
2904  break;
2905  case JOIN_CSELECT:
2906  fputs (" (cselect join)", f);
2907  break;
2908  case NO_JOIN:
2909  default:
2910  fputs (" (unknown join type)", f);
2911  break;
2912  }
2913  if (!bitset_is_empty (&(plan->plan_un.join.join_terms)))
2914  {
2915  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "edge:");
2916  qo_termset_fprint ((plan->info)->env, &(plan->plan_un.join.join_terms), f);
2917  }
2918  qo_plan_fprint (plan->plan_un.join.outer, f, howfar, "outer: ");
2919  qo_plan_fprint (plan->plan_un.join.inner, f, howfar, "inner: ");
2920  qo_plan_print_outer_join_terms (plan, f, howfar);
2921 }
2922 
2923 /*
2924  * qo_join_info () -
2925  * return:
2926  * plan(in):
2927  * f(in):
2928  * howfar(in):
2929  */
2930 static void
2931 qo_join_info (QO_PLAN * plan, FILE * f, int howfar)
2932 {
2933  if (!bitset_is_empty (&(plan->plan_un.join.join_terms)))
2934  {
2935  QO_ENV *env;
2936  const char *separator;
2937  int i;
2938  BITSET_ITERATOR bi;
2939 
2940  env = (plan->info)->env;
2941  separator = "";
2942 
2943  fprintf (f, "\n%*c%s(", (int) howfar, ' ', (plan->vtbl)->info_string);
2944  for (i = bitset_iterate (&(plan->plan_un.join.join_terms), &bi); i != -1; i = bitset_next_member (&bi))
2945  {
2946  fprintf (f, "%s%s", separator, qo_term_string (QO_ENV_TERM (env, i)));
2947  separator = " and ";
2948  }
2949  fprintf (f, ")");
2950  }
2951  else
2952  {
2953  fprintf (f, "\n%*cNested loops", (int) howfar, ' ');
2954  }
2955 
2956  if (plan->plan_un.join.join_type == JOIN_LEFT)
2957  {
2958  fprintf (f, ": left outer");
2959  }
2960  else if (plan->plan_un.join.join_type == JOIN_RIGHT)
2961  {
2962  fprintf (f, ": right outer");
2963  }
2964 
2965  qo_plan_lite_print (plan->plan_un.join.outer, f, howfar + INDENT_INCR);
2966  qo_plan_lite_print (plan->plan_un.join.inner, f, howfar + INDENT_INCR);
2967 }
2968 
2969 
2970 /*
2971  * qo_nljoin_cost () -
2972  * return:
2973  * planp(in):
2974  */
2975 static void
2977 {
2978  QO_PLAN *inner, *outer;
2979  double inner_io_cost, inner_cpu_cost, outer_io_cost, outer_cpu_cost;
2980  double pages, guessed_result_cardinality;
2981  double pages2, io_cost, diff_cost;
2982 
2983  inner = planp->plan_un.join.inner;
2984 
2985  /* for worst cost */
2986  if (inner->fixed_cpu_cost == QO_INFINITY || inner->fixed_io_cost == QO_INFINITY
2987  || inner->variable_cpu_cost == QO_INFINITY || inner->variable_io_cost == QO_INFINITY)
2988  {
2989  qo_worst_cost (planp);
2990  return;
2991  }
2992 
2993  outer = planp->plan_un.join.outer;
2994 
2995  /* for worst cost */
2996  if (outer->fixed_cpu_cost == QO_INFINITY || outer->fixed_io_cost == QO_INFINITY
2997  || outer->variable_cpu_cost == QO_INFINITY || outer->variable_io_cost == QO_INFINITY)
2998  {
2999  qo_worst_cost (planp);
3000  return;
3001  }
3002 
3003  /* CPU and IO costs which are fixed againt join */
3004  planp->fixed_cpu_cost = outer->fixed_cpu_cost + inner->fixed_cpu_cost;
3005  planp->fixed_io_cost = outer->fixed_io_cost + inner->fixed_io_cost;
3006 
3007  /* inner side CPU cost of nested-loop block join */
3008  if (outer->plan_type == QO_PLANTYPE_SORT && outer->plan_un.sort.sort_type == SORT_LIMIT)
3009  {
3010  /* cardinality of a SORT_LIMIT plan is given by the value of the query limit */
3011  guessed_result_cardinality = (double) db_get_bigint (&QO_ENV_LIMIT_VALUE (outer->info->env));
3012  }
3013  else
3014  {
3015  guessed_result_cardinality = (outer->info)->cardinality;
3016  }
3017  inner_cpu_cost = guessed_result_cardinality * (double) QO_CPU_WEIGHT;
3018  /* join cost */
3019 
3020  if (qo_is_iscan (inner) && inner->plan_un.scan.index_equi == true)
3021  {
3022  /* correlated index equi-join */
3023  inner_cpu_cost += inner->variable_cpu_cost;
3025  && guessed_result_cardinality > prm_get_integer_value (PRM_ID_MAX_OUTER_CARD_OF_IDXJOIN))
3026  {
3027  planp->variable_cpu_cost = QO_INFINITY;
3028  planp->variable_io_cost = QO_INFINITY;
3029  return;
3030  }
3031  }
3032  else
3033  {
3034  /* neither correlated index join nor equi-join */
3035  inner_cpu_cost += MAX (1.0, (outer->info)->cardinality) * inner->variable_cpu_cost;
3036  }
3037 
3038  /* inner side IO cost of nested-loop block join */
3039  inner_io_cost = outer->variable_io_cost * inner->variable_io_cost; /* assume IO as # blocks */
3040  if (inner->plan_type == QO_PLANTYPE_SCAN)
3041  {
3042  pages = QO_NODE_TCARD (inner->plan_un.scan.node);
3043  if (inner_io_cost > pages * 2)
3044  {
3045  /* inner IO cost cannot be greater than two times of the number of pages of the class because buffering */
3046  inner_io_cost = pages * 2;
3047 
3048  /* for iscan of inner, reconfig inner_io_cost */
3049  inner_io_cost -= inner->fixed_io_cost;
3050  inner_io_cost = MAX (0.0, inner_io_cost);
3051 
3052  }
3053 
3054  if (qo_is_seq_scan (outer) && qo_is_seq_scan (inner))
3055  {
3056  if ((outer->info)->cardinality == (inner->info)->cardinality)
3057  {
3058  pages2 = QO_NODE_TCARD (outer->plan_un.scan.node);
3059  /* exclude too many heavy-sequential scan nl-join - sscan (small) + sscan (big) */
3060  if (pages > pages2)
3061  {
3062  io_cost = (inner->variable_io_cost + MIN (inner_io_cost, pages2 * 2));
3063  diff_cost = io_cost - (outer->variable_io_cost + inner_io_cost);
3064  if (diff_cost > 0)
3065  {
3066  inner_io_cost += diff_cost + 0.1;
3067  }
3068  }
3069  }
3070  }
3071 
3072  if (planp->plan_un.join.join_type != JOIN_INNER)
3073  {
3074  /* outer join leads nongrouped scan overhead */
3075  inner_cpu_cost += ((outer->info)->cardinality * pages * NONGROUPED_SCAN_COST);
3076  }
3077  }
3078 
3079  if (inner->plan_type == QO_PLANTYPE_SORT)
3080  {
3081  /* (inner->plan_un.sort.subplan)->info == inner->info */
3082  pages = ((inner->info)->cardinality * (inner->info)->projected_size) / IO_PAGESIZE;
3083  if (pages < 1)
3084  pages = 1;
3085 
3086  pages2 = pages * 2;
3087  if (inner_io_cost > pages2)
3088  {
3089  diff_cost = inner_io_cost - pages2;
3090 
3091  /* inner IO cost cannot be greater than two times of the number of pages of the list file */
3092  inner_io_cost = pages2;
3093 
3094  /* The cost (in io's) of just handling a list file. This is mostly to discourage the optimizer from choosing
3095  * nl-join with temp inner for joins of little classes.
3096  */
3097  io_cost = inner->fixed_io_cost * 0.1;
3098  diff_cost = MIN (io_cost, diff_cost);
3099  planp->fixed_io_cost += diff_cost + 0.1;
3100  }
3101 
3102  inner_cpu_cost += (outer->info)->cardinality * pages * NONGROUPED_SCAN_COST;
3103 
3104  }
3105 
3106  /* outer side CPU cost of nested-loop block join */
3107  outer_cpu_cost = outer->variable_cpu_cost;
3108  /* outer side IO cost of nested-loop block join */
3109  outer_io_cost = outer->variable_io_cost;
3110 
3111  /* CPU and IO costs which are variable according to the join plan */
3112  planp->variable_cpu_cost = inner_cpu_cost + outer_cpu_cost;
3113  planp->variable_io_cost = inner_io_cost + outer_io_cost;
3114 
3115  {
3116  QO_ENV *env;
3117  int i;
3118  QO_SUBQUERY *subq;
3119  PT_NODE *query;
3120  double temp_cpu_cost, temp_io_cost;
3121  double subq_cpu_cost, subq_io_cost;
3122  BITSET_ITERATOR iter;
3123 
3124  /* Compute the costs for all of the subqueries. Each of the pinned subqueries is intended to be evaluated once for
3125  * each row produced by this plan; the cost of each such evaluation in the fixed cost of the subquery plus one trip
3126  * through the result, i.e.,
3127  *
3128  * QO_PLAN_FIXED_COST(subplan) + QO_PLAN_ACCESS_COST(subplan)
3129  *
3130  * The cost info for the subplan has (probably) been squirreled away in a QO_SUMMARY structure reachable from the
3131  * original select node.
3132  */
3133 
3134  /* When computing the cost for a WORST_PLAN, we'll get in here without a backing info node; just work around it. */
3135  env = inner->info ? (inner->info)->env : NULL;
3136  subq_cpu_cost = subq_io_cost = 0.0; /* init */
3137 
3138  for (i = bitset_iterate (&(inner->subqueries), &iter); i != -1; i = bitset_next_member (&iter))
3139  {
3140  subq = env ? &env->subqueries[i] : NULL;
3141  query = subq ? subq->node : NULL;
3142  qo_plan_compute_subquery_cost (query, &temp_cpu_cost, &temp_io_cost);
3143  subq_cpu_cost += temp_cpu_cost;
3144  subq_io_cost += temp_io_cost;
3145  }
3146 
3147  planp->variable_cpu_cost += MAX (0.0, guessed_result_cardinality - 1.0) * subq_cpu_cost;
3148  planp->variable_io_cost += MAX (0.0, outer->variable_io_cost - 1.0) * subq_io_cost; /* assume IO as # blocks */
3149  }
3150 }
3151 
3152 /*
3153  * qo_mjoin_cost () -
3154  * return:
3155  * planp(in):
3156  */
3157 static void
3159 {
3160  QO_PLAN *inner;
3161  QO_PLAN *outer;
3162  QO_ENV *env;
3163  double outer_cardinality = 0.0, inner_cardinality = 0.0;
3164 
3165  inner = planp->plan_un.join.inner;
3166 
3167  /* for worst cost */
3168  if (inner->fixed_cpu_cost == QO_INFINITY || inner->fixed_io_cost == QO_INFINITY
3169  || inner->variable_cpu_cost == QO_INFINITY || inner->variable_io_cost == QO_INFINITY)
3170  {
3171  qo_worst_cost (planp);
3172  return;
3173  }
3174 
3175  outer = planp->plan_un.join.outer;
3176 
3177  /* for worst cost */
3178  if (outer->fixed_cpu_cost == QO_INFINITY || outer->fixed_io_cost == QO_INFINITY
3179  || outer->variable_cpu_cost == QO_INFINITY || outer->variable_io_cost == QO_INFINITY)
3180  {
3181  qo_worst_cost (planp);
3182  return;
3183  }
3184 
3185  env = outer->info->env;
3186  if (outer->has_sort_limit)
3187  {
3188  outer_cardinality = (double) db_get_bigint (&QO_ENV_LIMIT_VALUE (env));
3189  }
3190  else
3191  {
3192  outer_cardinality = outer->info->cardinality;
3193  }
3194 
3195  if (inner->has_sort_limit)
3196  {
3197  inner_cardinality = (double) db_get_bigint (&QO_ENV_LIMIT_VALUE (env));
3198  }
3199  else
3200  {
3201  inner_cardinality = inner->info->cardinality;
3202  }
3203 
3204  /* CPU and IO costs which are fixed against join */
3205  planp->fixed_cpu_cost = outer->fixed_cpu_cost + inner->fixed_cpu_cost;
3206  planp->fixed_io_cost = outer->fixed_io_cost + inner->fixed_io_cost;
3207  /* CPU and IO costs which are variable according to the join plan */
3208  planp->variable_cpu_cost = outer->variable_cpu_cost + inner->variable_cpu_cost;
3209  planp->variable_cpu_cost += (outer_cardinality / 2) * (inner_cardinality / 2) * (double) QO_CPU_WEIGHT;
3210  /* merge cost */
3211  planp->variable_io_cost = outer->variable_io_cost + inner->variable_io_cost;
3212 }
3213 
3214 /*
3215  * qo_follow_new () -
3216  * return:
3217  * info(in):
3218  * head_plan(in):
3219  * path_term(in):
3220  * sarged_terms(in):
3221  * pinned_subqueries(in):
3222  */
3223 static QO_PLAN *
3224 qo_follow_new (QO_INFO * info, QO_PLAN * head_plan, QO_TERM * path_term, BITSET * sarged_terms,
3225  BITSET * pinned_subqueries)
3226 {
3227  QO_PLAN *plan;
3228 
3229  plan = qo_plan_malloc (info->env);
3230  if (plan == NULL)
3231  {
3232  return NULL;
3233  }
3234 
3235  QO_ASSERT (info->env, head_plan != NULL);
3236 
3237  plan->info = info;
3238  plan->refcount = 0;
3239  plan->top_rooted = false;
3240  plan->well_rooted = head_plan->well_rooted;
3241  plan->iscan_sort_list = NULL;
3242  plan->analytic_eval_list = NULL;
3243  plan->plan_type = QO_PLANTYPE_FOLLOW;
3244  plan->vtbl = &qo_follow_plan_vtbl;
3245  plan->order = QO_UNORDERED;
3246 
3247  plan->plan_un.follow.head = qo_plan_add_ref (head_plan);
3248  plan->plan_un.follow.path = path_term;
3249 
3251 
3252  bitset_assign (&(plan->sarged_terms), sarged_terms);
3253  bitset_remove (&(plan->sarged_terms), QO_TERM_IDX (path_term));
3254 
3255  bitset_assign (&(plan->subqueries), pinned_subqueries);
3256 
3257  bitset_union (&(plan->sarged_terms), &(QO_NODE_SARGS (QO_TERM_TAIL (path_term))));
3258  bitset_union (&(plan->subqueries), &(QO_NODE_SUBQUERIES (QO_TERM_TAIL (path_term))));
3259 
3260  qo_plan_compute_cost (plan);
3261 
3262  plan = qo_top_plan_new (plan);
3263 
3264  return plan;
3265 }
3266 
3267 /*
3268  * qo_follow_walk () -
3269  * return:
3270  * plan(in):
3271  * child_fn(in):
3272  * child_data(in):
3273  * parent_fn(in):
3274  * parent_data(in):
3275  */
3276 static void
3277 qo_follow_walk (QO_PLAN * plan, void (*child_fn) (QO_PLAN *, void *), void *child_data,
3278  void (*parent_fn) (QO_PLAN *, void *), void *parent_data)
3279 {
3280  if (child_fn)
3281  {
3282  (*child_fn) (plan->plan_un.follow.head, child_data);
3283  }
3284  if (parent_fn)
3285  {
3286  (*parent_fn) (plan, parent_data);
3287  }
3288 }
3289 
3290 /*
3291  * qo_follow_fprint () -
3292  * return:
3293  * plan(in):
3294  * f(in):
3295  * howfar(in):
3296  */
3297 static void
3298 qo_follow_fprint (QO_PLAN * plan, FILE * f, int howfar)
3299 {
3300  fprintf (f, "\n" INDENTED_TITLE_FMT, (int) howfar, ' ', "edge:");
3301  qo_term_fprint (plan->plan_un.follow.path, f);
3302  qo_plan_fprint (plan->plan_un.follow.head, f, howfar, "head: ");
3303 }
3304 
3305 /*
3306  * qo_follow_info () -
3307  * return:
3308  * plan(in):
3309  * f(in):
3310  * howfar(in):
3311  */
3312 static void
3313 qo_follow_info (QO_PLAN * plan, FILE * f, int howfar)
3314 {
3315  fprintf (f, "\n%*c%s(%s)", (int) howfar, ' ', (plan->vtbl)->info_string, qo_term_string (plan->plan_un.follow.path));
3316  qo_plan_lite_print (plan->plan_un.follow.head, f, howfar + INDENT_INCR);
3317 }
3318 
3319 /*
3320  * qo_follow_cost () -
3321  * return:
3322  * planp(in):
3323  */
3324 static void
3326 {
3327  QO_PLAN *head;
3328  QO_NODE *tail;
3329  double cardinality, target_pages, fetch_ios;
3330 
3331  head = planp->plan_un.follow.head;
3332 
3333  /* for worst cost */
3334  if (head->fixed_cpu_cost == QO_INFINITY || head->fixed_io_cost == QO_INFINITY
3336  {
3337  qo_worst_cost (planp);
3338  return;
3339  }
3340 
3341  cardinality = (planp->info)->cardinality;
3342  tail = QO_TERM_TAIL (planp->plan_un.follow.path);
3343  target_pages = (double) QO_NODE_TCARD (tail);
3344 
3345  if (cardinality < target_pages)
3346  {
3347  /* If we expect to fetch fewer objects than there are pages in the target class, just assume that each fetch will
3348  * touch a new page.
3349  */
3350  fetch_ios = cardinality;
3351  }
3352  else if (prm_get_integer_value (PRM_ID_PB_NBUFFERS) >= target_pages)
3353  {
3354  /* We have more pointers to follow than pages in the target, but fewer target pages than buffer pages. Assume
3355  * that the page buffering will limit the number of of page fetches to the number of target pages.
3356  */
3357  fetch_ios = target_pages;
3358  }
3359  else
3360  {
3361  fetch_ios = cardinality * (1.0 - ((double) prm_get_integer_value (PRM_ID_PB_NBUFFERS)) / target_pages);
3362  }
3363 
3364  planp->fixed_cpu_cost = head->fixed_cpu_cost;
3365  planp->fixed_io_cost = head->fixed_io_cost;
3366  planp->variable_cpu_cost = head->variable_cpu_cost + (cardinality * (double) QO_CPU_WEIGHT);
3367  planp->variable_io_cost = head->variable_io_cost + fetch_ios;
3368 }
3369 
3370 
3371 /*
3372  * qo_cp_new () -
3373  * return:
3374  * info(in):
3375  * outer(in):
3376  * inner(in):
3377  * sarged_terms(in):
3378  * pinned_subqueries(in):
3379  */
3380 static QO_PLAN *
3381 qo_cp_new (QO_INFO * info, QO_PLAN * outer, QO_PLAN * inner, BITSET * sarged_terms, BITSET * pinned_subqueries)
3382 {
3383  QO_PLAN *plan;
3384  BITSET empty_terms;
3385 
3386  bitset_init (&empty_terms, info->env);
3387 
3388  plan = qo_join_new (info, JOIN_INNER /* default */ ,
3389  QO_JOINMETHOD_NL_JOIN, outer, inner, &empty_terms /* join_terms */ ,
3390  &empty_terms /* duj_terms */ ,
3391  &empty_terms /* afj_terms */ ,
3392  sarged_terms, pinned_subqueries, &empty_terms /* hash_terms */ );
3393 
3394  bitset_delset (&empty_terms);
3395 
3396  return plan;
3397 }
3398 
3399 
3400 /*
3401  * qo_worst_new () -
3402  * return:
3403  * env(in):
3404  */
3405 static QO_PLAN *
3407 {
3408  QO_PLAN *plan;
3409 
3410  plan = qo_plan_malloc (env);
3411  if (plan == NULL)
3412  {
3413  return NULL;
3414  }
3415 
3416  plan->info = NULL;
3417  plan->refcount = 0;
3418  plan->top_rooted = true;
3419  plan->well_rooted = false;
3420  plan->iscan_sort_list = NULL;
3421  plan->analytic_eval_list = NULL;
3422  plan->order = QO_UNORDERED;
3423  plan->plan_type = QO_PLANTYPE_WORST;
3424  plan->vtbl = &qo_worst_plan_vtbl;
3425 
3427 
3428  qo_plan_compute_cost (plan);
3429 
3430  return plan;
3431 }
3432 
3433 /*
3434  * qo_worst_fprint () -
3435  * return:
3436  * plan(in):
3437  * f(in):
3438  * howfar(in):
3439  */
3440 static void
3441 qo_worst_fprint (QO_PLAN * plan, FILE * f, int howfar)
3442 {
3443 }
3444 
3445 /*
3446  * qo_worst_info () -
3447  * return:
3448  * plan(in):
3449  * f(in):
3450  * howfar(in):
3451  */
3452 static void
3453 qo_worst_info (QO_PLAN * plan, FILE * f, int howfar)
3454 {
3455  fprintf (f, "\n%*c%s", (int) howfar, ' ', (plan->vtbl)->info_string);
3456 }
3457 
3458 /*
3459  * qo_worst_cost () -
3460  * return:
3461  * planp(in):
3462  */
3463 static void
3465 {
3466  planp->fixed_cpu_cost = QO_INFINITY;
3467  planp->fixed_io_cost = QO_INFINITY;
3468  planp->variable_cpu_cost = QO_INFINITY;
3469  planp->variable_io_cost = QO_INFINITY;
3470  planp->use_iscan_descending = false;
3471 }
3472 
3473 
3474 /*
3475  * qo_zero_cost () -
3476  * return:
3477  * planp(in):
3478  */
3479 static void
3481 {
3482  planp->fixed_cpu_cost = 0.0;
3483  planp->fixed_io_cost = 0.0;
3484  planp->variable_cpu_cost = 0.0;
3485  planp->variable_io_cost = 0.0;
3486 }
3487 
3488 
3489 /*
3490  * qo_plan_order_by () -
3491  * return:
3492  * plan(in):
3493  * order(in):
3494  */
3495 static QO_PLAN *
3497 {
3498  if (plan == NULL || order == QO_UNORDERED || plan->order == order)
3499  {
3500  return plan;
3501  }
3502  else if (BITSET_MEMBER ((plan->info)->eqclasses, QO_EQCLASS_IDX (order)))
3503  {
3504  return qo_sort_new (plan, order, SORT_TEMP);
3505  }
3506  else
3507  {
3508  return (QO_PLAN *) NULL;
3509  }
3510 }
3511 
3512 /*
3513  * qo_plan_cmp_prefer_covering_index () - TODO
3514  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_GT}
3515  * scan_plan_p(in):
3516  * sort_plan_p(in):
3517  */
3519 qo_plan_cmp_prefer_covering_index (QO_PLAN * scan_plan_p, QO_PLAN * sort_plan_p)
3520 {
3521  QO_PLAN *sort_subplan_p;
3522 
3523  assert (scan_plan_p->plan_type == QO_PLANTYPE_SCAN);
3524  assert (sort_plan_p->plan_type == QO_PLANTYPE_SORT);
3525 
3526  sort_subplan_p = sort_plan_p->plan_un.sort.subplan;
3527 
3528  if (!qo_is_interesting_order_scan (scan_plan_p) || !qo_is_interesting_order_scan (sort_subplan_p))
3529  {
3530  return PLAN_COMP_UNK;
3531  }
3532 
3533  if (qo_is_index_iss_scan (scan_plan_p) || qo_is_index_loose_scan (scan_plan_p))
3534  {
3535  return PLAN_COMP_UNK;
3536  }
3537 
3538  if (qo_is_index_iss_scan (sort_subplan_p) || qo_is_index_loose_scan (sort_subplan_p))
3539  {
3540  return PLAN_COMP_UNK;
3541  }
3542 
3543  if (qo_is_index_covering_scan (sort_subplan_p))
3544  {
3545  /* if the sort plan contains a index plan with segment covering, prefer it */
3546  if (qo_is_index_covering_scan (scan_plan_p))
3547  {
3548  if (scan_plan_p->plan_un.scan.index->head == sort_subplan_p->plan_un.scan.index->head)
3549  {
3550  return PLAN_COMP_LT;
3551  }
3552  }
3553  else
3554  {
3555  if (!bitset_is_empty (&(sort_subplan_p->plan_un.scan.terms)))
3556  {
3557  /* prefer covering index scan with key-range */
3558  return PLAN_COMP_GT;
3559  }
3560  }
3561  }
3562 
3563  return PLAN_COMP_UNK;
3564 }
3565 
3566 /*
3567  * qo_plan_cmp () -
3568  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
3569  * a(in):
3570  * b(in):
3571  */
3574 {
3575 #if 1 /* TODO - do not delete me */
3576 #define QO_PLAN_CMP_CHECK_COST(a, b)
3577 #else
3578 #define QO_PLAN_CMP_CHECK_COST(a, b) assert ((a) < ((b)*10));
3579 #endif
3580 
3581 #ifdef OLD_CODE
3582  if (QO_PLAN_FIXED_COST (a) <= QO_PLAN_FIXED_COST (b))
3583  {
3584  return QO_PLAN_ACCESS_COST (a) <= QO_PLAN_ACCESS_COST (b) ? a : b;
3585  }
3586  else
3587  {
3588  return QO_PLAN_ACCESS_COST (b) <= QO_PLAN_ACCESS_COST (a) ? b : a;
3589  }
3590 #else /* OLD_CODE */
3591  double af, aa, bf, ba;
3592  QO_NODE *a_node, *b_node;
3593  QO_PLAN_COMPARE_RESULT temp_res;
3594 
3595  af = a->fixed_cpu_cost + a->fixed_io_cost;
3596  aa = a->variable_cpu_cost + a->variable_io_cost;
3597  bf = b->fixed_cpu_cost + b->fixed_io_cost;
3598  ba = b->variable_cpu_cost + b->variable_io_cost;
3599 
3600  if (qo_is_sort_limit (a))
3601  {
3602  if (qo_is_sort_limit (b))
3603  {
3604  /* compare subplans */
3605  a = a->plan_un.sort.subplan;
3606  b = b->plan_un.sort.subplan;
3607  }
3608  else if (a->plan_un.sort.subplan == b)
3609  {
3610  /* a is a SORT-LIMIT plan over b */
3611  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3612  return PLAN_COMP_LT;
3613  }
3614  }
3615  else if (qo_is_sort_limit (b) && a == b->plan_un.sort.subplan)
3616  {
3617  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3618  return PLAN_COMP_GT;
3619  }
3620 
3621  /* skip out top-level sort plan */
3622  if (a->top_rooted && b->top_rooted)
3623  {
3624  /* skip out the same sort plan */
3626  && a->plan_un.sort.sort_type == b->plan_un.sort.sort_type)
3627  {
3628  a = a->plan_un.sort.subplan;
3629  b = b->plan_un.sort.subplan;
3630  }
3631  }
3632  else
3633  {
3634  if (a->top_rooted)
3635  {
3636  while (a->plan_type == QO_PLANTYPE_SORT)
3637  {
3638  if (a->plan_un.sort.sort_type == SORT_TEMP)
3639  {
3640  break; /* is not top-level plan */
3641  }
3642  a = a->plan_un.sort.subplan;
3643  }
3644  }
3645  if (b->top_rooted)
3646  {
3647  while (b->plan_type == QO_PLANTYPE_SORT)
3648  {
3649  if (b->plan_un.sort.sort_type == SORT_TEMP)
3650  {
3651  break; /* is top-level plan */
3652  }
3653  b = b->plan_un.sort.subplan;
3654  }
3655  }
3656  }
3657 
3658  if (a == b)
3659  {
3660  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3661  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3662  return PLAN_COMP_EQ;
3663  }
3664 
3667  {
3668  /* there may be joins with multi range optimizations */
3669  temp_res = qo_multi_range_opt_plans_cmp (a, b);
3670  if (temp_res == PLAN_COMP_LT)
3671  {
3672  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3673  return PLAN_COMP_LT;
3674  }
3675  else if (temp_res == PLAN_COMP_GT)
3676  {
3677  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3678  return PLAN_COMP_GT;
3679  }
3680  else
3681  {
3682  goto cost_cmp; /* give up */
3683  }
3684  }
3685 
3686  /* a order by skip plan is always preferred to a sort plan */
3688  {
3689  /* prefer scan if it is multi range opt */
3690  if (qo_is_index_mro_scan (a))
3691  {
3692  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3693  return PLAN_COMP_LT;
3694  }
3695 
3696  temp_res = qo_plan_cmp_prefer_covering_index (a, b);
3697  if (temp_res == PLAN_COMP_LT)
3698  {
3699  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3700  return PLAN_COMP_LT;
3701  }
3702  else if (temp_res == PLAN_COMP_GT)
3703  {
3704  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3705  return PLAN_COMP_GT;
3706  }
3707 
3709  {
3710  if (a->plan_un.scan.index && a->plan_un.scan.index->head->groupby_skip)
3711  {
3712  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3713  return PLAN_COMP_LT;
3714  }
3715  if (a->plan_un.scan.index && a->plan_un.scan.index->head->orderby_skip)
3716  {
3717  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3718  return PLAN_COMP_LT;
3719  }
3720  }
3721  }
3722 
3724  {
3725  /* prefer scan if it is multi range opt */
3726  if (qo_is_index_mro_scan (b))
3727  {
3728  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3729  return PLAN_COMP_GT;
3730  }
3731 
3732  temp_res = qo_plan_cmp_prefer_covering_index (b, a);
3733 
3734  /* Since we swapped its position, we have to negate the comp result */
3735  if (temp_res == PLAN_COMP_LT)
3736  {
3737  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3738  return PLAN_COMP_GT;
3739  }
3740  else if (temp_res == PLAN_COMP_GT)
3741  {
3742  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3743  return PLAN_COMP_LT;
3744  }
3745 
3747  {
3748  if (b->plan_un.scan.index && b->plan_un.scan.index->head->groupby_skip)
3749  {
3750  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3751  return PLAN_COMP_GT;
3752  }
3753  if (b->plan_un.scan.index && b->plan_un.scan.index->head->orderby_skip)
3754  {
3755  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3756  return PLAN_COMP_GT;
3757  }
3758  }
3759  }
3760 
3762  {
3763  /* check if it is an unique index and all columns are equi */
3765  {
3766  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3767  return PLAN_COMP_LT;
3768  }
3770  {
3771  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3772  return PLAN_COMP_GT;
3773  }
3774 
3775  /* check multi range optimization */
3777  {
3778  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3779  return PLAN_COMP_LT;
3780  }
3782  {
3783  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3784  return PLAN_COMP_GT;
3785  }
3786 
3787  /* check covering index scan */
3789  {
3790  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3791  return PLAN_COMP_LT;
3792  }
3794  {
3795  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3796  return PLAN_COMP_GT;
3797  }
3798 
3799  /* a plan does order by skip, the other does group by skip - prefer the group by skipping because it's done in
3800  * the final step
3801  */
3803  {
3805  && !qo_is_index_loose_scan (b))
3806  {
3807  if (a->plan_un.scan.index->head->orderby_skip && b->plan_un.scan.index->head->groupby_skip)
3808  {
3809  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3810  return PLAN_COMP_LT;
3811  }
3812  else if (a->plan_un.scan.index->head->groupby_skip && b->plan_un.scan.index->head->orderby_skip)
3813  {
3814  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3815  return PLAN_COMP_GT;
3816  }
3817  }
3818  }
3819  }
3820 
3822  { /* impossible case */
3823  goto cost_cmp; /* give up */
3824  }
3825 
3826  a_node = a->plan_un.scan.node;
3827  b_node = b->plan_un.scan.node;
3828 
3829  /* check for empty spec */
3830  if (QO_NODE_NCARD (a_node) == 0 && QO_NODE_TCARD (a_node) == 0)
3831  {
3832  if (QO_NODE_NCARD (b_node) == 0 && QO_NODE_TCARD (b_node) == 0)
3833  {
3834  goto cost_cmp; /* give up */
3835  }
3836 
3837  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3838  return PLAN_COMP_LT;
3839  }
3840  else if (QO_NODE_NCARD (b_node) == 0 && QO_NODE_TCARD (b_node) == 0)
3841  {
3842  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3843  return PLAN_COMP_GT;
3844  }
3845 
3846  if (QO_NODE_IDX (a_node) != QO_NODE_IDX (b_node))
3847  {
3848  goto cost_cmp; /* give up */
3849  }
3850 
3851  /* check for both index scan of the same spec */
3853  {
3854  goto cost_cmp; /* give up */
3855  }
3856 
3857  /* check multi range optimization */
3858  temp_res = qo_multi_range_opt_plans_cmp (a, b);
3859  if (temp_res == PLAN_COMP_LT)
3860  {
3861  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3862  return PLAN_COMP_LT;
3863  }
3864  else if (temp_res == PLAN_COMP_GT)
3865  {
3866  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3867  return PLAN_COMP_GT;
3868  }
3869 
3870  /* check index coverage */
3871  temp_res = qo_index_covering_plans_cmp (a, b);
3872  if (temp_res == PLAN_COMP_LT)
3873  {
3874  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3875  return PLAN_COMP_LT;
3876  }
3877  else if (temp_res == PLAN_COMP_GT)
3878  {
3879  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3880  return PLAN_COMP_GT;
3881  }
3882 
3883  /* check if one of the plans skips the order by, and if so, prefer it */
3884  temp_res = qo_order_by_skip_plans_cmp (a, b);
3885  if (temp_res == PLAN_COMP_LT)
3886  {
3887  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3888  return PLAN_COMP_LT;
3889  }
3890  else if (temp_res == PLAN_COMP_GT)
3891  {
3892  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3893  return PLAN_COMP_GT;
3894  }
3895 
3896  /* check if one of the plans skips the group by, and if so, prefer it */
3897  temp_res = qo_group_by_skip_plans_cmp (a, b);
3898  if (temp_res == PLAN_COMP_LT)
3899  {
3900  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3901  return PLAN_COMP_LT;
3902  }
3903  else if (temp_res == PLAN_COMP_GT)
3904  {
3905  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3906  return PLAN_COMP_GT;
3907  }
3908 
3909  /* iscan vs iscan index rule comparison */
3910 
3911  {
3912  QO_NODE_INDEX_ENTRY *a_ni, *b_ni;
3913  QO_INDEX_ENTRY *a_ent, *b_ent;
3914  QO_ATTR_CUM_STATS *a_cum, *b_cum;
3915  int a_range, b_range; /* num iscan range terms */
3916  int a_filter, b_filter; /* num iscan filter terms */
3917  int a_last, b_last; /* the last partial-key indicator */
3918  int a_keys, b_keys; /* num keys */
3919  int a_pages, b_pages; /* num access index pages */
3920  int a_leafs, b_leafs; /* num access index leaf pages */
3921  int i;
3922  QO_TERM *term;
3923 
3924  /* index entry of spec 'a' */
3925  a_ni = a->plan_un.scan.index;
3926  a_ent = (a_ni)->head;
3927  a_cum = &(a_ni)->cum_stats;
3928 
3930  for (i = 0; i < a_cum->pkeys_size; i++)
3931  {
3932  if (a_cum->pkeys[i] <= 0)
3933  {
3934  break;
3935  }
3936  }
3937  a_last = i;
3938 
3939  /* index range terms */
3940  a_range = bitset_cardinality (&(a->plan_un.scan.terms));
3941  if (a_range > 0 && !(a->plan_un.scan.index_equi))
3942  {
3943  a_range--; /* set the last equal range term */
3944  }
3945 
3946  /* index filter terms */
3947  a_filter = bitset_cardinality (&(a->plan_un.scan.kf_terms));
3948 
3949  /* index entry of spec 'b' */
3950  b_ni = b->plan_un.scan.index;
3951  b_ent = (b_ni)->head;
3952  b_cum = &(b_ni)->cum_stats;
3953 
3955  for (i = 0; i < b_cum->pkeys_size; i++)
3956  {
3957  if (b_cum->pkeys[i] <= 0)
3958  {
3959  break;
3960  }
3961  }
3962  b_last = i;
3963 
3964  /* index range terms */
3965  b_range = bitset_cardinality (&(b->plan_un.scan.terms));
3966  if (b_range > 0 && !(b->plan_un.scan.index_equi))
3967  {
3968  b_range--; /* set the last equal range term */
3969  }
3970 
3971  /* index filter terms */
3972  b_filter = bitset_cardinality (&(b->plan_un.scan.kf_terms));
3973 
3974  /* STEP 1: take the smaller search condition */
3975 
3976  /* check for same index pointer */
3977  if (a_ent == b_ent)
3978  {
3979  /* check for search condition */
3980  if (a_range == b_range && a_filter == b_filter)
3981  {
3982  ; /* go ahead */
3983  }
3984  else if (a_range >= b_range && a_filter >= b_filter)
3985  {
3986  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
3987  return PLAN_COMP_LT;
3988  }
3989  else if (a_range <= b_range && a_filter <= b_filter)
3990  {
3991  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
3992  return PLAN_COMP_GT;
3993  }
3994  }
3995 
3996  /* STEP 2: check by index terms */
3997 
3998  temp_res = qo_plan_iscan_terms_cmp (a, b);
3999  if (temp_res == PLAN_COMP_LT)
4000  {
4001  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4002  return PLAN_COMP_LT;
4003  }
4004  else if (temp_res == PLAN_COMP_GT)
4005  {
4006  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4007  return PLAN_COMP_GT;
4008  }
4009 
4010  /* STEP 3: take the smaller access pages */
4011 
4012  if (a->variable_io_cost != b->variable_io_cost)
4013  {
4014  goto cost_cmp; /* give up */
4015  }
4016 
4017  /* btree partial-key stats */
4018  if (a_range == a_ent->col_num)
4019  {
4020  a_keys = a_cum->keys;
4021  }
4022  else if (a_range > 0 && a_range < a_last)
4023  {
4024  a_keys = a_cum->pkeys[a_range - 1];
4025  }
4026  else
4027  { /* a_range == 0 */
4028  a_keys = 1; /* init as full range */
4029  if (a_last > 0)
4030  {
4031  if (bitset_cardinality (&(a->plan_un.scan.terms)) > 0)
4032  {
4033  term = QO_ENV_TERM ((a->info)->env, bitset_first_member (&(a->plan_un.scan.terms)));
4034  a_keys = (int) ceil (1.0 / QO_TERM_SELECTIVITY (term));
4035  }
4036  else
4037  {
4038  a_keys = (int) ceil (1.0 / DEFAULT_SELECTIVITY);
4039  }
4040 
4041  a_keys = MIN (a_cum->pkeys[0], a_keys);
4042  }
4043  }
4044 
4045  if (a_cum->leafs <= a_keys)
4046  {
4047  a_leafs = 1;
4048  }
4049  else if (a_keys == 0)
4050  {
4051  a_leafs = 0;
4052  }
4053  else
4054  {
4055  a_leafs = (int) ceil ((double) a_cum->leafs / a_keys);
4056  }
4057 
4058  /* btree access pages */
4059  a_pages = a_leafs + a_cum->height - 1;
4060 
4061  /* btree partial-key stats */
4062  if (b_range == b_ent->col_num)
4063  {
4064  b_keys = b_cum->keys;
4065  }
4066  else if (b_range > 0 && b_range < b_last)
4067  {
4068  b_keys = b_cum->pkeys[b_range - 1];
4069  }
4070  else
4071  { /* b_range == 0 */
4072  b_keys = 1; /* init as full range */
4073  if (b_last > 0)
4074  {
4075  if (bitset_cardinality (&(b->plan_un.scan.terms)) > 0)
4076  {
4077  term = QO_ENV_TERM ((b->info)->env, bitset_first_member (&(b->plan_un.scan.terms)));
4078  b_keys = (int) ceil (1.0 / QO_TERM_SELECTIVITY (term));
4079  }
4080  else
4081  {
4082  b_keys = (int) ceil (1.0 / DEFAULT_SELECTIVITY);
4083  }
4084 
4085  b_keys = MIN (b_cum->pkeys[0], b_keys);
4086  }
4087  }
4088 
4089  if (b_cum->leafs <= b_keys)
4090  {
4091  b_leafs = 1;
4092  }
4093  else if (b_keys == 0)
4094  {
4095  b_leafs = 0;
4096  }
4097  else
4098  {
4099  b_leafs = (int) ceil ((double) b_cum->leafs / b_keys);
4100  }
4101 
4102  /* btree access pages */
4103  b_pages = b_leafs + b_cum->height - 1;
4104 
4105  if (a_pages < b_pages)
4106  {
4107  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4108  return PLAN_COMP_LT;
4109  }
4110  else if (a_pages > b_pages)
4111  {
4112  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4113  return PLAN_COMP_GT;
4114  }
4115 
4116  /* STEP 4: take the smaller index */
4117  if (a_cum->pages > a_cum->height && b_cum->pages > b_cum->height)
4118  {
4119  /* each index is big enough */
4120  if (a_cum->pages < b_cum->pages)
4121  {
4122  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4123  return PLAN_COMP_LT;
4124  }
4125  else if (a_cum->pages > b_cum->pages)
4126  {
4127  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4128  return PLAN_COMP_GT;
4129  }
4130  }
4131 
4132  /* STEP 5: take the smaller key range */
4133  if (a_keys > b_keys)
4134  {
4135  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4136  return PLAN_COMP_LT;
4137  }
4138  else if (a_keys < b_keys)
4139  {
4140  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4141  return PLAN_COMP_GT;
4142  }
4143 
4144  if (af == bf && aa == ba)
4145  {
4146  if (a->plan_un.scan.index_equi == b->plan_un.scan.index_equi && qo_is_index_covering_scan (a)
4148  {
4149  if (a_ent->col_num > b_ent->col_num)
4150  {
4151  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4152  return PLAN_COMP_GT;
4153  }
4154  else if (a_ent->col_num < b_ent->col_num)
4155  {
4156  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4157  return PLAN_COMP_LT;
4158  }
4159  }
4160 
4162  {
4163  if (a_ent->col_num > b_ent->col_num)
4164  {
4165  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4166  return PLAN_COMP_GT;
4167  }
4168  else if (a_ent->col_num < b_ent->col_num)
4169  {
4170  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4171  return PLAN_COMP_LT;
4172  }
4173  }
4174 
4175  /* if both plans skip order by and same costs, take the larger one */
4177  && !qo_is_index_loose_scan (b))
4178  {
4179  if (a_ent->orderby_skip && b_ent->orderby_skip)
4180  {
4181  if (a_ent->col_num > b_ent->col_num)
4182  {
4183  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4184  return PLAN_COMP_LT;
4185  }
4186  else if (a_ent->col_num < b_ent->col_num)
4187  {
4188  /* if the new plan has more columns, prefer it */
4189  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4190  return PLAN_COMP_GT;
4191  }
4192  }
4193  }
4194 
4195  /* if both plans skip group by and same costs, take the larger one */
4196  if (a_ent->groupby_skip && b_ent->groupby_skip)
4197  {
4198  if (a_ent->col_num > b_ent->col_num)
4199  {
4200  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4201  return PLAN_COMP_LT;
4202  }
4203  else if (a_ent->col_num < b_ent->col_num)
4204  {
4205  /* if the new plan has more columns, prefer it */
4206  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4207  return PLAN_COMP_GT;
4208  }
4209  }
4210  }
4211 
4212  }
4213 
4214 cost_cmp:
4215 
4216  if (a == b || (af == bf && aa == ba))
4217  {
4218  return PLAN_COMP_EQ;
4219  }
4220  if (af <= bf && aa <= ba)
4221  {
4222  QO_PLAN_CMP_CHECK_COST (af + aa, bf + ba);
4223  return PLAN_COMP_LT;
4224  }
4225  if (bf <= af && ba <= aa)
4226  {
4227  QO_PLAN_CMP_CHECK_COST (bf + ba, af + aa);
4228  return PLAN_COMP_GT;
4229  }
4230 
4231  return PLAN_COMP_UNK;
4232 #endif /* OLD_CODE */
4233 }
4234 
4235 /*
4236  * qo_multi_range_opt_plans_cmp () - compare two plans in regard with multi
4237  * range optimizations
4238  *
4239  * return : compare result
4240  * a (in) : first plan
4241  * b (in) : second plan
4242  */
4245 {
4246  QO_PLAN_COMPARE_RESULT temp_res;
4247 
4248  /* if no plan uses multi range optimization, nothing to do here */
4250  {
4251  return PLAN_COMP_UNK;
4252  }
4253 
4254  /* check if only one plan uses multi range optimization */
4256  {
4257  return PLAN_COMP_LT;
4258  }
4260  {
4261  return PLAN_COMP_GT;
4262  }
4263 
4264  /* at here, both plans use multi range optimization */
4265 
4267  {
4268  /* choose the plan where the optimized index scan is "outer-most" */
4269  int a_mro_join_idx = -1, b_mro_join_idx = -1;
4270 
4271  if (qo_find_subplan_using_multi_range_opt (a, NULL, &a_mro_join_idx) != NO_ERROR
4272  || qo_find_subplan_using_multi_range_opt (b, NULL, &b_mro_join_idx) != NO_ERROR)
4273  {
4274  assert (0);
4275  return PLAN_COMP_UNK;
4276  }
4277  if (a_mro_join_idx < b_mro_join_idx)
4278  {
4279  return PLAN_COMP_LT;
4280  }
4281  else if (a_mro_join_idx > b_mro_join_idx)
4282  {
4283  return PLAN_COMP_GT;
4284  }
4285  else
4286  {
4287  return PLAN_COMP_EQ;
4288  }
4289  }
4290 
4292  {
4293  /* one plan is join, the other is not join */
4294  return PLAN_COMP_UNK;
4295  }
4296 
4297  /* both plans must be optimized index scans */
4300 
4301  assert (bitset_cardinality (&(a->plan_un.scan.terms)) > 0);
4302  assert (bitset_cardinality (&(b->plan_un.scan.terms)) > 0);
4303 
4304  /* choose the plan that also covers all segments */
4305  temp_res = qo_index_covering_plans_cmp (a, b);
4306  if (temp_res == PLAN_COMP_LT || temp_res == PLAN_COMP_GT)
4307  {
4308  return temp_res;
4309  }
4310 
4311  return qo_plan_iscan_terms_cmp (a, b);
4312 }
4313 
4314 /*
4315  * qo_index_covering_plans_cmp () - compare 2 index scan plans by coverage
4316  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
4317  * a(in):
4318  * b(in):
4319  */
4322 {
4323  int a_range, b_range; /* num iscan range terms */
4324 
4326  {
4327  return PLAN_COMP_UNK;
4328  }
4329 
4330  assert (a->plan_un.scan.index->head != NULL);
4331  assert (b->plan_un.scan.index->head != NULL);
4332 
4334  {
4335  return PLAN_COMP_UNK;
4336  }
4337 
4339  {
4340  return PLAN_COMP_UNK;
4341  }
4342 
4343  a_range = bitset_cardinality (&(a->plan_un.scan.terms));
4344  b_range = bitset_cardinality (&(b->plan_un.scan.terms));
4345 
4346  assert (a_range >= 0);
4347  assert (b_range >= 0);
4348 
4349  if (qo_is_index_covering_scan (a))
4350  {
4351  if (qo_is_index_covering_scan (b))
4352  {
4353  return qo_plan_iscan_terms_cmp (a, b);
4354  }
4355  else
4356  {
4357  if (a_range >= b_range)
4358  {
4359  /* prefer covering index scan with key-range */
4360  return PLAN_COMP_LT;
4361  }
4362  }
4363  }
4364  else if (qo_is_index_covering_scan (b))
4365  {
4366  if (b_range >= a_range)
4367  {
4368  /* prefer covering index scan with key-range */
4369  return PLAN_COMP_GT;
4370  }
4371  }
4372 
4373  return PLAN_COMP_EQ;
4374 }
4375 
4376 /*
4377  * qo_plan_fprint () -
4378  * return:
4379  * plan(in):
4380  * f(in):
4381  * howfar(in):
4382  * title(in):
4383  */
4384 static void
4385 qo_plan_fprint (QO_PLAN * plan, FILE * f, int howfar, const char *title)
4386 {
4387  if (howfar < 0)
4388  {
4389  howfar = -howfar;
4390  }
4391  else
4392  {
4393  fputs ("\n", f);
4394  if (howfar)
4395  {
4396  fprintf (f, INDENT_FMT, (int) howfar, ' ');
4397  }
4398  }
4399 
4400  if (title)
4401  {
4402  fprintf (f, TITLE_FMT, title);
4403  }
4404 
4405  fputs ((plan->vtbl)->plan_string, f);
4406 
4407  {
4408  int title_len;
4409 
4410  title_len = title ? (int) strlen (title) : 0;
4411  howfar += (title_len + INDENT_INCR);
4412  }
4413 
4414  (*((plan->vtbl)->fprint_fn)) (plan, f, howfar);
4415 
4416  qo_plan_print_projected_segs (plan, f, howfar);
4417  qo_plan_print_sarged_terms (plan, f, howfar);
4418  qo_plan_print_subqueries (plan, f, howfar);
4419  qo_plan_print_sort_spec (plan, f, howfar);
4420  qo_plan_print_costs (plan, f, howfar);
4421  qo_plan_print_analytic_eval (plan, f, howfar);
4422 }
4423 
4424 /*
4425  * qo_plan_lite_print () -
4426  * return:
4427  * plan(in):
4428  * f(in):
4429  * howfar(in):
4430  */
4431 void
4432 qo_plan_lite_print (QO_PLAN * plan, FILE * f, int howfar)
4433 {
4434  (*((plan->vtbl)->info_fn)) (plan, f, howfar);
4435 }
4436 
4437 
4438 /*
4439  * qo_plan_finalize () -
4440  * return:
4441  * plan(in):
4442  */
4443 static QO_PLAN *
4445 {
4446  return qo_plan_add_ref (plan);
4447 }
4448 
4449 
4450 /*
4451  * qo_plan_discard () -
4452  * return:
4453  * plan(in):
4454  */
4455 void
4457 {
4458  if (plan)
4459  {
4460  QO_ENV *env;
4461  bool dump_enable;
4462 
4463  /*
4464  * Be sure to capture dump_enable *before* we free the env
4465  * structure!
4466  */
4467  env = (plan->info)->env;
4468  dump_enable = env->dump_enable;
4469 
4470  qo_plan_del_ref (plan);
4471  qo_env_free (env);
4472 
4473  if (dump_enable)
4474  {
4475  qo_print_stats (stdout);
4476  }
4477  }
4478 }
4479 
4480 
4481 /*
4482  * qo_plan_walk () -
4483  * return:
4484  * plan(in):
4485  * child_fn(in):
4486  * child_data(in):
4487  * parent_fn(in):
4488  * parent_data(in):
4489  */
4490 static void
4491 qo_plan_walk (QO_PLAN * plan, void (*child_fn) (QO_PLAN *, void *), void *child_data,
4492  void (*parent_fn) (QO_PLAN *, void *), void *parent_data)
4493 {
4494  (*(plan->vtbl)->walk_fn) (plan, child_fn, child_data, parent_fn, parent_data);
4495 }
4496 
4497 /*
4498  * qo_plan_del_ref_func () -
4499  * return:
4500  * plan(in):
4501  */
4502 static void
4503 qo_plan_del_ref_func (QO_PLAN * plan, void *ignore)
4504 {
4505  qo_plan_del_ref (plan); /* use the macro */
4506 }
4507 
4508 /*
4509  * qo_plan_add_to_free_list () -
4510  * return:
4511  * plan(in):
4512  */
4513 static void
4514 qo_plan_add_to_free_list (QO_PLAN * plan, void *ignore)
4515 {
4516  bitset_delset (&(plan->sarged_terms));
4517  bitset_delset (&(plan->subqueries));
4518  if (plan->iscan_sort_list)
4519  {
4520  parser_free_tree (QO_ENV_PARSER ((plan->info)->env), plan->iscan_sort_list);
4521  }
4522 
4524  {
4525  memset ((void *) plan, 0, sizeof (*plan));
4526  plan->plan_un.free.link = qo_plan_free_list;
4527  qo_plan_free_list = plan;
4528  }
4529  else
4530  {
4532  free_and_init (plan);
4533  }
4535 }
4536 
4537 /*
4538  * qo_plan_free () -
4539  * return:
4540  * plan(in):
4541  */
4542 static void
4544 {
4545  if (plan->refcount != 0)
4546  {
4547 #if defined(CUBRID_DEBUG)
4548  fprintf (stderr, "*** optimizer problem: plan refcount = %d ***\n", plan->refcount);
4549 #endif /* CUBRID_DEBUG */
4550  }
4551  else
4552  {
4553  if ((plan->vtbl)->free_fn)
4554  {
4555  (*(plan->vtbl)->free_fn) (plan);
4556  }
4557 
4559  }
4560 }
4561 
4562 /*
4563  * qo_plans_init () -
4564  * return:
4565  * env(in):
4566  */
4567 static void
4569 {
4570  qo_plan_free_list = NULL;
4571  qo_plans_allocated = 0;
4573  qo_plans_malloced = 0;
4574  qo_plans_demalloced = 0;
4575  qo_accumulating_plans = false /* true */ ;
4576  qo_next_tmpfile = 0;
4577 }
4578 
4579 /*
4580  * qo_plans_teardown () -
4581  * return:
4582  * env(in):
4583  */
4584 static void
4586 {
4587  while (qo_plan_free_list)
4588  {
4589  QO_PLAN *plan = qo_plan_free_list;
4590 
4591  qo_plan_free_list = plan->plan_un.free.link;
4592  if (plan)
4593  {
4594  free_and_init (plan);
4595  }
4597  }
4598  qo_accumulating_plans = false;
4599 }
4600 
4601 /*
4602  * qo_plans_stats () -
4603  * return:
4604  * f(in):
4605  */
4606 void
4607 qo_plans_stats (FILE * f)
4608 {
4609  fprintf (f, "%d/%d plans allocated/deallocated\n", qo_plans_allocated, qo_plans_deallocated);
4610  fprintf (f, "%d/%d plans malloced/demalloced\n", qo_plans_malloced, qo_plans_demalloced);
4611 }
4612 
4613 /*
4614  * qo_plan_dump () - Print a representation of the plan on the indicated
4615  * stream
4616  * return: nothing
4617  * plan(in): A pointer to a query optimizer plan
4618  * output(in): The stream to dump the plan to
4619  */
4620 void
4621 qo_plan_dump (QO_PLAN * plan, FILE * output)
4622 {
4623  int level;
4624 
4625  if (output == NULL)
4626  {
4627  output = stdout;
4628  }
4629 
4630  if (plan == NULL)
4631  {
4632  fputs ("\nNo optimized plan!\n", output);
4633  return;
4634  }
4635 
4637  if (DETAILED_DUMP (level))
4638  {
4639  qo_plan_fprint (plan, output, 0, NULL);
4640  }
4641  else if (SIMPLE_DUMP (level))
4642  {
4643  qo_plan_lite_print (plan, output, 0);
4644  }
4645 
4646  fputs ("\n", output);
4647 }
4648 
4649 /*
4650  * qo_plan_get_cost_fn
4651  *
4652  * arguments:
4653  * plan_name: The name of a particular plan type.
4654  *
4655  * returns/side-effects: nothing
4656  *
4657  * description: Retrieve the current cost function for the named plan.
4658  */
4659 
4660 int
4661 qo_plan_get_cost_fn (const char *plan_name)
4662 {
4663  int n = DIM (all_vtbls);
4664  int i = 0;
4665  int cost = 'u';
4666 
4667  for (i = 0; i < n; i++)
4668  {
4669  if (intl_mbs_ncasecmp (plan_name, all_vtbls[i]->plan_string, strlen (all_vtbls[i]->plan_string)) == 0)
4670  {
4671  if (all_vtbls[i]->cost_fn == &qo_zero_cost)
4672  {
4673  cost = '0';
4674  }
4675  else if (all_vtbls[i]->cost_fn == &qo_worst_cost)
4676  {
4677  cost = 'i';
4678  }
4679  else
4680  {
4681  cost = 'd';
4682  }
4683  break;
4684  }
4685  }
4686 
4687  return cost;
4688 }
4689 
4690 /*
4691  * qo_plan_set_cost_fn () - Changes the optimizer cost function for all plans
4692  * of the kind
4693  * return: nothing
4694  * plan_name(in): The name of a particular plan type
4695  * fn(in): The new setting for the optimizer cost unction for the plan
4696  *
4697  * Note: Useful for testing different optimizer strategies and for forcing
4698  * particular kinds of plans during testing
4699  */
4700 const char *
4701 qo_plan_set_cost_fn (const char *plan_name, int fn)
4702 {
4703  int n = DIM (all_vtbls);
4704  int i = 0;
4705 
4706  for (i = 0; i < n; i++)
4707  {
4708  if (intl_mbs_ncasecmp (plan_name, all_vtbls[i]->plan_string, strlen (all_vtbls[i]->plan_string)) == 0)
4709  {
4710  switch (fn)
4711  {
4712  case 0:
4713  case '0':
4714  case 'b': /* best */
4715  case 'B': /* BEST */
4716  case 'z': /* zero */
4717  case 'Z': /* ZERO */
4718  all_vtbls[i]->cost_fn = &qo_zero_cost;
4719  break;
4720 
4721  case 1:
4722  case '1':
4723  case 'i': /* infinite */
4724  case 'I': /* INFINITE */
4725  case 'w': /* worst */
4726  case 'W': /* WORST */
4727  all_vtbls[i]->cost_fn = &qo_worst_cost;
4728  break;
4729 
4730  default:
4731  all_vtbls[i]->cost_fn = all_vtbls[i]->default_cost;
4732  break;
4733  }
4734  return all_vtbls[i]->plan_string;
4735  }
4736  }
4737 
4738  return NULL;
4739 
4740 } /* qo_plan_set_cost_fn */
4741 
4742 /*
4743  * qo_set_cost () - csql method interface to qo_set_cost_fn()
4744  * return: nothing
4745  * target(in): The target of the method; we don't care
4746  * result(in): The result returned by the method; we don't care
4747  * plan(in): The plan type to get jacked
4748  * cost(in): The new cost for that plan type
4749  *
4750  * Note: This should get registered in the schema as
4751  *
4752  * alter class foo
4753  * add class method opt_set_cost(string, string)
4754  * function qo_set_cost;
4755  *
4756  * No libraries or other files are required, since this will
4757  * always be linked in to the base executable. Once linked, you
4758  * should be able to do things like
4759  *
4760  * call opt_set_cost("iscan", "0") on class foo
4761  *
4762  * from csql
4763  */
4764 void
4765 qo_set_cost (DB_OBJECT * target, DB_VALUE * result, DB_VALUE * plan, DB_VALUE * cost)
4766 {
4767  const char *plan_string;
4768  const char *cost_string;
4769 
4770  switch (DB_VALUE_TYPE (plan))
4771  {
4772  case DB_TYPE_STRING:
4773  case DB_TYPE_CHAR:
4774  case DB_TYPE_NCHAR:
4775  plan_string = db_get_string (plan);
4776  break;
4777  default:
4778  plan_string = "unknown";
4779  break;
4780  }
4781 
4782  switch (DB_VALUE_TYPE (cost))
4783  {
4784  case DB_TYPE_STRING:
4785  case DB_TYPE_CHAR:
4786  case DB_TYPE_NCHAR:
4787  cost_string = db_get_string (cost);
4788  break;
4789  default:
4790  cost_string = "d";
4791  break;
4792  }
4793 
4794  /*
4795  * This relies on the fact that qo_plan_set_cost_fn is returning a
4796  * CONST string. That way we don't need to dup it, and therefore we
4797  * won't leak it when the return value is discarded.
4798  */
4799  plan_string = qo_plan_set_cost_fn (plan_string, cost_string[0]);
4800  if (plan_string != NULL)
4801  {
4802  db_make_string (result, plan_string);
4803  }
4804  else
4805  {
4807  db_make_error (result, ER_GENERIC_ERROR);
4808  }
4809 }
4810 
4811 /*
4812  * qo_init_planvec () -
4813  * return:
4814  * planvec(in):
4815  */
4816 static void
4818 {
4819  int i;
4820 
4821  planvec->overflow = false;
4822  planvec->nplans = 0;
4823 
4824  for (i = 0; i < NPLANS; ++i)
4825  {
4826  planvec->plan[i] = (QO_PLAN *) NULL;
4827  }
4828 }
4829 
4830 /*
4831  * qo_uninit_planvec () -
4832  * return:
4833  * planvec(in):
4834  */
4835 static void
4837 {
4838  int i;
4839 
4840  for (i = 0; i < planvec->nplans; ++i)
4841  {
4842  qo_plan_del_ref (planvec->plan[i]);
4843  }
4844 
4845  planvec->overflow = false;
4846  planvec->nplans = 0;
4847 }
4848 
4849 /*
4850  * qo_dump_planvec () -
4851  * return:
4852  * planvec(in):
4853  * f(in):
4854  * indent(in):
4855  */
4856 static void
4857 qo_dump_planvec (QO_PLANVEC * planvec, FILE * f, int indent)
4858 {
4859  int i;
4860  int positive_indent = indent < 0 ? -indent : indent;
4861 
4862  if (planvec->overflow)
4863  {
4864  fputs ("(overflowed) ", f);
4865  }
4866 
4867  for (i = 0; i < planvec->nplans; ++i)
4868  {
4869  qo_plan_fprint (planvec->plan[i], f, indent, NULL);
4870  fputs ("\n\n", f);
4871  indent = positive_indent;
4872  }
4873 }
4874 
4875 /*
4876  * qo_check_planvec () -
4877  * return: one of {PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
4878  * planvec(in):
4879  * plan(in):
4880  */
4883 {
4884  /*
4885  * Check whether the new plan is definitely better than any of the
4886  * others. Keep it if it is, or if it is incomparable and we still
4887  * have room in the planvec. Return true if we keep the plan, false
4888  * if not.
4889  */
4890  int i;
4891  int already_retained;
4893  int num_eq;
4894 
4895  if (plan == NULL)
4896  {
4897  /* There is no new plan to be compared. */
4898  return PLAN_COMP_LT;
4899  }
4900 
4901  /* init */
4902  already_retained = 0;
4903  num_eq = 0;
4904 
4905  for (i = 0; i < planvec->nplans; i++)
4906  {
4907  cmp = qo_plan_cmp (planvec->plan[i], plan);
4908 
4909  /* cmp : PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT */
4910  if (cmp == PLAN_COMP_GT)
4911  {
4912  /*
4913  * The new plan is better than the previous one in the i'th
4914  * slot. Remove the old one, and if we haven't yet retained
4915  * the new one, put it in the freshly-available slot. If we
4916  * have already retained the plan, pull the last element down
4917  * from the end of the planvec and stuff it in this slot, and
4918  * then check this slot all over again. Don't forget to NULL
4919  * out the old last element.
4920  */
4921  if (already_retained)
4922  {
4923  planvec->nplans--;
4924  qo_plan_del_ref (planvec->plan[i]);
4925  planvec->plan[i] = (i < planvec->nplans) ? planvec->plan[planvec->nplans] : NULL;
4926  planvec->plan[planvec->nplans] = NULL;
4927  /*
4928  * Back up `i' so that we examine this slot again.
4929  */
4930  i--;
4931  }
4932  else
4933  {
4934  (void) qo_plan_add_ref (plan);
4935  qo_plan_del_ref (planvec->plan[i]);
4936  planvec->plan[i] = plan;
4937  }
4938  already_retained = 1;
4939  }
4940  else if (cmp == PLAN_COMP_EQ)
4941  {
4942  /* found equal cost plan already found */
4943  num_eq++;
4944  }
4945  else if (cmp == PLAN_COMP_LT)
4946  {
4947  /*
4948  * The new plan is worse than some plan that we already have.
4949  * There is no point in checking any others; give up and get
4950  * out.
4951  */
4952  return PLAN_COMP_LT;
4953  }
4954  }
4955 
4956  /*
4957  * Ok, we've looked at all of the current plans. It's possible to
4958  * get here and still not have retained the new plan if it couldn't
4959  * be determined whether it was definitely better or worse than any
4960  * of the plans we're already holding (or if we're not holding any).
4961  * Try to add it to the vector of plans.
4962  */
4963  if (!already_retained && !num_eq)
4964  { /* all is PLAN_COMP_UNK */
4965 
4966  if (i < NPLANS)
4967  {
4968  planvec->nplans++;
4969  (void) qo_plan_add_ref (plan);
4970  qo_plan_del_ref (planvec->plan[i]);
4971  planvec->plan[i] = plan;
4972  already_retained = 1;
4973  }
4974  else
4975  {
4976  int best_vc_pid, best_tc_pid;
4977  int worst_vc_pid, worst_tc_pid;
4978  double vc, tc, p_vc, p_tc;
4979  QO_PLAN *p;
4980 
4981  /*
4982  * We would like to keep this plan, but we're out of slots in
4983  * the planvec. For now, we just throw out one plan with the
4984  * highest access cost.
4985  */
4986 
4987  /* STEP 1: found best plan */
4988  best_vc_pid = best_tc_pid = -1; /* init */
4989 
4990  vc = plan->variable_cpu_cost + plan->variable_io_cost;
4991  tc = plan->fixed_cpu_cost + plan->fixed_io_cost + vc;
4992 
4993  for (i = 0; i < planvec->nplans; i++)
4994  {
4995  p = planvec->plan[i];
4996  p_vc = p->variable_cpu_cost + p->variable_io_cost;
4997  p_tc = p->fixed_cpu_cost + p->fixed_io_cost + p_vc;
4998 
4999  if (p_vc < vc)
5000  { /* found best variable cost plan */
5001  best_vc_pid = i;
5002  vc = p_vc; /* save best variable cost */
5003  }
5004 
5005  if (p_tc < tc)
5006  { /* found best total cost plan */
5007  best_tc_pid = i;
5008  tc = p_tc; /* save best total cost */
5009  }
5010  }
5011 
5012  /* STEP 2: found worst plan */
5013  worst_vc_pid = worst_tc_pid = -1; /* init */
5014 
5015  vc = plan->variable_cpu_cost + plan->variable_io_cost;
5016  tc = plan->fixed_cpu_cost + plan->fixed_io_cost + vc;
5017 
5018  for (i = 0; i < planvec->nplans; i++)
5019  {
5020  p = planvec->plan[i];
5021  p_vc = p->variable_cpu_cost + p->variable_io_cost;
5022  p_tc = p->fixed_cpu_cost + p->fixed_io_cost + p_vc;
5023 
5024  if (i != best_vc_pid && i != best_tc_pid)
5025  {
5026  if (p_vc > vc)
5027  { /* found worst variable cost plan */
5028  worst_vc_pid = i;
5029  vc = p_vc; /* save worst variable cost */
5030  }
5031 
5032  if (p_tc > tc)
5033  { /* found worst total cost plan */
5034  worst_tc_pid = i;
5035  tc = p_tc; /* save worst total cost */
5036  }
5037  }
5038  }
5039 
5040  if (worst_tc_pid != -1)
5041  { /* release worst total cost plan */
5042  (void) qo_plan_add_ref (plan);
5043  qo_plan_del_ref (planvec->plan[worst_tc_pid]);
5044  planvec->plan[worst_tc_pid] = plan;
5045  already_retained = 1;
5046  }
5047  else if (worst_vc_pid != -1)
5048  { /* release worst variable cost plan */
5049  (void) qo_plan_add_ref (plan);
5050  qo_plan_del_ref (planvec->plan[worst_vc_pid]);
5051  planvec->plan[worst_vc_pid] = plan;
5052  already_retained = 1;
5053  }
5054  else
5055  {
5056  /*
5057  * The new plan is worse than some plan that we already have.
5058  * There is no point in checking any others; give up and get
5059  * out.
5060  */
5061  return PLAN_COMP_LT;
5062  }
5063  }
5064  }
5065 
5066  if (already_retained)
5067  {
5068  return PLAN_COMP_GT;
5069  }
5070  else if (num_eq)
5071  {
5072  return PLAN_COMP_EQ;
5073  }
5074 
5075  return cmp;
5076 }
5077 
5078 /*
5079  * qo_cmp_planvec () -
5080  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
5081  * planvec(in):
5082  * plan(in):
5083  */
5085 qo_cmp_planvec (QO_PLANVEC * planvec, QO_PLAN * plan)
5086 {
5087  int i;
5089 
5090  cmp = PLAN_COMP_UNK; /* init */
5091 
5092  for (i = 0; i < planvec->nplans; i++)
5093  {
5094  cmp = qo_plan_cmp (planvec->plan[i], plan);
5095  if (cmp != PLAN_COMP_UNK)
5096  {
5097  return cmp;
5098  }
5099  }
5100 
5101  /* at here, all is PLAN_COMP_UNK */
5102 
5103  return cmp;
5104 }
5105 
5106 /*
5107  * qo_find_best_plan_on_planvec () -
5108  * return:
5109  * planvec(in):
5110  * n(in):
5111  */
5112 static QO_PLAN *
5114 {
5115  int i;
5116  QO_PLAN *best_plan, *plan;
5117  double fixed, variable, best_cost, cost;
5118 
5119  /* While initializing the cost to QO_INFINITY and starting the loop at i = 0 might look equivalent to this, it
5120  * actually loses if all of the elements in the vector have cost QO_INFINITY, because the comparison never succeeds
5121  * and we never make plan non-NULL. This is very bad for those callers above who believe that we're returning
5122  * something useful.
5123  */
5124 
5125  best_plan = planvec->plan[0];
5126  fixed = best_plan->fixed_cpu_cost + best_plan->fixed_io_cost;
5127  variable = best_plan->variable_cpu_cost + best_plan->variable_io_cost;
5128  best_cost = fixed + (n * variable);
5129  for (i = 1; i < planvec->nplans; i++)
5130  {
5131  plan = planvec->plan[i];
5132  fixed = plan->fixed_cpu_cost + plan->fixed_io_cost;
5133  variable = plan->variable_cpu_cost + plan->variable_io_cost;
5134  cost = fixed + (n * variable);
5135 
5136  if (cost < best_cost)
5137  {
5138  best_plan = plan;
5139  best_cost = cost;
5140  }
5141  }
5142 
5143  return best_plan;
5144 }
5145 
5146 /*
5147  * An Info node is associated with a combination of join expressions, and
5148  * holds plans for producing the result described by that combination.
5149  * At any time, the node holds the best plans we have yet encountered for
5150  * producing the result in any of the interesting orders (including the
5151  * best way we know of when order is not a concern). Of course, for many
5152  * join combinations, it will be impossible to produce a result in a
5153  * given order (i.e., when that order is based on an attribute of a
5154  * relation that doesn't participate in the particular combination). In
5155  * these cases we simply record a NULL plan for that order.
5156  */
5157 
5158 /*
5159  * qo_info_nodes_init () -
5160  * return:
5161  * env(in):
5162  */
5163 static void
5165 {
5166  infos_allocated = 0;
5167  infos_deallocated = 0;
5168 }
5169 
5170 /*
5171  * qo_alloc_info () -
5172  * return:
5173  * planner(in):
5174  * nodes(in):
5175  * terms(in):
5176  * eqclasses(in):
5177  * cardinality(in):
5178  */
5179 static QO_INFO *
5180 qo_alloc_info (QO_PLANNER * planner, BITSET * nodes, BITSET * terms, BITSET * eqclasses, double cardinality)
5181 {
5182  QO_INFO *info;
5183  int i;
5184  int EQ;
5185 
5186  info = (QO_INFO *) malloc (sizeof (QO_INFO));
5187  if (info == NULL)
5188  {
5190  return NULL;
5191  }
5192 
5193  i = 0;
5194  EQ = planner->EQ;
5195 
5196  info->env = planner->env;
5197  info->planner = planner;
5198 
5199  bitset_init (&(info->nodes), planner->env);
5200  bitset_init (&(info->terms), planner->env);
5201  bitset_init (&(info->eqclasses), planner->env);
5202  bitset_init (&(info->projected_segs), planner->env);
5203 
5204  bitset_assign (&info->nodes, nodes);
5205  bitset_assign (&info->terms, terms);
5206  bitset_assign (&info->eqclasses, eqclasses);
5207  qo_compute_projected_segs (planner, nodes, terms, &info->projected_segs);
5208  info->projected_size = qo_compute_projected_size (planner, &info->projected_segs);
5209  info->cardinality = cardinality;
5210 
5211  qo_init_planvec (&info->best_no_order);
5212 
5213  /*
5214  * Set aside an array for ordered plans. Each element of the array
5215  * holds a plan that is ordered according to the corresponding
5216  * equivalence class.
5217  *
5218  * If this malloc() fails, we'll lose the memory pointed to by
5219  * info. I'll take the chance.
5220  */
5221  info->planvec = NULL;
5222  if (EQ > 0)
5223  {
5224  info->planvec = (QO_PLANVEC *) malloc (sizeof (QO_PLANVEC) * EQ);
5225  if (info->planvec == NULL)
5226  {
5228  free_and_init (info);
5229  return NULL;
5230  }
5231  }
5232 
5233  for (i = 0; i < EQ; ++i)
5234  {
5235  qo_init_planvec (&info->planvec[i]);
5236  }
5237 
5238  info->join_unit = planner->join_unit; /* init */
5239 
5240  info->detached = false;
5241 
5242  infos_allocated++;
5243 
5244  /* insert into the head of alloced info list */
5245  info->next = planner->info_list;
5246  planner->info_list = info;
5247 
5248  return info;
5249 }
5250 
5251 /*
5252  * qo_free_info () -
5253  * return:
5254  * info(in):
5255  */
5256 static void
5258 {
5259  if (info == NULL)
5260  {
5261  return;
5262  }
5263 
5264  qo_detach_info (info);
5265 
5266  bitset_delset (&(info->nodes));
5267  bitset_delset (&(info->terms));
5268  bitset_delset (&(info->eqclasses));
5269  bitset_delset (&(info->projected_segs));
5270 
5271  free_and_init (info);
5272 
5274 }
5275 
5276 /*
5277  * qo_detach_info () -
5278  * return:
5279  * info(in):
5280  */
5281 static void
5283 {
5284  /*
5285  * If the node hasn't already been detached, detach it now and give
5286  * up references to all plans that are no longer needed.
5287  */
5288  if (!info->detached)
5289  {
5290  int i;
5291  int EQ = info->planner->EQ;
5292 
5293  for (i = 0; i < EQ; ++i)
5294  {
5295  qo_uninit_planvec (&info->planvec[i]);
5296  }
5297  free_and_init (info->planvec);
5298  info->detached = true;
5299 
5301  }
5302 }
5303 
5304 /*
5305  * qo_check_new_best_plan_on_info () -
5306  * return:
5307  * info(in):
5308  * plan(in):
5309  */
5310 static bool
5312 {
5314  QO_EQCLASS *order;
5315 
5316  order = plan->order;
5317  if (order && bitset_is_empty (&(QO_EQCLASS_SEGS (order))))
5318  {
5319  /* Then this "equivalence class" is a phony fabricated especially for a complex merge term. skip out */
5320  cmp = PLAN_COMP_LT;
5321  }
5322  else
5323  {
5324  cmp = qo_check_planvec (&info->best_no_order, plan);
5325 
5326  if (cmp == PLAN_COMP_GT)
5327  {
5328  if (plan->plan_type != QO_PLANTYPE_SORT || plan->plan_un.sort.sort_type != SORT_LIMIT)
5329  {
5330  int i, EQ;
5331  QO_PLAN *new_plan, *sort_plan, *best_plan;
5332  QO_ENV *env;
5333  QO_PLAN_COMPARE_RESULT new_cmp;
5334 
5335  env = info->env;
5336 
5337  EQ = info->planner->EQ;
5338  best_plan = qo_find_best_plan_on_planvec (&info->best_no_order, 1.0);
5339  if (QO_ENV_USE_SORT_LIMIT (env) == QO_SL_USE && !best_plan->has_sort_limit
5341  && !qo_plan_is_orderby_skip_candidate (best_plan))
5342  {
5343  /* generate a SORT_LIMIT plan over this plan */
5344  sort_plan = qo_sort_new (best_plan, QO_UNORDERED, SORT_LIMIT);
5345  if (sort_plan != NULL)
5346  {
5347  if (qo_check_plan_on_info (info, sort_plan) > 0)
5348  {
5349  best_plan = sort_plan;
5350  }
5351  }
5352  }
5353  /*
5354  * Check to see if any of the ordered solutions can be made
5355  * cheaper by sorting this new plan.
5356  */
5357  for (i = 0; i < EQ; i++)
5358  {
5359  order = &info->planner->eqclass[i];
5360 
5361  new_plan = qo_plan_order_by (best_plan, order);
5362  if (new_plan)
5363  {
5364  new_cmp = qo_check_planvec (&info->planvec[i], new_plan);
5365  if (new_cmp == PLAN_COMP_LT || new_cmp == PLAN_COMP_EQ)
5366  {
5367  qo_plan_release (new_plan);
5368  }
5369  }
5370  }
5371  }
5372  }
5373  }
5374 
5375  if (cmp == PLAN_COMP_LT || cmp == PLAN_COMP_EQ)
5376  {
5377  qo_plan_release (plan);
5378  return false;
5379  }
5380 
5381  return true;
5382 }
5383 
5384 /*
5385  * qo_check_plan_on_info () -
5386  * return:
5387  * info(in):
5388  * plan(in):
5389  */
5390 static int
5392 {
5393  QO_INFO *best_info;
5394  QO_EQCLASS *plan_order;
5396  bool found_new_best;
5397 
5398  if (info == NULL || plan == NULL)
5399  {
5400  return 0;
5401  }
5402 
5403  /* init */
5404  found_new_best = false;
5405  best_info = info->planner->best_info;
5406  plan_order = plan->order;
5407 
5408  /* if the plan is of type QO_SCANMETHOD_INDEX_ORDERBY_SCAN but it doesn't skip the orderby, we release the plan. */
5409  if (qo_is_iscan_from_orderby (plan) && !plan->plan_un.scan.index->head->orderby_skip)
5410  {
5411  qo_plan_release (plan);
5412  return 0;
5413  }
5414 
5415  /* if the plan is of type QO_SCANMETHOD_INDEX_GRUOPBY_SCAN but it doesn't skip the groupby, we release the plan. */
5416  if (qo_is_iscan_from_groupby (plan) && !plan->plan_un.scan.index->head->groupby_skip)
5417  {
5418  qo_plan_release (plan);
5419  return 0;
5420  }
5421 
5422  /*
5423  * If the cost of the new Plan already exceeds the cost of the best
5424  * known solution with the same order, there is no point in
5425  * remembering the new plan.
5426  */
5427  if (best_info)
5428  {
5429  cmp =
5430  qo_cmp_planvec (plan_order ==
5431  QO_UNORDERED ? &best_info->best_no_order : &best_info->planvec[QO_EQCLASS_IDX (plan_order)],
5432  plan);
5433  /* cmp : PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT */
5434  if (cmp == PLAN_COMP_LT || cmp == PLAN_COMP_EQ)
5435  {
5436  qo_plan_release (plan);
5437  return 0;
5438  }
5439  }
5440 
5441  /*
5442  * The only time we will keep an unordered plan is if it is cheaper
5443  * than any other plan we have seen so far (ordered or unordered).
5444  * Only ordered plans are kept in the _plan vector.
5445  */
5446  if (plan_order == QO_UNORDERED)
5447  {
5448  found_new_best = qo_check_new_best_plan_on_info (info, plan);
5449  }
5450  else
5451  {
5452  /*
5453  * If we get here, we are dealing with an ordered plan. Check
5454  * whether we already have memo-ized a plan for this particular scan
5455  * order. If so, see if this new plan is an improvement.
5456  */
5457 
5458  cmp = qo_check_planvec (&info->planvec[QO_EQCLASS_IDX (plan_order)], plan);
5459  if (cmp == PLAN_COMP_GT)
5460  {
5461  (void) qo_check_new_best_plan_on_info (info, plan);
5462  found_new_best = true;
5463  }
5464  else
5465  {
5466  qo_plan_release (plan);
5467  return 0;
5468  }
5469  }
5470 
5471  if (found_new_best != true)
5472  {
5473  return 0;
5474  }
5475 
5476  /* save the last join level; used for cache */
5477  info->join_unit = info->planner->join_unit;
5478 
5479  return 1;
5480 }
5481 
5482 /*
5483  * qo_find_best_nljoin_inner_plan_on_info () -
5484  * return:
5485  * outer(in):
5486  * info(in):
5487  * join_type(in):
5488  * idx_join_plan_n(in):
5489  */
5490 static QO_PLAN *
5491 qo_find_best_nljoin_inner_plan_on_info (QO_PLAN * outer, QO_INFO * info, JOIN_TYPE join_type, int idx_join_plan_n)
5492 {
5493  QO_PLANVEC *pv;
5494  QO_PLAN *temp, *best_plan, *inner;
5495  double temp_cost, best_cost;
5496  int i;
5497 
5498  /* init */
5499  best_plan = NULL;
5500  best_cost = 0;
5501 
5502  /* alloc temporary nl-join plan */
5503  temp = qo_plan_malloc (info->env);
5504  if (temp == NULL)
5505  {
5506  return NULL;
5507  }
5508 
5509  temp->info = info;
5510  temp->refcount = 0;
5511  temp->top_rooted = false;
5512  temp->well_rooted = false;
5513  temp->iscan_sort_list = NULL;
5514  temp->analytic_eval_list = NULL;
5515 
5516  temp->plan_un.join.join_type = join_type; /* set nl-join type */
5517  temp->plan_un.join.outer = outer; /* set outer */
5518 
5520 
5521  for (i = 0, pv = &info->best_no_order; i < pv->nplans; i++)
5522  {
5523  inner = pv->plan[i]; /* set inner */
5524 
5525  /* if already found idx-join, then exclude sequential inner */
5526  if (idx_join_plan_n > 0)
5527  {
5528  if (qo_is_seq_scan (inner) || inner->has_sort_limit)
5529  {
5530  continue;
5531  }
5532  }
5533 
5534  temp->plan_un.join.inner = inner;
5535  qo_nljoin_cost (temp);
5536  temp_cost = temp->fixed_cpu_cost + temp->fixed_io_cost + temp->variable_cpu_cost + temp->variable_io_cost;
5537  if (best_plan == NULL || temp_cost < best_cost)
5538  {
5539  /* save new best inner */
5540  best_cost = temp_cost;
5541  best_plan = inner;
5542  }
5543  }
5544 
5545  /* free temp plan */
5546  temp->plan_un.join.outer = NULL;
5547  temp->plan_un.join.inner = NULL;
5548 
5550 
5551  return best_plan;
5552 }
5553 
5554 /*
5555  * qo_find_best_plan_on_info () -
5556  * return:
5557  * info(in):
5558  * order(in):
5559  * n(in):
5560  */
5561 static QO_PLAN *
5563 {
5564  QO_PLANVEC *pv;
5565 
5566  if (order == QO_UNORDERED)
5567  {
5568  pv = &info->best_no_order;
5569  }
5570  else
5571  {
5572  int order_idx = QO_EQCLASS_IDX (order);
5573  if (info->planvec[order_idx].nplans == 0)
5574  {
5575  QO_PLAN *planp;
5576 
5577  planp = qo_sort_new (qo_find_best_plan_on_planvec (&info->best_no_order, n), order, SORT_TEMP);
5578 
5579  qo_check_planvec (&info->planvec[order_idx], planp);
5580  }
5581  pv = &info->planvec[order_idx];
5582  }
5583 
5584  return qo_find_best_plan_on_planvec (pv, n);
5585 }
5586 
5587 /*
5588  * qo_examine_idx_join () -
5589  * return:
5590  * info(in):
5591  * join_type(in):
5592  * outer(in):
5593  * inner(in):
5594  * afj_terms(in):
5595  * sarged_terms(in):
5596  * pinned_subqueries(in):
5597  */
5598 static int
5599 qo_examine_idx_join (QO_INFO * info, JOIN_TYPE join_type, QO_INFO * outer, QO_INFO * inner, BITSET * afj_terms,
5600  BITSET * sarged_terms, BITSET * pinned_subqueries)
5601 {
5602  int n = 0;
5603  QO_NODE *inner_node;
5604 
5605  /* check for right outer join; */
5606  if (join_type == JOIN_RIGHT)
5607  {
5608  if (bitset_cardinality (&(outer->nodes)) != 1)
5609  { /* not single class spec */
5610  /* inner of correlated index join should be plain class access */
5611  goto exit;
5612  }
5613 
5614  inner_node = QO_ENV_NODE (outer->env, bitset_first_member (&(outer->nodes)));
5615  if (QO_NODE_HINT (inner_node) & PT_HINT_ORDERED)
5616  {
5617  /* join hint: force join left-to-right; skip idx-join because, these are only support left outer join */
5618  goto exit;
5619  }
5620  }
5621  else
5622  {
5623  inner_node = QO_ENV_NODE (inner->env, bitset_first_member (&(inner->nodes)));
5624  }
5625 
5626  /* inner is single class spec */
5627  if (QO_NODE_HINT (inner_node) & (PT_HINT_USE_IDX | PT_HINT_USE_NL))
5628  {
5629  /* join hint: force idx-join */
5630  }
5631  else if (QO_NODE_HINT (inner_node) & PT_HINT_USE_MERGE)
5632  {
5633  /* join hint: force merge-join; skip idx-join */
5634  goto exit;
5635  }
5636 
5637  /* check whether we can build a nested loop join with a correlated index scan. That is, is the inner term a scan of a
5638  * single node, and can this join term be used as an index with respect to that node? If so, we can build a special
5639  * kind of plan to exploit that.
5640  */
5641  if (join_type == JOIN_RIGHT)
5642  {
5643  /* if right outer join, select outer plan from the inner node and inner plan from the outer node, and do left
5644  * outer join
5645  */
5646  n = qo_examine_correlated_index (info, JOIN_LEFT, inner, outer, afj_terms, sarged_terms, pinned_subqueries);
5647  }
5648  else
5649  {
5650  n = qo_examine_correlated_index (info, join_type, outer, inner, afj_terms, sarged_terms, pinned_subqueries);
5651  }
5652 
5653 exit:
5654 
5655  return n;
5656 }
5657 
5658 /*
5659  * qo_examine_nl_join () -
5660  * return:
5661  * info(in):
5662  * join_type(in):
5663  * outer(in):
5664  * inner(in):
5665  * nl_join_terms(in):
5666  * duj_terms(in):
5667  * afj_terms(in):
5668  * sarged_terms(in):
5669  * pinned_subqueries(in):
5670  * idx_join_plan_n(in):
5671  */
5672 static int
5673 qo_examine_nl_join (QO_INFO * info, JOIN_TYPE join_type, QO_INFO * outer, QO_INFO * inner, BITSET * nl_join_terms,
5674  BITSET * duj_terms, BITSET * afj_terms, BITSET * sarged_terms, BITSET * pinned_subqueries,
5675  int idx_join_plan_n, BITSET * hash_terms)
5676 {
5677  int n = 0;
5678  QO_PLAN *outer_plan, *inner_plan;
5679  QO_NODE *inner_node;
5680 
5681  if (join_type == JOIN_RIGHT)
5682  {
5683  /* converse outer join type */
5684  join_type = JOIN_LEFT;
5685 
5686  if (bitset_intersects (sarged_terms, &(info->env->fake_terms)))
5687  {
5688  goto exit;
5689  }
5690 
5691  {
5692  int t;
5693  QO_TERM *term;
5694  BITSET_ITERATOR iter;
5695 
5696  for (t = bitset_iterate (nl_join_terms, &iter); t != -1; t = bitset_next_member (&iter))
5697  {
5698  term = QO_ENV_TERM (info->env, t);
5699  if (QO_TERM_CLASS (term) == QO_TC_DEP_LINK)
5700  {
5701  goto exit;
5702  }
5703  } /* for (t = ...) */
5704  }
5705 
5706  if (bitset_cardinality (&(outer->nodes)) == 1)
5707  { /* single class spec */
5708  inner_node = QO_ENV_NODE (outer->env, bitset_first_member (&(outer->nodes)));
5709  if (QO_NODE_HINT (inner_node) & PT_HINT_ORDERED)
5710  {
5711  /* join hint: force join left-to-right; skip idx-join because, these are only support left outer join */
5712  goto exit;
5713  }
5714 
5715  if (QO_NODE_HINT (inner_node) & PT_HINT_USE_NL)
5716  {
5717  /* join hint: force nl-join */
5718  }
5719  else if (QO_NODE_HINT (inner_node) & (PT_HINT_USE_IDX | PT_HINT_USE_MERGE))
5720  {
5721  /* join hint: force idx-join or merge-join; skip nl-join */
5722  goto exit;
5723  }
5724  }
5725 
5726  outer_plan = qo_find_best_plan_on_info (inner, QO_UNORDERED, 1.0);
5727  if (outer_plan == NULL)
5728  {
5729  goto exit;
5730  }
5731  inner_plan = qo_find_best_nljoin_inner_plan_on_info (outer_plan, outer, join_type, idx_join_plan_n);
5732  if (inner_plan == NULL)
5733  {
5734  goto exit;
5735  }
5736  }
5737  else
5738  {
5739  /* At here, inner is single class spec */
5740  inner_node = QO_ENV_NODE (inner->env, bitset_first_member (&(inner->nodes)));
5741  if (QO_NODE_HINT (inner_node) & PT_HINT_USE_NL)
5742  {
5743  /* join hint: force nl-join */
5744  }
5745  else if (QO_NODE_HINT (inner_node) & (PT_HINT_USE_IDX | PT_HINT_USE_MERGE))
5746  {
5747  /* join hint: force idx-join or merge-join; skip nl-join */
5748  goto exit;
5749  }
5750 
5751  outer_plan = qo_find_best_plan_on_info (outer, QO_UNORDERED, 1.0);
5752  if (outer_plan == NULL)
5753  {
5754  goto exit;
5755  }
5756  inner_plan = qo_find_best_nljoin_inner_plan_on_info (outer_plan, inner, join_type, idx_join_plan_n);
5757  if (inner_plan == NULL)
5758  {
5759  goto exit;
5760  }
5761  }
5762 
5763 #if 0 /* CHAINS_ONLY */
5764  /* If CHAINS_ONLY is defined, we want the optimizer constrained to produce only left-linear trees of joins, i.e., no
5765  * inner term can itself be a join or a follow.
5766  */
5767 
5768  if (inner_plan->plan_type != QO_PLANTYPE_SCAN)
5769  {
5770  if (inner_plan->plan_type == QO_PLANTYPE_SORT && inner_plan->order == QO_UNORDERED)
5771  {
5772  /* inner has temporary list file plan; it's ok */
5773  ;
5774  }
5775  else
5776  {
5777  goto exit;
5778  }
5779  }
5780 #endif /* CHAINS_ONLY */
5781 
5782 #if 0 /* JOIN_FOLLOW_RESTRICTION */
5783  /* Under this restriction, we are not permitted to produce plans that have follow nodes sandwiched between joins.
5784  * Don't ask why.
5785  */
5786 
5787  if (outer_plan->plan_type == QO_PLANTYPE_FOLLOW && QO_PLAN_SUBJOINS (outer_plan))
5788  {
5789  goto exit;
5790  }
5791  if (inner_plan->plan_type == QO_PLANTYPE_FOLLOW && QO_PLAN_SUBJOINS (inner_plan))
5792  {
5793  goto exit;
5794  }
5795 #endif /* JOIN_FOLLOW_RESTRICTION */
5796 
5797  /* look for the best nested loop solution we can find. Since the subnodes are already keeping track of the
5798  * lowest-cost plan they have seen, we needn't do any search here to find the cheapest nested loop join we can
5799  * produce for this combination.
5800  */
5801  n =
5802  qo_check_plan_on_info (info,
5803  qo_join_new (info, join_type, QO_JOINMETHOD_NL_JOIN, outer_plan, inner_plan, nl_join_terms,
5804  duj_terms, afj_terms, sarged_terms, pinned_subqueries, hash_terms));
5805 
5806 exit:
5807 
5808  return n;
5809 }
5810 
5811 /*
5812  * qo_examine_merge_join () -
5813  * return:
5814  * info(in):
5815  * join_type(in):
5816  * outer(in):
5817  * inner(in):
5818  * sm_join_terms(in):
5819  * duj_terms(in):
5820  * afj_terms(in):
5821  * sarged_terms(in):
5822  * pinned_subqueries(in):
5823  */
5824 static int
5825 qo_examine_merge_join (QO_INFO * info, JOIN_TYPE join_type, QO_INFO * outer, QO_INFO * inner, BITSET * sm_join_terms,
5826  BITSET * duj_terms, BITSET * afj_terms, BITSET * sarged_terms, BITSET * pinned_subqueries)
5827 {
5828  int n = 0;
5829  QO_PLAN *outer_plan, *inner_plan;
5830  QO_NODE *inner_node;
5831  QO_EQCLASS *order = QO_UNORDERED;
5832  int t;
5833  BITSET_ITERATOR iter;
5834  QO_TERM *term;
5835  BITSET empty_terms;
5836  bitset_init (&empty_terms, info->env);
5837 
5838  /* If any of the sarged terms are fake terms, we can't implement this join as a merge join, because the timing
5839  * assumptions required by the fake terms won't be satisfied. Nested loops are the only joins that will work.
5840  */
5841  if (bitset_intersects (sarged_terms, &(info->env->fake_terms)))
5842  {
5843  goto exit;
5844  }
5845 
5846  /* examine ways of producing ordered results. For each ordering, check whether the inner and outer subresults can be
5847  * produced in that order. If so, check a merge join plan on that order.
5848  */
5849  for (t = bitset_iterate (sm_join_terms, &iter); t != -1; t = bitset_next_member (&iter))
5850  {
5851  term = QO_ENV_TERM (info->env, t);
5852  order = QO_TERM_EQCLASS (term);
5853  if (order != QO_UNORDERED)
5854  {
5855  break;
5856  }
5857  }
5858 
5859  if (order == QO_UNORDERED)
5860  {
5861  goto exit;
5862  }
5863 
5864 #ifdef OUTER_MERGE_JOIN_RESTRICTION
5865  if (IS_OUTER_JOIN_TYPE (join_type))
5866  {
5867  int node_idx;
5868 
5869  term = QO_ENV_TERM (info->env, bitset_first_member (sm_join_terms));
5870  node_idx = (join_type == JOIN_LEFT) ? QO_NODE_IDX (QO_TERM_HEAD (term)) : QO_NODE_IDX (QO_TERM_TAIL (term));
5871  for (t = bitset_iterate (duj_terms, &iter); t != -1; t = bitset_next_member (&iter))
5872  {
5873  term = QO_ENV_TERM (info->env, t);
5874  if (!BITSET_MEMBER (QO_TERM_NODES (term), node_idx))
5875  {
5876  goto exit;
5877  }
5878  }
5879  }
5880 #endif /* OUTER_MERGE_JOIN_RESTRICTION */
5881 
5882  /* At here, inner is single class spec */
5883  inner_node = QO_ENV_NODE (inner->env, bitset_first_member (&(inner->nodes)));
5884 
5885  if (QO_NODE_HINT (inner_node) & PT_HINT_USE_MERGE)
5886  {
5887  /* join hint: force m-join; */
5888  }
5889  else if (QO_NODE_HINT (inner_node) & (PT_HINT_USE_NL | PT_HINT_USE_IDX))
5890  {
5891  /* join hint: force nl-join, idx-join; */
5892  goto exit;
5893  }
5895  {
5896  /* optimizer prm: keep out m-join; */
5897  goto exit;
5898  }
5899 
5900  outer_plan = qo_find_best_plan_on_info (outer, order, 1.0);
5901  if (outer_plan == NULL)
5902  {
5903  goto exit;
5904  }
5905 
5906  inner_plan = qo_find_best_plan_on_info (inner, order, 1.0);
5907  if (inner_plan == NULL)
5908  {
5909  goto exit;
5910  }
5911 
5912 #ifdef CHAINS_ONLY
5913  /* If CHAINS_ONLY is defined, we want the optimizer constrained to produce only left-linear trees of joins, i.e., no
5914  * inner term can itself be a join or a follow.
5915  */
5916 
5917  if (inner_plan->plan_type != QO_PLANTYPE_SCAN)
5918  {
5919  if (inner_plan->plan_type == QO_PLANTYPE_SORT && inner_plan->order == QO_UNORDERED)
5920  {
5921  /* inner has temporary list file plan; it's ok */
5922  ;
5923  }
5924  else
5925  {
5926  goto exit;
5927  }
5928  }
5929 #endif /* CHAINS_ONLY */
5930 
5931 #if 0 /* JOIN_FOLLOW_RESTRICTION */
5932  /* Under this restriction, we are not permitted to produce plans that have follow nodes sandwiched between joins.
5933  * Don't ask why.
5934  */
5935 
5936  if (outer_plan->plan_type == QO_PLANTYPE_FOLLOW && QO_PLAN_SUBJOINS (outer_plan))
5937  {
5938  goto exit;
5939  }
5940  if (inner_plan->plan_type == QO_PLANTYPE_FOLLOW && QO_PLAN_SUBJOINS (inner_plan))
5941  {
5942  goto exit;
5943  }
5944 #endif /* JOIN_FOLLOW_RESTRICTION */
5945 
5946  n =
5947  qo_check_plan_on_info (info,
5948  qo_join_new (info, join_type, QO_JOINMETHOD_MERGE_JOIN, outer_plan, inner_plan,
5949  sm_join_terms, duj_terms, afj_terms, sarged_terms, pinned_subqueries,
5950  &empty_terms));
5951 
5952 exit:
5953 
5954  return n;
5955 }
5956 
5957 /*
5958  * qo_examine_correlated_index () -
5959  * return: int
5960  * info(in): The info node to be corresponding to the join being investigated
5961  * join_type(in):
5962  * outer(in): The info node for the outer join operand
5963  * inner(in): The info node for the inner join operand
5964  * afj_terms(in): The term being used to join the operands
5965  * sarged_terms(in): The residual terms to be evaluated at this level of
5966  * the plan tree
5967  * pinned_subqueries(in): The subqueries to be pinned to plans at this node
5968  *
5969  * Note: Check whether we can build a nested loop join that implements
5970  * the join term as a correlated index on the inner term.
5971  * Operationally, such a join looks something like
5972  *
5973  * for (every record in the outer term)
5974  * {
5975  * parameterize join term with values
5976  * from outer record;
5977  * do index scan on inner node;
5978  * for (every record in inner scan)
5979  * {
5980  * join outer and inner records;
5981  * }
5982  * }
5983  */
5984 static int
5985 qo_examine_correlated_index (QO_INFO * info, JOIN_TYPE join_type, QO_INFO * outer, QO_INFO * inner, BITSET * afj_terms,
5986  BITSET * sarged_terms, BITSET * pinned_subqueries)
5987 {
5988  QO_NODE *nodep;
5989  QO_NODE_INDEX *node_indexp;
5990  QO_NODE_INDEX_ENTRY *ni_entryp;
5991  QO_INDEX_ENTRY *index_entryp;
5992  QO_PLAN *outer_plan;
5993  int i, n = 0;
5994  BITSET_ITERATOR iter;
5995  int t;
5996  QO_TERM *termp;
5997  int num_only_args;
5998  BITSET indexable_terms;
5999 
6000  /* outer plan */
6001  outer_plan = qo_find_best_plan_on_info (outer, QO_UNORDERED, 1.0);
6002  if (outer_plan == NULL)
6003  {
6004  return 0;
6005  }
6006 
6007 #if 0 /* JOIN_FOLLOW_RESTRICTION */
6008  /* Under this restriction, we are not permitted to produce plans that have follow nodes sandwiched between joins.
6009  * Don't ask why.
6010  */
6011 
6012  if (outer_plan->plan_type == QO_PLANTYPE_FOLLOW && QO_PLAN_SUBJOINS (outer_plan))
6013  {
6014  return 0;
6015  }
6016 #endif /* JOIN_FOLLOW_RESTRICTION */
6017 
6018  /* inner node and its indexes */
6019  nodep = &info->planner->node[bitset_first_member (&(inner->nodes))];
6020  node_indexp = QO_NODE_INDEXES (nodep);
6021  if (node_indexp == NULL)
6022  {
6023  /* inner does not have any usable index */
6024  return 0;
6025  }
6026 
6027  bitset_init (&indexable_terms, info->env);
6028 
6029  /* We're interested in all of the terms so combine 'join_term' and 'sarged_terms' together. */
6030  if (IS_OUTER_JOIN_TYPE (join_type))
6031  {
6032  for (t = bitset_iterate (sarged_terms, &iter); t != -1; t = bitset_next_member (&iter))
6033  {
6034 
6035  termp = QO_ENV_TERM (QO_NODE_ENV (nodep), t);
6036 
6037  if (QO_TERM_CLASS (termp) == QO_TC_AFTER_JOIN)
6038  {
6039  /* exclude after-join term in 'sarged_terms' */
6040  continue;
6041  }
6042 
6043  bitset_add (&indexable_terms, t);
6044  }
6045  }
6046  else
6047  {
6048  bitset_union (&indexable_terms, sarged_terms);
6049  }
6050 
6051  /* finally, combine inner plan's 'sarg term' together */
6052  bitset_union (&indexable_terms, &(QO_NODE_SARGS (nodep)));
6053 
6054  num_only_args = 0; /* init */
6055 
6056  /* Iterate through the indexes attached to this node and look for ones which are a subset of the terms that we're
6057  * interested in. For each applicable index, register a plans and compute the cost.
6058  */
6059  for (i = 0; i < QO_NI_N (node_indexp); i++)
6060  {
6061  /* pointer to QO_NODE_INDEX_ENTRY structure */
6062  ni_entryp = QO_NI_ENTRY (node_indexp, i);
6063  /* pointer to QO_INDEX_ENTRY structure */
6064  index_entryp = (ni_entryp)->head;
6065  if (index_entryp->force < 0)
6066  {
6067  continue; /* is disabled index; skip and go ahead */
6068  }
6069 
6070  /* the index has terms which are a subset of the terms that we're interested in */
6071  if (bitset_intersects (&indexable_terms, &(index_entryp->terms)))
6072  {
6073 
6074  if (!bitset_intersects (sarged_terms, &(index_entryp->terms)))
6075  {
6076  /* there is not join-edge, only inner sargs */
6077  num_only_args++;
6078  continue;
6079  }
6080 
6081  /* generate join index scan using 'ni_entryp' */
6082  n +=
6083  qo_generate_join_index_scan (info, join_type, outer_plan, inner, nodep, ni_entryp, &indexable_terms,
6084  afj_terms, sarged_terms, pinned_subqueries);
6085  }
6086  }
6087 
6088  if (QO_NODE_HINT (nodep) & PT_HINT_USE_IDX)
6089  {
6090  /* join hint: force idx-join */
6091  if (n == 0 && num_only_args)
6092  { /* not found 'idx-join' plan */
6093  /* Re-Iterate */
6094  for (i = 0; i < QO_NI_N (node_indexp); i++)
6095  {
6096  /* pointer to QO_NODE_INDEX_ENTRY structure */
6097  ni_entryp = QO_NI_ENTRY (node_indexp, i);
6098  /* pointer to QO_INDEX_ENTRY structure */
6099  index_entryp = (ni_entryp)->head;
6100  if (index_entryp->force < 0)
6101  {
6102  continue; /* is disabled index; skip and go ahead */
6103  }
6104 
6105  /* the index has terms which are a subset of the terms that we're intersted in */
6106  if (bitset_intersects (&indexable_terms, &(index_entryp->terms)))
6107  {
6108  if (bitset_intersects (sarged_terms, &(index_entryp->terms)))
6109  {
6110  /* there is join-edge; already examined */
6111  continue;
6112  }
6113 
6114  /* generate join index scan using 'ni_entryp' */
6115  n +=
6116  qo_generate_join_index_scan (info, join_type, outer_plan, inner, nodep, ni_entryp, &indexable_terms,
6117  afj_terms, sarged_terms, pinned_subqueries);
6118  }
6119  }
6120  }
6121  }
6122 
6123  bitset_delset (&indexable_terms);
6124 
6125  return n;
6126 }
6127 
6128 /*
6129  * qo_examine_follow () -
6130  * return:
6131  * info(in):
6132  * path_term(in):
6133  * head_info(in):
6134  * sarged_terms(in):
6135  * pinned_subqueries(in):
6136  */
6137 static int
6138 qo_examine_follow (QO_INFO * info, QO_TERM * path_term, QO_INFO * head_info, BITSET * sarged_terms,
6139  BITSET * pinned_subqueries)
6140 {
6141  PT_NODE *entity_spec;
6142  /*
6143  * Examine the feasibility of a follow plan implementation for this
6144  * edge. Don't build follow plans if the tail of the path is an rdb
6145  * proxy; these things *have* to be implemented via joins.
6146  */
6147  entity_spec = path_term->tail->entity_spec;
6148  if (entity_spec->info.spec.flat_entity_list == NULL)
6149  {
6150  return 0;
6151  }
6152 
6153  return qo_check_plan_on_info (info,
6154  qo_follow_new (info, qo_find_best_plan_on_info (head_info, QO_UNORDERED, 1.0),
6155  path_term, sarged_terms, pinned_subqueries));
6156 
6157 }
6158 
6159 /*
6160  * qo_compute_projected_segs () -
6161  * return:
6162  * planner(in):
6163  * nodes(in):
6164  * terms(in):
6165  * projected(in):
6166  */
6167 static void
6168 qo_compute_projected_segs (QO_PLANNER * planner, BITSET * nodes, BITSET * terms, BITSET * projected)
6169 {
6170  /*
6171  * Figure out which of the attributes of the nodes joined by the
6172  * terms in 'terms' need to be projected out of the join in order to
6173  * satisfy the needs of higher-level plans. An attribute will need
6174  * to preserved if it is to be produced as part of the final result
6175  * or if it is needed to compute some term that isn't included in
6176  * 'terms'.
6177  */
6178 
6179  BITSET required;
6180  int i;
6181  QO_TERM *term;
6182 
6183  BITSET_CLEAR (*projected);
6184  bitset_init (&required, planner->env);
6185  bitset_assign (&required, &(planner->final_segs));
6186 
6187  for (i = 0; i < (signed) planner->T; i++)
6188  {
6189  if (!BITSET_MEMBER (*terms, i))
6190  {
6191  term = &planner->term[i];
6192  bitset_union (&required, &(QO_TERM_SEGS (term)));
6193  }
6194  }
6195 
6196  for (i = 0; i < (signed) planner->N; ++i)
6197  {
6198  if (BITSET_MEMBER (*nodes, i))
6199  bitset_union (projected, &(QO_NODE_SEGS (&planner->node[i])));
6200  }
6201 
6202  bitset_intersect (projected, &required);
6203  bitset_delset (&required);
6204 }
6205 
6206 /*
6207  * qo_compute_projected_size () -
6208  * return:
6209  * planner(in):
6210  * segset(in):
6211  */
6212 static int
6214 {
6215  BITSET_ITERATOR si;
6216  int i;
6217  int size;
6218 
6219  /*
6220  * 8 bytes overhead per record.
6221  */
6222  size = 8;
6223 
6224  for (i = bitset_iterate (segset, &si); i != -1; i = bitset_next_member (&si))
6225  {
6226  /*
6227  * Four bytes overhead for each field.
6228  */
6229  size += qo_seg_width (QO_ENV_SEG (planner->env, i)) + 4;
6230  }
6231 
6232  return size;
6233 }
6234 
6235 /*
6236  * qo_dump_info () -
6237  * return:
6238  * info(in):
6239  * f(in):
6240  */
6241 static void
6242 qo_dump_info (QO_INFO * info, FILE * f)
6243 {
6244  /*
6245  * Dump the contents of this node for debugging scrutiny.
6246  */
6247 
6248  int i;
6249 
6250  fputs (" projected segments: ", f);
6251  bitset_print (&(info->projected_segs), f);
6252  fputs ("\n", f);
6253 
6254  fputs (" best: ", f);
6255  if (info->best_no_order.nplans > 0)
6256  {
6257  qo_dump_planvec (&info->best_no_order, f, -8);
6258  }
6259  else
6260  {
6261  fputs ("(empty)\n\n", f);
6262  }
6263 
6264  if (info->planvec)
6265  {
6266  for (i = 0; i < (signed) info->planner->EQ; ++i)
6267  {
6268  if (info->planvec[i].nplans > 0)
6269  {
6270  char buf[20];
6271 
6272  sprintf (buf, "[%d]: ", i);
6273  fprintf (f, "%8s", buf);
6274  qo_dump_planvec (&info->planvec[i], f, -8);
6275  }
6276  }
6277  }
6278 }
6279 
6280 /*
6281  * qo_info_stats () -
6282  * return:
6283  * f(in):
6284  */
6285 void
6286 qo_info_stats (FILE * f)
6287 {
6288  fprintf (f, "%d/%d info nodes allocated/deallocated\n", infos_allocated, infos_deallocated);
6289 }
6290 
6291 /*
6292  * qo_alloc_planner () -
6293  * return:
6294  * env(in):
6295  */
6296 static QO_PLANNER *
6298 {
6299  int i;
6300  QO_PLANNER *planner;
6301 
6302  planner = (QO_PLANNER *) malloc (sizeof (QO_PLANNER));
6303  if (planner == NULL)
6304  {
6306  return NULL;
6307  }
6308 
6309  env->planner = planner;
6310 
6311  planner->env = env;
6312  planner->node = env->nodes;
6313  planner->N = env->nnodes;
6314  planner->E = env->nedges;
6315  planner->M = 0; /* later, set in qo_search_planner() */
6316  if (planner->N < 32)
6317  {
6318  planner->node_mask = (unsigned long) ((unsigned int) (1 << planner->N) - 1);
6319  }
6320  else
6321  {
6322  planner->node_mask = (unsigned long) DB_UINT32_MAX;
6323  }
6324  planner->join_unit = 0;
6325  planner->term = env->terms;
6326  planner->T = env->nterms;
6327  planner->segment = env->segs;
6328  planner->S = env->nsegs;
6329  planner->eqclass = env->eqclasses;
6330  planner->EQ = env->neqclasses;
6331  planner->subqueries = env->subqueries;
6332  planner->Q = env->nsubqueries;
6333  planner->P = env->npartitions;
6334  planner->partition = env->partitions;
6335 
6336  bitset_init (&(planner->final_segs), env);
6337  bitset_assign (&(planner->final_segs), &(env->final_segs));
6338  bitset_init (&(planner->all_subqueries), env);
6339  for (i = 0; i < (signed) planner->Q; ++i)
6340  bitset_add (&(planner->all_subqueries), i);
6341 
6342  planner->node_info = NULL;
6343  planner->join_info = NULL;
6344  planner->best_info = NULL;
6345  planner->cp_info = NULL;
6346 
6347  planner->info_list = NULL;
6348 
6349  planner->cleanup_needed = true;
6350 
6351  return planner;
6352 }
6353 
6354 /*
6355  * qo_planner_free () -
6356  * return:
6357  * planner(in):
6358  */
6359 void
6361 {
6362  if (planner->cleanup_needed)
6363  qo_clean_planner (planner);
6364 
6365  qo_plan_del_ref (planner->worst_plan);
6366 
6367  if (planner->info_list)
6368  {
6369  QO_INFO *info, *next_info;
6370 
6371  for (info = planner->info_list; info; info = next_info)
6372  {
6373  next_info = info->next; /* save next link */
6374  qo_free_info (info);
6375  }
6376  }
6377 
6378  if (planner->node_info)
6379  {
6380  free_and_init (planner->node_info);
6381  }
6382 
6383  if (planner->join_info)
6384  {
6385  free_and_init (planner->join_info);
6386  }
6387 
6388  if (planner->cp_info)
6389  {
6390  free_and_init (planner->cp_info);
6391  }
6392 
6393  free_and_init (planner);
6394 }
6395 
6396 /*
6397  * qo_dump_planner_info () -
6398  * return:
6399  * planner(in):
6400  * partition(in):
6401  * f(in):
6402  */
6403 static void
6404 qo_dump_planner_info (QO_PLANNER * planner, QO_PARTITION * partition, FILE * f)
6405 {
6406  int i, M;
6407  QO_INFO *info;
6408  int t;
6409  BITSET_ITERATOR iter;
6410  const char *prefix;
6411 
6412  fputs ("\nNode info maps:\n", f);
6413  for (i = 0; i < (signed) planner->N; i++)
6414  {
6415  if (BITSET_MEMBER (QO_PARTITION_NODES (partition), i))
6416  {
6417  info = planner->node_info[i];
6418  if (info && !info->detached)
6419  {
6420  fprintf (f, "node_info[%d]:\n", i);
6421  qo_dump_info (info, f);
6422  }
6423  }
6424  }
6425 
6426  if (!bitset_is_empty (&(QO_PARTITION_EDGES (partition))))
6427  {
6428  fputs ("\nJoin info maps:\n", f);
6429  /* in current implementation, join_info[0..2] does not used */
6430  i = QO_PARTITION_M_OFFSET (partition);
6431  M = i + QO_JOIN_INFO_SIZE (partition);
6432  for (i = i + 3; i < M; i++)
6433  {
6434  info = planner->join_info[i];
6435  if (info && !info->detached)
6436  {
6437  fputs ("join_info[", f);
6438  prefix = ""; /* init */
6439  for (t = bitset_iterate (&(info->nodes), &iter); t != -1; t = bitset_next_member (&iter))
6440  {
6441  fprintf (f, "%s%d", prefix, QO_NODE_IDX (QO_ENV_NODE (planner->env, t)));
6442  prefix = ",";
6443  }
6444  fputs ("]:\n", f);
6445  qo_dump_info (info, f);
6446  }
6447  }
6448  }
6449 }
6450 
6451 /*
6452  * planner_visit_node () -
6453  * return:
6454  * planner(in):
6455  * partition(in):
6456  * hint(in):
6457  * head_node(in):
6458  * tail_node(in):
6459  * visited_nodes(in):
6460  * visited_rel_nodes(in):
6461  * visited_terms(in):
6462  * nested_path_nodes(in):
6463  * remaining_nodes(in):
6464  * remaining_terms(in):
6465  * remaining_subqueries(in):
6466  * num_path_inner(in):
6467  */
6468 static void
6469 planner_visit_node (QO_PLANNER * planner, QO_PARTITION * partition, PT_HINT_ENUM hint, QO_NODE * head_node,
6470  QO_NODE * tail_node, BITSET * visited_nodes, BITSET * visited_rel_nodes, BITSET * visited_terms,
6471  BITSET * nested_path_nodes, BITSET * remaining_nodes, BITSET * remaining_terms,
6472  BITSET * remaining_subqueries, int num_path_inner)
6473 {
6474  JOIN_TYPE join_type = NO_JOIN;
6475  QO_TERM *follow_term = NULL;
6476  int idx_join_cnt = 0; /* number of idx-join edges */
6477  QO_TERM *term;
6478  QO_NODE *node;
6479  QO_INFO *head_info = (QO_INFO *) NULL;
6480  QO_INFO *tail_info = (QO_INFO *) NULL;
6481  QO_INFO *new_info = (QO_INFO *) NULL;
6482  int i, j;
6483  bool check_afj_terms = false;
6484  bool is_dummy_term = false;
6485  BITSET_ITERATOR bi, bj;
6486  BITSET nl_join_terms; /* nested-loop join terms */
6487  BITSET sm_join_terms; /* sort merge join terms */
6488  BITSET duj_terms; /* during join terms */
6489  BITSET afj_terms; /* after join terms */
6490  BITSET sarged_terms;
6491  BITSET info_terms;
6492  BITSET pinned_subqueries;
6493 
6494  bitset_init (&nl_join_terms, planner->env);
6495  bitset_init (&sm_join_terms, planner->env);
6496  bitset_init (&duj_terms, planner->env);
6497  bitset_init (&afj_terms, planner->env);
6498  bitset_init (&sarged_terms, planner->env);
6499  bitset_init (&info_terms, planner->env);
6500  bitset_init (&pinned_subqueries, planner->env);
6501 
6502 
6503  if (head_node == NULL)
6504  {
6505  goto wrapup; /* unknown error */
6506  }
6507 
6508  if (num_path_inner)
6509  { /* check for path connected nodes */
6510  if (bitset_is_empty (nested_path_nodes))
6511  { /* not yet assign path connected nodes */
6512  int found_num, found_idx;
6513 
6514  for (i = bitset_iterate (remaining_terms, &bi); i != -1; i = bitset_next_member (&bi))
6515  {
6516  term = QO_ENV_TERM (planner->env, i);
6517  if (QO_TERM_CLASS (term) == QO_TC_PATH && QO_NODE_IDX (QO_TERM_HEAD (term)) == QO_NODE_IDX (head_node)
6518  && QO_NODE_IDX (QO_TERM_TAIL (term)) == QO_NODE_IDX (tail_node))
6519  {
6520  bitset_add (nested_path_nodes, QO_NODE_IDX (QO_TERM_TAIL (term)));
6521  /* Traverse tail link */
6522  do
6523  {
6524  found_num = 0; /* init */
6525  for (j = bitset_iterate (remaining_terms, &bj); j != -1; j = bitset_next_member (&bj))
6526  {
6527  term = QO_ENV_TERM (planner->env, j);
6528  if (QO_TERM_CLASS (term) == QO_TC_PATH
6529  && BITSET_MEMBER (*nested_path_nodes, QO_NODE_IDX (QO_TERM_HEAD (term))))
6530  {
6531  found_idx = QO_NODE_IDX (QO_TERM_TAIL (term));
6532  /* found nested path term */
6533  if (!BITSET_MEMBER (*nested_path_nodes, found_idx))
6534  {
6535  bitset_add (nested_path_nodes, found_idx);
6536  found_num++;
6537  }
6538  }
6539  }
6540  }
6541  while (found_num);
6542 
6543  /* Traverse head link reversely */
6544  do
6545  {
6546  found_num = 0; /* init */
6547  for (j = bitset_iterate (remaining_terms, &bj); j != -1; j = bitset_next_member (&bj))
6548  {
6549  term = QO_ENV_TERM (planner->env, j);
6550  if (QO_TERM_CLASS (term) == QO_TC_PATH
6551  && BITSET_MEMBER (*nested_path_nodes, QO_NODE_IDX (QO_TERM_TAIL (term))))
6552  {
6553  found_idx = QO_NODE_IDX (QO_TERM_HEAD (term));
6554  /* found nested path term */
6555  if (!BITSET_MEMBER (*nested_path_nodes, found_idx))
6556  {
6557  bitset_add (nested_path_nodes, found_idx);
6558  found_num++;
6559  }
6560  }
6561  }
6562  }
6563  while (found_num);
6564 
6565  /* exclude already joined nodes */
6566  bitset_difference (nested_path_nodes, visited_nodes);
6567  /* remove tail_node from path connected nodes */
6568  bitset_remove (nested_path_nodes, QO_NODE_IDX (tail_node));
6569 
6570  break; /* exit for-loop */
6571  }
6572  }
6573  }
6574  else
6575  { /* already assign path connected nodes */
6576  if (BITSET_MEMBER (*nested_path_nodes, QO_NODE_IDX (tail_node)))
6577  {
6578  /* remove tail_node from path connected nodes */
6579  bitset_remove (nested_path_nodes, QO_NODE_IDX (tail_node));
6580  }
6581  else
6582  {
6583  goto wrapup;
6584  }
6585  }
6586  }
6587 
6588  /*
6589  * STEP 1: set head_info, tail_info, visited_nodes, visited_rel_nodes
6590  */
6591 
6592  /* head_info points to the current prefix */
6593  if (bitset_cardinality (visited_nodes) == 1)
6594  {
6595  /* current prefix has only one node */
6596  head_info = planner->node_info[QO_NODE_IDX (head_node)];
6597  }
6598  else
6599  {
6600  /* current prefix has two or more nodes */
6601  head_info = planner->join_info[QO_INFO_INDEX (QO_PARTITION_M_OFFSET (partition), *visited_rel_nodes)];
6602  /* currently, do not permit cross join plan. for future work, NEED MORE CONSIDERAION */
6603  if (head_info == NULL)
6604  {
6605  goto wrapup;
6606  }
6607  }
6608 
6609  /* tail_info points to the node for the single class being added to the prefix */
6610  tail_info = planner->node_info[QO_NODE_IDX (tail_node)];
6611 
6612  /* connect tail_node to the prefix */
6613  bitset_add (visited_nodes, QO_NODE_IDX (tail_node));
6614  bitset_add (visited_rel_nodes, QO_NODE_REL_IDX (tail_node));
6615  bitset_remove (remaining_nodes, QO_NODE_IDX (tail_node));
6616 
6617  new_info = planner->join_info[QO_INFO_INDEX (QO_PARTITION_M_OFFSET (partition), *visited_rel_nodes)];
6618 
6619  /* check for already examined join_info */
6620  if (new_info && new_info->join_unit < planner->join_unit)
6621  {
6622  /* at here, not yet visited at this join level; use cache */
6623 
6624  if (new_info->best_no_order.nplans == 0)
6625  {
6626  goto wrapup; /* give up */
6627  }
6628 
6629  /* STEP 2: set terms for join_info */
6630  /* set info terms */
6631  bitset_assign (&info_terms, &(new_info->terms));
6632  bitset_difference (&info_terms, visited_terms);
6633 
6634  /* extract visited info terms */
6635  bitset_union (visited_terms, &info_terms);
6636  bitset_difference (remaining_terms, &info_terms);
6637 
6638  /* STEP 3: set pinned_subqueries */
6639  {
6640  QO_SUBQUERY *subq;
6641 
6642  for (i = bitset_iterate (remaining_subqueries, &bi); i != -1; i = bitset_next_member (&bi))
6643  {
6644  subq = &planner->subqueries[i];
6645  if (bitset_subset (visited_nodes, &(subq->nodes)) && bitset_subset (visited_terms, &(subq->terms)))
6646  {
6647  bitset_add (&pinned_subqueries, i);
6648  }
6649  }
6650 
6651  /* extract pinned subqueries */
6652  bitset_difference (remaining_subqueries, &pinned_subqueries);
6653  }
6654 
6655  goto go_ahead_subvisit;
6656  }
6657 
6658  /* extract terms of the tail_info subplan. this is necessary to ensure that we are aware of any terms that have been
6659  * sarged by the subplans */
6660  bitset_union (&info_terms, &(tail_info->terms));
6661 
6662  /* extract visited info terms */
6663  bitset_union (visited_terms, &info_terms);
6664  bitset_difference (remaining_terms, &info_terms);
6665 
6666  /* STEP 2: set specific terms for follow and join */
6667 
6668  /* in given partition, collect terms connected to tail_info */
6669  {
6670  int retry_cnt, edge_cnt, path_cnt;
6671  bool found_edge;
6672 
6673  retry_cnt = 0; /* init */
6674 
6675  retry_join_edge:
6676 
6677  edge_cnt = path_cnt = 0; /* init */
6678 
6679  for (i = bitset_iterate (remaining_terms, &bi); i != -1; i = bitset_next_member (&bi))
6680  {
6681 
6682  term = QO_ENV_TERM (planner->env, i);
6683 
6684  /* check term nodes */
6685  if (!bitset_subset (visited_nodes, &(QO_TERM_NODES (term))))
6686  {
6687  continue;
6688  }
6689 
6690  /* check location for outer join */
6691  if (QO_TERM_CLASS (term) == QO_TC_DURING_JOIN)
6692  {
6693  QO_ASSERT (planner->env, QO_ON_COND_TERM (term));
6694 
6695  for (j = bitset_iterate (visited_nodes, &bj); j != -1; j = bitset_next_member (&bj))
6696  {
6697  node = QO_ENV_NODE (planner->env, j);
6698  if (QO_NODE_LOCATION (node) == QO_TERM_LOCATION (term))
6699  {
6700  break;
6701  }
6702  }
6703 
6704  if (j == -1)
6705  { /* out of location */
6706  continue;
6707  }
6708  }
6709 
6710  found_edge = false; /* init */
6711 
6712  if (BITSET_MEMBER (QO_TERM_NODES (term), QO_NODE_IDX (tail_node)))
6713  {
6714  if (QO_TERM_CLASS (term) == QO_TC_PATH)
6715  {
6716  if (retry_cnt == 0)
6717  { /* is the first stage */
6718  /* need to check the direction; head -> tail */
6719  if (QO_NODE_IDX (QO_TERM_TAIL (term)) == QO_NODE_IDX (tail_node))
6720  {
6721  found_edge = true;
6722  }
6723  else
6724  {
6725  /* save path for the retry stage */
6726  path_cnt++;
6727  }
6728  }
6729  else
6730  {
6731  /* at retry stage; there is only path edge so, need not to check the direction */
6732  found_edge = true;
6733  }
6734  }
6735  else if (QO_IS_EDGE_TERM (term))
6736  {
6737  found_edge = true;
6738  }
6739  }
6740 
6741  if (found_edge == true)
6742  {
6743  /* found edge */
6744  edge_cnt++;
6745 
6746  /* set join type */
6747  if (join_type == NO_JOIN || is_dummy_term)
6748  {
6749  /* the first time except dummy term */
6750  join_type = QO_TERM_JOIN_TYPE (term);
6751  is_dummy_term = QO_TERM_CLASS (term) == QO_TC_DUMMY_JOIN ? true : false;
6752  }
6753  else if (QO_TERM_CLASS (term) == QO_TC_DUMMY_JOIN)
6754  {
6755  /* The dummy join term is excluded from the outer join check. */
6756  }
6757  else
6758  { /* already assigned */
6759  if (IS_OUTER_JOIN_TYPE (join_type))
6760  {
6761  /* outer join type must be the same */
6763  {
6764  QO_ASSERT (planner->env, join_type == QO_TERM_JOIN_TYPE (term));
6765  }
6766  }
6767  else
6768  {
6770  {
6771  /* replace to the outer join type */
6772  join_type = QO_TERM_JOIN_TYPE (term);
6773  }
6774  }
6775  }
6776 
6777  switch (QO_TERM_CLASS (term))
6778  {
6779  case QO_TC_DUMMY_JOIN: /* is always true dummy join term */
6780  /* check for idx-join */
6781  if (QO_TERM_CAN_USE_INDEX (term))
6782  {
6783  idx_join_cnt++;
6784  }
6785  break;
6786 
6787  case QO_TC_PATH:
6788  if (follow_term == NULL)
6789  { /* get the first PATH term idx */
6790  follow_term = term;
6791  /* for path-term, if join type is not outer join, we can use idx-join, nl-join */
6792  if (QO_TERM_JOIN_TYPE (follow_term) == JOIN_INNER)
6793  {
6794  /* check for idx-join */
6795  if (QO_TERM_CAN_USE_INDEX (term))
6796  {
6797  idx_join_cnt++;
6798  }
6799  bitset_add (&nl_join_terms, i);
6800  }
6801  /* check for m-join */
6803  {
6804  bitset_add (&sm_join_terms, i);
6805  }
6806  }
6807  else
6808  { /* found another PATH term */
6809  /* unknown error */
6810  QO_ASSERT (planner->env, UNEXPECTED_CASE);
6811  }
6812  break;
6813 
6814  case QO_TC_JOIN:
6815  /* check for idx-join */
6816  if (QO_TERM_CAN_USE_INDEX (term))
6817  {
6818  idx_join_cnt++;
6819  }
6820  bitset_add (&nl_join_terms, i);
6821  /* check for m-join */
6823  {
6824  bitset_add (&sm_join_terms, i);
6825  }
6826  else
6827  { /* non-eq edge */
6828  if (IS_OUTER_JOIN_TYPE (join_type) && QO_ON_COND_TERM (term))
6829  { /* ON clause */
6830  bitset_add (&duj_terms, i); /* need for m-join */
6831  }
6832  }
6833  break;
6834 
6835  case QO_TC_DEP_LINK:
6836  case QO_TC_DEP_JOIN:
6837  bitset_add (&nl_join_terms, i);
6838  break;
6839 
6840  default:
6841  QO_ASSERT (planner->env, UNEXPECTED_CASE);
6842  break;
6843  }
6844  }
6845  else
6846  {
6847  /* does not edge */
6848 
6849  if (QO_TERM_CLASS (term) == QO_TC_DURING_JOIN)
6850  {
6851  bitset_add (&duj_terms, i);
6852  }
6853  else if (QO_TERM_CLASS (term) == QO_TC_AFTER_JOIN)
6854  {
6855  check_afj_terms = true;
6856 
6857  /* If visited_nodes is the same as partition's nodes, then we have successfully generated one of the
6858  * graph permutations(i.e., we have considered every one of the nodes). only include after-join term
6859  * for this plan.
6860  */
6861  if (!bitset_is_equivalent (visited_nodes, &(QO_PARTITION_NODES (partition))))
6862  {
6863  continue;
6864  }
6865  bitset_add (&afj_terms, i);
6866  }
6867  else if (QO_TERM_CLASS (term) == QO_TC_OTHER)
6868  {
6869  if (IS_OUTER_JOIN_TYPE (join_type) && QO_ON_COND_TERM (term))
6870  { /* ON clause */
6871  bitset_add (&duj_terms, i);
6872  }
6873  }
6874  }
6875 
6876  bitset_add (&info_terms, i); /* add to info term */
6877 
6878  /* skip always true dummy join term and do not evaluate */
6879  if (QO_TERM_CLASS (term) != QO_TC_DUMMY_JOIN)
6880  {
6881  bitset_add (&sarged_terms, i); /* add to sarged term */
6882  }
6883  }
6884 
6885  /* currently, do not permit cross join plan. for future work, NEED MORE CONSIDERAION */
6886  if (edge_cnt == 0)
6887  {
6888  if (retry_cnt == 0)
6889  { /* is the first stage */
6890  if (path_cnt > 0)
6891  {
6892  /* there is only path edge and the direction is reversed */
6893  retry_cnt++;
6894  goto retry_join_edge;
6895  }
6896  }
6897  goto wrapup;
6898  }
6899  }
6900 
6901 #if 1 /* TO NOT DELETE ME - very special case for Object fetch plan */
6902  /* re-check for after join term; is depence to Object fetch plan */
6903  if (check_afj_terms && bitset_is_empty (&afj_terms))
6904  {
6905  BITSET path_nodes;
6906 
6907  bitset_init (&path_nodes, planner->env);
6908 
6909  for (i = bitset_iterate (remaining_terms, &bi); i != -1; i = bitset_next_member (&bi))
6910  {
6911  term = QO_ENV_TERM (planner->env, i);
6912 
6913  if (QO_TERM_CLASS (term) == QO_TC_PATH)
6914  {
6915  bitset_add (&path_nodes, QO_NODE_IDX (QO_TERM_TAIL (term)));
6916  }
6917  }
6918 
6919  /* there is only path joined nodes. So, should apply after join terms at here. */
6920  if (bitset_subset (&path_nodes, remaining_nodes))
6921  {
6922  for (i = bitset_iterate (remaining_terms, &bi); i != -1; i = bitset_next_member (&bi))
6923  {
6924  term = QO_ENV_TERM (planner->env, i);
6925 
6926  if (QO_TERM_CLASS (term) == QO_TC_AFTER_JOIN)
6927  {
6928  bitset_add (&afj_terms, i);
6929  bitset_add (&info_terms, i); /* add to info term */
6930  bitset_add (&sarged_terms, i); /* add to sarged term */
6931  }
6932  }
6933  }
6934 
6935  bitset_delset (&path_nodes);
6936  }
6937 #endif
6938 
6939  /* extract visited info terms */
6940  bitset_union (visited_terms, &info_terms);
6941  bitset_difference (remaining_terms, &info_terms);
6942 
6943  /* STEP 3: set pinned_subqueries */
6944 
6945  /* Find out if we can pin any of the remaining subqueries. A subquery is eligible to be pinned here if all of the
6946  * nodes on which it depends are covered here. However, it mustn't be pinned here if it is part of a term that
6947  * hasn't been pinned yet. Doing so risks improperly pushing a subquery plan down through a merge join during XASL
6948  * generation, which results in an incorrect plan (the subquery has to be evaluated during the merge, rather than
6949  * during the scan that feeds the merge).
6950  */
6951  {
6952  QO_SUBQUERY *subq;
6953 
6954  for (i = bitset_iterate (remaining_subqueries, &bi); i != -1; i = bitset_next_member (&bi))
6955  {
6956  subq = &planner->subqueries[i];
6957  if (bitset_subset (visited_nodes, &(subq->nodes)) && bitset_subset (visited_terms, &(subq->terms)))
6958  {
6959  bitset_add (&pinned_subqueries, i);
6960  }
6961  }
6962 
6963  /* extract pinned subqueries */
6964  bitset_difference (remaining_subqueries, &pinned_subqueries);
6965  }
6966 
6967  /* STEP 4: set joined info */
6968 
6969  if (new_info == NULL)
6970  {
6971 
6972  double selectivity, cardinality;
6973  BITSET eqclasses;
6974 
6975  bitset_init (&eqclasses, planner->env);
6976 
6977 
6978  selectivity = 1.0; /* init */
6979 
6980  cardinality = head_info->cardinality * tail_info->cardinality;
6981  if (IS_OUTER_JOIN_TYPE (join_type))
6982  {
6983  /* set lower bound of outer join result */
6984  if (join_type == JOIN_RIGHT)
6985  {
6986  cardinality = MAX (cardinality, tail_info->cardinality);
6987  }
6988  else
6989  {
6990  cardinality = MAX (cardinality, head_info->cardinality);
6991  }
6992  }
6993 
6994  if (cardinality != 0)
6995  { /* not empty */
6996  cardinality = MAX (1.0, cardinality);
6997  for (i = bitset_iterate (&sarged_terms, &bi); i != -1; i = bitset_next_member (&bi))
6998  {
6999  term = &planner->term[i];
7000  if (QO_IS_PATH_TERM (term) && QO_TERM_JOIN_TYPE (term) != JOIN_INNER)
7001  {
7002  /* single-fetch */
7003  cardinality = head_info->cardinality;
7004  if (cardinality != 0)
7005  { /* not empty */
7006  cardinality = MAX (1.0, cardinality);
7007  }
7008  }
7009  else
7010  {
7011  selectivity *= QO_TERM_SELECTIVITY (term);
7012  selectivity = MAX (1.0 / cardinality, selectivity);
7013  }
7014  }
7015  cardinality *= selectivity;
7016  cardinality = MAX (1.0, cardinality);
7017 
7018  if (IS_OUTER_JOIN_TYPE (join_type) && bitset_is_empty (&afj_terms))
7019  {
7020  /* set lower bound of outer join result */
7021  if (join_type == JOIN_RIGHT)
7022  {
7023  cardinality = MAX (cardinality, tail_info->cardinality);
7024  }
7025  else
7026  {
7027  cardinality = MAX (cardinality, head_info->cardinality);
7028  }
7029  }
7030  }
7031 
7032  bitset_assign (&eqclasses, &(head_info->eqclasses));
7033  bitset_union (&eqclasses, &(tail_info->eqclasses));
7034 
7035  new_info = planner->join_info[QO_INFO_INDEX (QO_PARTITION_M_OFFSET (partition), *visited_rel_nodes)] =
7036  qo_alloc_info (planner, visited_nodes, visited_terms, &eqclasses, cardinality);
7037 
7038  bitset_delset (&eqclasses);
7039  }
7040 
7041  /* STEP 5: do EXAMINE follow, join */
7042 
7043  {
7044  int kept = 0;
7045  int idx_join_plan_n = 0;
7046 
7047  /* for path-term, if join order is correct, we can use follow. */
7048  if (follow_term && (QO_NODE_IDX (QO_TERM_TAIL (follow_term)) == QO_NODE_IDX (tail_node)))
7049  {
7050  /* STEP 5-1: examine follow */
7051  kept += qo_examine_follow (new_info, follow_term, head_info, &sarged_terms, &pinned_subqueries);
7052  }
7053 
7054  if (follow_term && join_type != JOIN_INNER && QO_NODE_IDX (QO_TERM_TAIL (follow_term)) != QO_NODE_IDX (tail_node))
7055  {
7056  /* if there is a path-term whose outer join order is not correct, we can not use idx-join, nl-join, m-join */
7057  ;
7058  }
7059  else
7060  {
7061 #if 1 /* CORRELATED_INDEX */
7062  /* STEP 5-2: examine idx-join */
7063  if (idx_join_cnt)
7064  {
7065  idx_join_plan_n =
7066  qo_examine_idx_join (new_info, join_type, head_info, tail_info, &afj_terms, &sarged_terms,
7067  &pinned_subqueries);
7068  kept += idx_join_plan_n;
7069  }
7070 #endif /* CORRELATED_INDEX */
7071 
7072  /* STEP 5-3: examine nl-join */
7073  /* sm_join_terms is a mergeable term for SM join. In hash list scan, mergeable term is used as hash term. */
7074  /* The mergeable term and the hash term have the same characteristics. */
7075  /* If the characteristics for mergeable terms are changed, the logic for hash terms should be separated. */
7076  /* mergeable term : equi-term, symmetrical term, e.g. TBL1.a = TBL2.a, function(TAB1.a) = function(TAB2.a) */
7077  kept +=
7078  qo_examine_nl_join (new_info, join_type, head_info, tail_info, &nl_join_terms, &duj_terms, &afj_terms,
7079  &sarged_terms, &pinned_subqueries, idx_join_plan_n, &sm_join_terms);
7080 
7081 #if 1 /* MERGE_JOINS */
7082  /* STEP 5-4: examine merge-join */
7083  if (!bitset_is_empty (&sm_join_terms))
7084  {
7085  kept +=
7086  qo_examine_merge_join (new_info, join_type, head_info, tail_info, &sm_join_terms, &duj_terms, &afj_terms,
7087  &sarged_terms, &pinned_subqueries);
7088  }
7089 #endif /* MERGE_JOINS */
7090  }
7091 
7092  /* At this point, kept indicates the number of worthwhile plans generated by examine_joins (i.e., plans that where
7093  * cheaper than some previous equivalent plan). If that number is 0, then there is no point in continuing this
7094  * particular branch of permutations: we've already generated all of the suffixes once before, and with a better
7095  * prefix to boot. There is no possibility of finding a better plan with this prefix.
7096  */
7097  if (!kept)
7098  {
7099  goto wrapup;
7100  }
7101  }
7102 
7103  /* STEP 7: go on sub permutations */
7104 
7105 go_ahead_subvisit:
7106 
7107  /* If visited_nodes' cardinality is the same as join_unit, then we have successfully generated one of the graph
7108  * permutations (i.e., we have considered every one of the nodes). If not, we need to try to recursively generate
7109  * suffixes.
7110  */
7111  if (bitset_cardinality (visited_nodes) >= planner->join_unit)
7112  {
7113  /* If this is the info node that corresponds to the final plan (i.e., every node in the partition is covered by
7114  * the plans at this node), *AND* we have something to put in it, then record that fact in the planner. This
7115  * permits more aggressive pruning, since we can immediately discard any plan (or subplan) that is no better than
7116  * the best known plan for the entire partition.
7117  */
7118  if (!planner->best_info)
7119  {
7120  planner->best_info = new_info;
7121  }
7122  }
7123  else
7124  {
7125  for (i = bitset_iterate (remaining_nodes, &bi); i != -1; i = bitset_next_member (&bi))
7126  {
7127  node = QO_ENV_NODE (planner->env, i);
7128 
7129  /* node dependency check; */
7130  if (!bitset_subset (visited_nodes, &(QO_NODE_DEP_SET (node))))
7131  {
7132  /* node represents dependent tables, so there is no way this combination can work in isolation. Give up
7133  * so we can try some other combinations.
7134  */
7135  continue;
7136  }
7137  if (!bitset_subset (visited_nodes, &(QO_NODE_OUTER_DEP_SET (node))))
7138  {
7139  /* All previous nodes participating in outer join spec should be joined before. QO_NODE_OUTER_DEP_SET()
7140  * represents all previous nodes which are dependents on the node.
7141  */
7142  continue;
7143  }
7144 
7145  /* now, set node as next tail node, do recursion */
7146  (void) planner_visit_node (planner, partition, hint, tail_node, /* next head node */
7147  node, /* next tail node */
7148  visited_nodes, visited_rel_nodes, visited_terms, nested_path_nodes,
7149  remaining_nodes, remaining_terms, remaining_subqueries, num_path_inner);
7150 
7151  /* join hint: force join left-to-right */
7152  if (hint & PT_HINT_ORDERED)
7153  {
7154  break;
7155  }
7156  }
7157  }
7158 
7159 wrapup:
7160 
7161  /* recover to original */
7162 
7163  bitset_remove (visited_nodes, QO_NODE_IDX (tail_node));
7164  bitset_remove (visited_rel_nodes, QO_NODE_REL_IDX (tail_node));
7165  bitset_add (remaining_nodes, QO_NODE_IDX (tail_node));
7166 
7167  bitset_difference (visited_terms, &info_terms);
7168  bitset_union (remaining_terms, &info_terms);
7169 
7170  bitset_union (remaining_subqueries, &pinned_subqueries);
7171 
7172  /* free alloced */
7173  bitset_delset (&nl_join_terms);
7174  bitset_delset (&sm_join_terms);
7175  bitset_delset (&duj_terms);
7176  bitset_delset (&afj_terms);
7177  bitset_delset (&sarged_terms);
7178  bitset_delset (&info_terms);
7179  bitset_delset (&pinned_subqueries);
7180 }
7181 
7182 /*
7183  * planner_nodeset_join_cost () -
7184  * return:
7185  * planner(in):
7186  * nodeset(in):
7187  */
7188 static double
7190 {
7191  int i;
7192  BITSET_ITERATOR bi;
7193  QO_NODE *node;
7194  QO_INFO *info;
7195  QO_PLAN *plan, *subplan;
7196  double total_cost, objects, result_size, pages;
7197 
7198  total_cost = 0.0; /* init */
7199 
7200  for (i = bitset_iterate (nodeset, &bi); i != -1; i = bitset_next_member (&bi))
7201  {
7202 
7203  node = QO_ENV_NODE (planner->env, i);
7204  info = planner->node_info[QO_NODE_IDX (node)];
7205 
7206  plan = qo_find_best_plan_on_info (info, QO_UNORDERED, 1.0);
7207 
7208  if (plan == NULL)
7209  { /* something wrong */
7210  continue; /* give up */
7211  }
7212 
7213  objects = (plan->info)->cardinality;
7214  result_size = objects * (double) (plan->info)->projected_size;
7215  pages = result_size / (double) IO_PAGESIZE;
7216  pages = MAX (1.0, pages);
7217 
7218  /* apply join cost; add to the total cost */
7219  total_cost += pages;
7220 
7221  if (QO_NODE_HINT (node) & (PT_HINT_USE_IDX | PT_HINT_USE_NL))
7222  {
7223  /* join hint: force idx-join, nl-join; */
7224  }
7225  else if (QO_NODE_HINT (node) & PT_HINT_USE_MERGE)
7226  { /* force m-join */
7227  if (plan->plan_type == QO_PLANTYPE_SORT)
7228  {
7229  subplan = plan->plan_un.sort.subplan;
7230  }
7231  else
7232  {
7233  subplan = plan;
7234  }
7235 
7236  objects = (subplan->info)->cardinality;
7237  result_size = objects * (double) (subplan->info)->projected_size;
7238  pages = result_size / (double) IO_PAGESIZE;
7239  pages = MAX (1.0, pages);
7240 
7241  /* apply merge cost; add to the total cost */
7242  if (plan->plan_type == QO_PLANTYPE_SORT)
7243  {
7244  /* already apply inner cost: apply only outer cost */
7245  total_cost += pages;
7246  }
7247  else
7248  {
7249  /* do guessing: apply outer, inner cost */
7250  total_cost += pages * 2.0;
7251  }
7252  }
7253  }
7254 
7255  return total_cost;
7256 }
7257 
7258 /*
7259  * planner_permutate () -
7260  * return:
7261  * planner(in):
7262  * partition(in):
7263  * hint(in):
7264  * prev_head_node(in):
7265  * visited_nodes(in):
7266  * visited_rel_nodes(in):
7267  * visited_terms(in):
7268  * first_nodes(in):
7269  * nested_path_nodes(in):
7270  * remaining_nodes(in):
7271  * remaining_terms(in):
7272  * remaining_subqueries(in):
7273  * num_path_inner(in):
7274  * node_idxp(in):
7275  */
7276 static void
7277 planner_permutate (QO_PLANNER * planner, QO_PARTITION * partition, PT_HINT_ENUM hint, QO_NODE * prev_head_node,
7278  BITSET * visited_nodes, BITSET * visited_rel_nodes, BITSET * visited_terms, BITSET * first_nodes,
7279  BITSET * nested_path_nodes, BITSET * remaining_nodes, BITSET * remaining_terms,
7280  BITSET * remaining_subqueries, int num_path_inner, int *node_idxp)
7281 {
7282  int i, j;
7283  BITSET_ITERATOR bi, bj;
7284  QO_INFO *head_info, *best_info;
7285  QO_NODE *head_node, *tail_node;
7286  QO_PLAN *best_plan;
7287  double best_cost, prev_best_cost;
7288  BITSET rest_nodes;
7289 
7290  bitset_init (&rest_nodes, planner->env);
7291 
7292  planner->best_info = NULL; /* init */
7293 
7294  prev_best_cost = -1.0; /* init */
7295 
7296  /* Now perform the actual search. Entries in join_info will gradually be filled and refined within the calls to
7297  * examine_xxx_join(). When we finish, planner->best_info will hold information about the best ways discovered to
7298  * perform the entire join.
7299  */
7300  for (i = bitset_iterate (remaining_nodes, &bi); i != -1; i = bitset_next_member (&bi))
7301  {
7302 
7303  head_node = QO_ENV_NODE (planner->env, i);
7304 
7305  /* head node dependency check; */
7306  if (!bitset_subset (visited_nodes, &(QO_NODE_DEP_SET (head_node))))
7307  {
7308  /* head node represents dependent tables, so there is no way this combination can work in isolation. Give up
7309  * so we can try some other combinations.
7310  */
7311  continue;
7312  }
7313  if (!bitset_subset (visited_nodes, &(QO_NODE_OUTER_DEP_SET (head_node))))
7314  {
7315  /* All previous nodes participating in outer join spec should be joined before. QO_NODE_OUTER_DEP_SET()
7316  * represents all previous nodes which are dependents on the node.
7317  */
7318  continue;
7319  }
7320 
7321  /* the first join node check */
7322  if (!bitset_is_empty (first_nodes))
7323  {
7324  if (!bitset_intersects (visited_nodes, first_nodes))
7325  { /* not include */
7326  if (!BITSET_MEMBER (*first_nodes, QO_NODE_IDX (head_node)))
7327  {
7328  continue;
7329  }
7330  }
7331  }
7332 
7333  if (bitset_is_empty (visited_nodes))
7334  { /* not found outermost nodes */
7335 
7336  head_info = planner->node_info[QO_NODE_IDX (head_node)];
7337 
7338  /* init */
7339  bitset_add (visited_nodes, QO_NODE_IDX (head_node));
7340  bitset_add (visited_rel_nodes, QO_NODE_REL_IDX (head_node));
7341  bitset_remove (remaining_nodes, QO_NODE_IDX (head_node));
7342 
7343  bitset_union (visited_terms, &(head_info->terms));
7344  bitset_difference (remaining_terms, &(head_info->terms));
7345 
7346  for (j = bitset_iterate (remaining_nodes, &bj); j != -1; j = bitset_next_member (&bj))
7347  {
7348 
7349  tail_node = QO_ENV_NODE (planner->env, j);
7350 
7351  /* tail node dependency check; */
7352  if (!bitset_subset (visited_nodes, &(QO_NODE_DEP_SET (tail_node))))
7353  {
7354  continue;
7355  }
7356  if (!bitset_subset (visited_nodes, &(QO_NODE_OUTER_DEP_SET (tail_node))))
7357  {
7358  continue;
7359  }
7360 
7361  BITSET_CLEAR (*nested_path_nodes);
7362 
7363  (void) planner_visit_node (planner, partition, hint, head_node, tail_node, visited_nodes,
7364  visited_rel_nodes, visited_terms, nested_path_nodes, remaining_nodes,
7365  remaining_terms, remaining_subqueries, num_path_inner);
7366 
7367  /* join hint: force join left-to-right */
7368  if (hint & PT_HINT_ORDERED)
7369  {
7370  break;
7371  }
7372  }
7373 
7374  /* recover to original */
7375  BITSET_CLEAR (*visited_nodes);
7376  BITSET_CLEAR (*visited_rel_nodes);
7377  bitset_add (remaining_nodes, QO_NODE_IDX (head_node));
7378 
7379  bitset_difference (visited_terms, &(head_info->terms));
7380  bitset_union (remaining_terms, &(head_info->terms));
7381 
7382  }
7383  else
7384  { /* found some outermost nodes */
7385 
7386  BITSET_CLEAR (*nested_path_nodes);
7387 
7388  (void) planner_visit_node (planner, partition, hint, prev_head_node, head_node, /* next tail node */
7389  visited_nodes, visited_rel_nodes, visited_terms, nested_path_nodes,
7390  remaining_nodes, remaining_terms, remaining_subqueries, num_path_inner);
7391  }
7392 
7393  if (node_idxp)
7394  { /* is partial node visit */
7395  best_info = planner->best_info;
7396  if (best_info == NULL)
7397  { /* not found best plan */
7398  continue; /* skip and go ahead */
7399  }
7400 
7401  best_plan = qo_find_best_plan_on_info (best_info, QO_UNORDERED, 1.0);
7402 
7403  if (best_plan == NULL)
7404  { /* unknown error */
7405  break; /* give up */
7406  }
7407 
7408  /* set best plan's cost */
7409  best_cost =
7410  best_plan->fixed_cpu_cost + best_plan->fixed_io_cost + best_plan->variable_cpu_cost +
7411  best_plan->variable_io_cost;
7412 
7413  /* apply rest nodes's cost */
7414  bitset_assign (&rest_nodes, remaining_nodes);
7415  bitset_difference (&rest_nodes, &(best_info->nodes));
7416  best_cost += planner_nodeset_join_cost (planner, &rest_nodes);
7417 
7418  if (prev_best_cost == -1.0 /* the first time */
7419  || best_cost < prev_best_cost)
7420  {
7421  *node_idxp = QO_NODE_IDX (head_node);
7422  prev_best_cost = best_cost; /* found new best */
7423  }
7424 
7425  planner->best_info = NULL; /* clear */
7426  }
7427 
7428  /* join hint: force join left-to-right */
7429  if (hint & PT_HINT_ORDERED)
7430  {
7431  break;
7432  }
7433  }
7434 
7435  if (node_idxp)
7436  { /* is partial node visit */
7437  planner->best_info = NULL; /* clear */
7438  }
7439 
7440  bitset_delset (&rest_nodes);
7441 
7442  return;
7443 }
7444 
7445 /*
7446  * qo_planner_search () -
7447  * return:
7448  * env(in):
7449  */
7450 QO_PLAN *
7452 {
7453  QO_PLANNER *planner;
7454  QO_PLAN *plan;
7455 
7456  planner = NULL;
7457  plan = NULL;
7458 
7459  planner = qo_alloc_planner (env);
7460  if (planner == NULL)
7461  {
7462  return NULL;
7463  }
7464 
7465  qo_info_nodes_init (env);
7466  qo_plans_init (env);
7467  plan = qo_search_planner (planner);
7468  qo_clean_planner (planner);
7469 
7470  return plan;
7471 }
7472 
7473 /*
7474  * qo_generate_join_index_scan () -
7475  * return:
7476  * infop(in):
7477  * join_type(in):
7478  * outer_plan(in):
7479  * inner(in):
7480  * nodep(in):
7481  * ni_entryp(in):
7482  * indexable_terms(in):
7483  * afj_terms(in):
7484  * sarged_terms(in):
7485  * pinned_subqueries(in):
7486  */
7487 static int
7488 qo_generate_join_index_scan (QO_INFO * infop, JOIN_TYPE join_type, QO_PLAN * outer_plan, QO_INFO * inner,
7489  QO_NODE * nodep, QO_NODE_INDEX_ENTRY * ni_entryp, BITSET * indexable_terms,
7490  BITSET * afj_terms, BITSET * sarged_terms, BITSET * pinned_subqueries)
7491 {
7492  QO_ENV *env;
7493  QO_INDEX_ENTRY *index_entryp;
7494  BITSET_ITERATOR iter;
7495  QO_TERM *termp;
7496  QO_PLAN *inner_plan;
7497  int i, t, last_t, j, n, seg, rangelist_term_idx;
7498  bool found_rangelist;
7499  BITSET range_terms;
7500  BITSET empty_terms;
7501  BITSET remaining_terms;
7502 
7503  if (nodep != NULL && QO_NODE_IS_CLASS_HIERARCHY (nodep))
7504  {
7505  /* Class hierarchies are split into scan blocks which cannot be used for index joins. However, if the class
7506  * hierarchy is a partitioning hierarchy, we can use an index join for inner joins
7507  */
7508  if (!QO_NODE_IS_CLASS_PARTITIONED (nodep))
7509  {
7510  return 0;
7511  }
7512  else if (join_type != JOIN_INNER)
7513  {
7514  return 0;
7515  }
7516  }
7517  env = infop->env;
7518 
7519  bitset_init (&range_terms, env);
7520  bitset_init (&empty_terms, env);
7521  bitset_init (&remaining_terms, env);
7522 
7523  bitset_assign (&remaining_terms, sarged_terms);
7524 
7525  /* pointer to QO_INDEX_ENTRY structure */
7526  index_entryp = (ni_entryp)->head;
7527  if (index_entryp->force < 0)
7528  {
7529  assert (false);
7530  return 0;
7531  }
7532 
7533  found_rangelist = false;
7534  rangelist_term_idx = -1;
7535  for (i = 0; i < index_entryp->nsegs; i++)
7536  {
7537  seg = index_entryp->seg_idxs[i];
7538  if (seg == -1)
7539  {
7540  break;
7541  }
7542  n = 0;
7543  last_t = -1;
7544  for (t = bitset_iterate (indexable_terms, &iter); t != -1; t = bitset_next_member (&iter))
7545  {
7546  termp = QO_ENV_TERM (env, t);
7547 
7548  /* check for always true dummy join term */
7549  if (QO_TERM_CLASS (termp) == QO_TC_DUMMY_JOIN)
7550  {
7551  /* skip out from all terms */
7552  bitset_remove (&remaining_terms, t);
7553  continue; /* do not add to range_terms */
7554  }
7555 
7557  {
7558  /* case of multi column term ex) (a,b) in ... */
7559  if (found_rangelist == true && QO_TERM_IDX (termp) != rangelist_term_idx)
7560  {
7561  break; /* already found. give up */
7562  }
7563  for (j = 0; j < termp->multi_col_cnt; j++)
7564  {
7565  if (QO_TERM_IS_FLAGED (termp, QO_TERM_RANGELIST))
7566  {
7567  found_rangelist = true;
7568  rangelist_term_idx = QO_TERM_IDX (termp);
7569  }
7570  /* found term */
7571  if (termp->multi_col_segs[j] == seg && BITSET_MEMBER (index_entryp->seg_equal_terms[i], t))
7572  /* multi col term is only indexable when term's class is TC_SARG. so can use seg_equal_terms */
7573  {
7574  /* save last found term */
7575  last_t = t;
7576  /* found EQ term */
7577  if (QO_TERM_IS_FLAGED (termp, QO_TERM_EQUAL_OP))
7578  {
7579  bitset_add (&range_terms, t);
7580  bitset_add (&(index_entryp->multi_col_range_segs), seg);
7581  n++;
7582  }
7583  }
7584  }
7585  }
7586  else
7587  {
7588  for (j = 0; j < termp->can_use_index; j++)
7589  {
7590  /* found term */
7591  if (QO_SEG_IDX (termp->index_seg[j]) == seg)
7592  {
7593  /* save last found term */
7594  last_t = t;
7595 
7596  /* found EQ term */
7597  if (QO_TERM_IS_FLAGED (termp, QO_TERM_EQUAL_OP))
7598  {
7599  if (QO_TERM_IS_FLAGED (termp, QO_TERM_RANGELIST))
7600  {
7601  if (found_rangelist == true)
7602  {
7603  break; /* already found. give up */
7604  }
7605 
7606  /* is the first time */
7607  found_rangelist = true;
7608  rangelist_term_idx = QO_TERM_IDX (termp);
7609  }
7610 
7611  bitset_add (&range_terms, t);
7612  n++;
7613  }
7614 
7615  break;
7616  }
7617  }
7618  }
7619 
7620  /* found EQ term. exit term-iteration loop */
7621  if (n)
7622  {
7623  break;
7624  }
7625  }
7626 
7627  /* not found EQ term. exit seg-iteration loop */
7628  if (n == 0)
7629  {
7630  /* found term. add last non-EQ term */
7631  if (last_t != -1)
7632  {
7633  if (found_rangelist == true)
7634  {
7635  termp = QO_ENV_TERM (env, last_t);
7636  if (QO_TERM_IS_FLAGED (termp, QO_TERM_RANGELIST))
7637  {
7638  break; /* give up */
7639  }
7640  }
7641  bitset_add (&range_terms, last_t);
7642  }
7643  break;
7644  }
7645  }
7646 
7647  n = 0;
7648  if (!bitset_is_empty (&range_terms))
7649  {
7650  inner_plan = qo_index_scan_new (inner, nodep, ni_entryp, QO_SCANMETHOD_INDEX_SCAN, &range_terms, indexable_terms);
7651 
7652  if (inner_plan)
7653  {
7654  /* now, key-filter is assigned; exclude key-range, key-filter terms from remaining terms */
7655  bitset_difference (&remaining_terms, &range_terms);
7656  bitset_difference (&remaining_terms, &(inner_plan->plan_un.scan.kf_terms));
7657 
7658  n =
7659  qo_check_plan_on_info (infop,
7660  qo_join_new (infop, join_type, QO_JOINMETHOD_IDX_JOIN, outer_plan, inner_plan,
7661  &empty_terms, &empty_terms, afj_terms, &remaining_terms,
7662  pinned_subqueries, &empty_terms));
7663  }
7664  }
7665 
7666  bitset_delset (&remaining_terms);
7667  bitset_delset (&empty_terms);
7668  bitset_delset (&range_terms);
7669 
7670  return n;
7671 }
7672 
7673 /*
7674  * qo_is_seq_scan ()
7675  * return: true/false
7676  * plan(in):
7677  */
7678 bool
7680 {
7681  if (plan && plan->plan_type == QO_PLANTYPE_SCAN && plan->plan_un.scan.scan_method == QO_SCANMETHOD_SEQ_SCAN)
7682  {
7683  return true;
7684  }
7685 
7686  return false;
7687 }
7688 
7689 /*
7690  * qo_generate_seq_scan () - Generates sequential scan plan
7691  * return: nothing
7692  * infop(in): pointer to QO_INFO (environment info node which holds plans)
7693  * nodep(in): pointer to QO_NODE (node in the join graph)
7694  */
7695 static void
7697 {
7698  int n;
7699  QO_PLAN *planp;
7700  bool plan_created = false;
7701 
7702  planp = qo_seq_scan_new (infop, nodep);
7703 
7704  n = qo_check_plan_on_info (infop, planp);
7705  if (n)
7706  {
7707  plan_created = true;
7708  }
7709 }
7710 
7711 /*
7712  * qo_is_iscan ()
7713  * return: true/false
7714  * plan(in):
7715  */
7716 bool
7718 {
7719  if (plan && plan->plan_type == QO_PLANTYPE_SCAN
7720  && (plan->plan_un.scan.scan_method == QO_SCANMETHOD_INDEX_SCAN
7721  || plan->plan_un.scan.scan_method == QO_SCANMETHOD_INDEX_SCAN_INSPECT))
7722  {
7723  return true;
7724  }
7725 
7726  return false;
7727 }
7728 
7729 /*
7730  * qo_generate_index_scan () - With index information, generates index scan plan
7731  * return: num of index scan plans
7732  * infop(in): pointer to QO_INFO (environment info node which holds plans)
7733  * nodep(in): pointer to QO_NODE (node in the join graph)
7734  * ni_entryp(in): pointer to QO_NODE_INDEX_ENTRY (node index entry)
7735  * nsegs(in):
7736  */
7737 static int
7738 qo_generate_index_scan (QO_INFO * infop, QO_NODE * nodep, QO_NODE_INDEX_ENTRY * ni_entryp, int nsegs)
7739 {
7740  QO_INDEX_ENTRY *index_entryp;
7741  BITSET_ITERATOR iter;
7742  int i, t, n, normal_index_plan_n = 0;
7743  QO_PLAN *planp;
7744  BITSET range_terms;
7745  BITSET seg_other_terms;
7746  int start_column = 0;
7747 
7748  bitset_init (&range_terms, infop->env);
7749  bitset_init (&seg_other_terms, infop->env);
7750 
7751  /* pointer to QO_INDEX_ENTRY structure */
7752  index_entryp = (ni_entryp)->head;
7753  if (index_entryp->force < 0)
7754  {
7755  assert (false);
7756  return 0;
7757  }
7758 
7759  if (QO_ENTRY_MULTI_COL (index_entryp))
7760  {
7761  assert (nsegs >= 1);
7762  ; /* nop */
7763  }
7764  else
7765  {
7766  assert (nsegs == 1);
7767  assert (index_entryp->is_iss_candidate == 0);
7768  assert (!(index_entryp->ils_prefix_len > 0));
7769  }
7770 
7771  start_column = index_entryp->is_iss_candidate ? 1 : 0;
7772 
7773  for (i = start_column; i < nsegs - 1; i++)
7774  {
7775  t = bitset_first_member (&(index_entryp->seg_equal_terms[i]));
7776  bitset_add (&range_terms, t);
7777 
7778  /* add multi_col_range_segs */
7780  {
7781  bitset_add (&(index_entryp->multi_col_range_segs), index_entryp->seg_idxs[i]);
7782  }
7783  }
7784 
7785  /* for each terms associated with the last segment */
7786  t = bitset_iterate (&(index_entryp->seg_equal_terms[nsegs - 1]), &iter);
7787  for (; t != -1; t = bitset_next_member (&iter))
7788  {
7789  bitset_add (&range_terms, t);
7790  /* add multi_col_range_segs */
7792  {
7793  bitset_add (&(index_entryp->multi_col_range_segs), index_entryp->seg_idxs[nsegs - 1]);
7794  }
7795 
7796  /* generate index scan plan */
7797  planp = qo_index_scan_new (infop, nodep, ni_entryp, QO_SCANMETHOD_INDEX_SCAN, &range_terms, NULL);
7798 
7799  n = qo_check_plan_on_info (infop, planp);
7800  if (n)
7801  {
7802  normal_index_plan_n++; /* include index skip scan */
7803  }
7804 
7805  /* is it safe to ignore the result of qo_check_plan_on_info()? */
7806  bitset_remove (&range_terms, t);
7808  {
7809  bitset_remove (&(index_entryp->multi_col_range_segs), index_entryp->seg_idxs[nsegs - 1]);
7810  }
7811  }
7812 
7813  bitset_assign (&seg_other_terms, &(index_entryp->seg_other_terms[nsegs - 1]));
7814  for (t = bitset_iterate (&seg_other_terms, &iter); t != -1; t = bitset_next_member (&iter))
7815  {
7816  bitset_add (&range_terms, t);
7817 
7818  /* generate index scan plan */
7819  planp = qo_index_scan_new (infop, nodep, ni_entryp, QO_SCANMETHOD_INDEX_SCAN, &range_terms, NULL);
7820 
7821  n = qo_check_plan_on_info (infop, planp);
7822  if (n)
7823  {
7824  normal_index_plan_n++; /* include index skip scan */
7825  }
7826 
7827  /* is it safe to ignore the result of qo_check_plan_on_info()? */
7828  bitset_remove (&range_terms, t);
7829  }
7830 
7831  bitset_delset (&seg_other_terms);
7832  bitset_delset (&range_terms);
7833 
7834  return normal_index_plan_n;
7835 }
7836 
7837 /*
7838  * qo_generate_loose_index_scan () -
7839  * return: num of index loosed scan plans
7840  * infop(in): pointer to QO_INFO (environment info node which holds plans)
7841  * nodep(in): pointer to QO_NODE (node in the join graph)
7842  * ni_entryp(in): pointer to QO_NODE_INDEX_ENTRY (node index entry)
7843  */
7844 static int
7846 {
7847  QO_INDEX_ENTRY *index_entryp;
7848  int n = 0;
7849  QO_PLAN *planp;
7850  BITSET range_terms;
7851 
7852  bitset_init (&range_terms, infop->env);
7853 
7854  /* pointer to QO_INDEX_ENTRY structure */
7855  index_entryp = (ni_entryp)->head;
7856  if (index_entryp->force < 0)
7857  {
7858  assert (false);
7859  return 0;
7860  }
7861 
7862  assert (bitset_is_empty (&(index_entryp->seg_equal_terms[0])));
7863  assert (index_entryp->ils_prefix_len > 0);
7864  assert (QO_ENTRY_MULTI_COL (index_entryp));
7865  assert (index_entryp->cover_segments == true);
7866  assert (index_entryp->is_iss_candidate == false);
7867 
7868  assert (bitset_is_empty (&range_terms));
7869 
7870  planp = qo_index_scan_new (infop, nodep, ni_entryp, QO_SCANMETHOD_INDEX_SCAN, &range_terms, NULL);
7871 
7872  n = qo_check_plan_on_info (infop, planp);
7873 
7874  bitset_delset (&range_terms);
7875 
7876  return n;
7877 }
7878 
7879 /*
7880  * qo_generate_sort_limit_plan () - generate SORT_LIMIT plans
7881  * return : number of plans generated
7882  * env (in) :
7883  * infop (in) : info for the plan
7884  * subplan (in) : subplan over which to generate the SORT_LIMIT plan
7885  */
7886 static int
7888 {
7889  int n;
7890  QO_PLAN *plan;
7891 
7892  if (subplan->order != QO_UNORDERED)
7893  {
7894  /* Do not put a SORT_LIMIT plan over an ordered plan because we have to keep the ordered principle. At best, we
7895  * can place a SORT_LIMIT plan directly under an ordered one.
7896  */
7897  return 0;
7898  }
7899 
7900  plan = qo_sort_new (subplan, QO_UNORDERED, SORT_LIMIT);
7901  if (plan == NULL)
7902  {
7903  return 0;
7904  }
7905  n = qo_check_plan_on_info (infop, plan);
7906  return n;
7907 }
7908 
7909 /*
7910  * qo_has_is_not_null_term () - Check if whether a given node has sarg term
7911  * with not null operation
7912  * return: 1 if it is found, otherwise 0
7913  * node(in): pointer to QO_NODE
7914  */
7915 static int
7917 {
7918  QO_ENV *env;
7919  QO_TERM *term;
7920  PT_NODE *expr;
7921  int i;
7922  bool found;
7923 
7924  assert (node != NULL && node->env != NULL);
7925  if (node == NULL || node->env == NULL)
7926  {
7927  return 0;
7928  }
7929 
7930  env = QO_NODE_ENV (node);
7931  for (i = 0; i < env->nterms; i++)
7932  {
7933  term = QO_ENV_TERM (env, i);
7934 
7935  /* term should belong to the given node */
7936  if (!bitset_intersects (&(QO_TERM_SEGS (term)), &(QO_NODE_SEGS (node))))
7937  {
7938  continue;
7939  }
7940 
7941  expr = QO_TERM_PT_EXPR (term);
7942  if (!PT_IS_EXPR_NODE (expr))
7943  {
7944  continue;
7945  }
7946 
7947  found = false;
7948  while (expr)
7949  {
7950  if (expr->info.expr.op == PT_IS_NOT_NULL)
7951  {
7952  found = true;
7953  }
7954  else if (expr->info.expr.op == PT_IS_NULL)
7955  {
7956  found = false;
7957  break;
7958  }
7959 
7960  expr = expr->or_next;
7961  }
7962 
7963  /* return if one of sarg term has not null operation */
7964  if (found)
7965  {
7966  return 1;
7967  }
7968  }
7969  return 0;
7970 }
7971 
7972 /*
7973  * qo_search_planner () -
7974  * return:
7975  * planner(in):
7976  */
7977 static QO_PLAN *
7979 {
7980  int i, j, nsegs;
7981  bool broken;
7982  QO_PLAN *plan;
7983  QO_NODE *node;
7984  QO_INFO *info;
7985  BITSET_ITERATOR si;
7986  int subq_idx;
7987  QO_SUBQUERY *subq;
7988  QO_NODE_INDEX *node_index;
7989  QO_NODE_INDEX_ENTRY *ni_entry;
7990  QO_INDEX_ENTRY *index_entry;
7991  BITSET seg_terms;
7992  BITSET nodes, subqueries, remaining_subqueries;
7993  int join_info_bytes;
7994  int normal_index_plan_n, n;
7995  int start_column = 0;
7996  PT_NODE *tree = NULL;
7997  bool special_index_scan = false;
7998 
7999  bitset_init (&nodes, planner->env);
8000  bitset_init (&subqueries, planner->env);
8001  bitset_init (&remaining_subqueries, planner->env);
8002 
8003  planner->worst_plan = qo_worst_new (planner->env);
8004  if (planner->worst_plan == NULL)
8005  {
8006  plan = NULL;
8007  goto end;
8008  }
8009 
8010  planner->worst_info = qo_alloc_info (planner, &nodes, &nodes, &nodes, QO_INFINITY);
8011  (planner->worst_plan)->info = planner->worst_info;
8012  (void) qo_plan_add_ref (planner->worst_plan);
8013 
8014  /*
8015  * At this point, N (and node), S (and seg), E (and edge), and
8016  * EQ (and eqclass) have been initialized; we now need to set up the
8017  * various info vectors.
8018  *
8019  * For the time being, we assume that N is never "too large", and we
8020  * go ahead and allocate the full join_info vector of M elements.
8021  */
8022  if (planner->N > 1)
8023  {
8024  planner->M =
8025  QO_PARTITION_M_OFFSET (&planner->partition[planner->P - 1]) +
8026  QO_JOIN_INFO_SIZE (&planner->partition[planner->P - 1]);
8027 
8028  join_info_bytes = planner->M * sizeof (QO_INFO *);
8029  if (join_info_bytes > 0)
8030  {
8031  planner->join_info = (QO_INFO **) malloc (join_info_bytes);
8032  if (planner->join_info == NULL)
8033  {
8034  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) join_info_bytes);
8035  plan = NULL;
8036  goto end;
8037  }
8038  }
8039  else
8040  {
8041  plan = NULL;
8042  goto end;
8043  }
8044 
8045  memset (planner->join_info, 0, join_info_bytes);
8046  }
8047 
8048  bitset_assign (&remaining_subqueries, &(planner->all_subqueries));
8049 
8050  /*
8051  * Add appropriate scan plans for each node.
8052  */
8053  planner->node_info = NULL;
8054  if (planner->N > 0)
8055  {
8056  size_t size = sizeof (QO_INFO *) * planner->N;
8057 
8058  planner->node_info = (QO_INFO **) malloc (size);
8059  if (planner->node_info == NULL)
8060  {
8062  plan = NULL;
8063  goto end;
8064  }
8065  }
8066 
8067  for (i = 0; i < (signed) planner->N; ++i)
8068  {
8069  node = &planner->node[i];
8070  BITSET_CLEAR (nodes);
8071  bitset_add (&nodes, i);
8072  planner->node_info[i] =
8073  qo_alloc_info (planner, &nodes, &QO_NODE_SARGS (node), &QO_NODE_EQCLASSES (node),
8074  QO_NODE_SELECTIVITY (node) * (double) QO_NODE_NCARD (node));
8075 
8076  if (planner->node_info[i] == NULL)
8077  {
8078  plan = NULL;
8079  goto end;
8080  }
8081 
8082  BITSET_CLEAR (subqueries);
8083  for (subq_idx = bitset_iterate (&remaining_subqueries, &si); subq_idx != -1; subq_idx = bitset_next_member (&si))
8084  {
8085  subq = &planner->subqueries[subq_idx];
8086  if (bitset_is_empty (&subq->nodes) /* uncorrelated */
8087  || (bitset_subset (&nodes, &(subq->nodes)) /* correlated */
8088  && bitset_subset (&(QO_NODE_SARGS (node)), &(subq->terms))))
8089  {
8090  bitset_add (&subqueries, subq_idx);
8091  bitset_remove (&remaining_subqueries, subq_idx);
8092  }
8093  }
8094  bitset_assign (&(QO_NODE_SUBQUERIES (node)), &subqueries);
8095  }
8096 
8097  /*
8098  * Check all of the terms to determine which are eligible to serve as
8099  * index scans.
8100  */
8101  for (i = 0; i < (signed) planner->N; i++)
8102  {
8103  node = &planner->node[i];
8104  info = planner->node_info[QO_NODE_IDX (node)];
8105 
8106  node_index = QO_NODE_INDEXES (node);
8107 
8108  /* Set special_index_scan to true if spec if flagged as: 1. Scan for b-tree key info. 2. Scan for b-tree node
8109  * info. These are special cases which need index scan forced.
8110  */
8111  special_index_scan = PT_SPEC_SPECIAL_INDEX_SCAN (QO_NODE_ENTITY_SPEC (node));
8112  if (special_index_scan)
8113  {
8114  /* Make sure there is only one index entry */
8115  assert (node_index != NULL && QO_NI_N (node_index) == 1);
8116  ni_entry = QO_NI_ENTRY (node_index, 0);
8117  n =
8118  qo_check_plan_on_info (info,
8120  NULL));
8121  assert (n == 1);
8122  continue;
8123  }
8124 
8125  /*
8126  * It is possible that this node will not have indexes. This would
8127  * happen (for instance) if the node represented a derived table.
8128  * There is no purpose looking for index scans for a node without
8129  * indexes so skip the search in this case.
8130  */
8131  normal_index_plan_n = 0;
8132 
8133  if (node_index != NULL)
8134  {
8135  bitset_init (&seg_terms, planner->env);
8136 
8137  for (j = 0; j < QO_NI_N (node_index); j++)
8138  {
8139  ni_entry = QO_NI_ENTRY (node_index, j);
8140  index_entry = (ni_entry)->head;
8141  if (index_entry->force < 0)
8142  {
8143  continue; /* is disabled index; skip and go ahead */
8144  }
8145 
8146  /* If the index is a candidate for index skip scan, then it will not have any terms for seg_equal or
8147  * seg_other[0], so we should skip that first column from initial checks. Set the start column to 1.
8148  */
8149  start_column = index_entry->is_iss_candidate ? 1 : 0;
8150 
8151  /* seg_terms will contain all the indexable terms that refer segments from this node; stops at the first
8152  * one that has no equals or other terms
8153  */
8154  BITSET_CLEAR (seg_terms);
8155  for (nsegs = start_column; nsegs < index_entry->nsegs; nsegs++)
8156  {
8157  bitset_union (&seg_terms, &(index_entry->seg_equal_terms[nsegs]));
8158  bitset_union (&seg_terms, &(index_entry->seg_other_terms[nsegs]));
8159 
8160  if (bitset_is_empty (&(index_entry->seg_equal_terms[nsegs])))
8161  {
8162  if (!bitset_is_empty (&(index_entry->seg_other_terms[nsegs])))
8163  {
8164  nsegs++; /* include this term */
8165  }
8166  break;
8167  }
8168  }
8169 
8170  bitset_intersect (&seg_terms, &(QO_NODE_SARGS (node)));
8171 
8172  n = 0; /* init */
8173 
8174  if (!bitset_is_empty (&seg_terms))
8175  {
8176  assert (nsegs > 0);
8177 
8178  n = qo_generate_index_scan (info, node, ni_entry, nsegs);
8179  normal_index_plan_n += n;
8180  }
8181  else if (index_entry->constraints->filter_predicate && index_entry->force > 0)
8182  {
8183  assert (bitset_is_empty (&seg_terms));
8184 
8185  /* Currently, CUBRID does not allow null values in index. The filter index expression must contain at
8186  * least one term different than "is null". Otherwise, the index will be empty. Having at least one
8187  * term different than "is null" in a filter index expression, the user knows from beginning that
8188  * null values can't appear when scan filter index.
8189  */
8190 
8191  n =
8192  qo_check_plan_on_info (info,
8193  qo_index_scan_new (info, node, ni_entry, QO_SCANMETHOD_INDEX_SCAN,
8194  &seg_terms, NULL));
8195  normal_index_plan_n += n;
8196  }
8197  else if (index_entry->ils_prefix_len > 0)
8198  {
8199  assert (bitset_is_empty (&seg_terms));
8200 
8201  n = qo_generate_loose_index_scan (info, node, ni_entry);
8202  normal_index_plan_n += n;
8203  }
8204  else
8205  {
8206  assert (bitset_is_empty (&seg_terms));
8207 
8208  /* if the index didn't normally skipped the order by, we try the new plan, maybe this will be better.
8209  * DO NOT generate a order by index if there is no order by! Skip generating index from order by if
8210  * multi_range_opt is true (multi range optimized plan is already better)
8211  */
8212  tree = QO_ENV_PT_TREE (info->env);
8213  if (tree == NULL)
8214  {
8215  assert (false); /* is invalid case */
8216  continue; /* nop */
8217  }
8218 
8219  if (tree->info.query.q.select.connect_by != NULL || qo_is_prefix_index (index_entry))
8220  {
8221  continue; /* nop; go ahead */
8222  }
8223 
8224  /* if the index didn't normally skipped the group/order by, we try the new plan, maybe this will be
8225  * better. DO NOT generate if there is no group/order by!
8226  */
8227  if (!n && !index_entry->groupby_skip && tree->info.query.q.select.group_by
8228  && qo_validate_index_for_groupby (info->env, ni_entry))
8229  {
8230  n =
8231  qo_check_plan_on_info (info,
8232  qo_index_scan_new (info, node, ni_entry,
8233  QO_SCANMETHOD_INDEX_GROUPBY_SCAN, &seg_terms, NULL));
8234  }
8235 
8236  if (!n && !index_entry->orderby_skip && tree->info.query.order_by
8237  && qo_validate_index_for_orderby (info->env, ni_entry))
8238  {
8239  n =
8240  qo_check_plan_on_info (info,
8241  qo_index_scan_new (info, node, ni_entry,
8242  QO_SCANMETHOD_INDEX_ORDERBY_SCAN, &seg_terms, NULL));
8243  }
8244  }
8245  }
8246 
8247  bitset_delset (&seg_terms);
8248  }
8249 
8250  /*
8251  * Create a sequential scan plan for each node.
8252  */
8253  if (normal_index_plan_n > 0)
8254  {
8255  /* Already generate some index scans. Skip sequential scan plan for the node. */
8256  ; /* nop */
8257  }
8258  else
8259  {
8260  qo_generate_seq_scan (info, node);
8261  }
8262 
8263  if (QO_ENV_USE_SORT_LIMIT (planner->env) && QO_NODE_SORT_LIMIT_CANDIDATE (node))
8264  {
8265  /* generate a stop plan over the current best plan of the */
8266  QO_PLAN *best_plan;
8267  best_plan = qo_find_best_plan_on_info (info, QO_UNORDERED, 1.0);
8268  if (best_plan->plan_type == QO_PLANTYPE_SCAN && !qo_plan_multi_range_opt (best_plan)
8269  && !qo_is_iscan_from_orderby (best_plan) && !qo_is_iscan_from_groupby (best_plan))
8270  {
8271  qo_generate_sort_limit_plan (planner->env, info, best_plan);
8272  }
8273  }
8274  }
8275 
8276  /*
8277  * Now remaining_subqueries should contain only entries that depend
8278  * on more than one class.
8279  */
8280 
8281  if (planner->P > 1)
8282  {
8283  size_t size = sizeof (QO_INFO *) * planner->P;
8284 
8285  planner->cp_info = (QO_INFO **) malloc (size);
8286  if (planner->cp_info == NULL)
8287  {
8289  plan = NULL;
8290  goto end;
8291  }
8292 
8293  for (i = 0; i < (signed) planner->P; i++)
8294  {
8295  planner->cp_info[i] = NULL;
8296  }
8297  }
8298 
8299  broken = false;
8300  for (i = 0; i < (signed) planner->P; ++i)
8301  {
8302  /*
8303  * If any partition fails, give up. We'll have to build an
8304  * unoptimized plan elsewhere.
8305  */
8306  if (qo_search_partition (planner, &planner->partition[i], QO_UNORDERED, &remaining_subqueries) == NULL)
8307  {
8308  for (j = 0; j < i; ++j)
8309  {
8310  qo_plan_del_ref (planner->partition[j].plan);
8311  }
8312  broken = true;
8313  break;
8314  }
8315  }
8316  plan = broken ? NULL : qo_combine_partitions (planner, &remaining_subqueries);
8317 
8318  /* if we have use_desc_idx hint and order by or group by, do some checking */
8319  if (plan)
8320  {
8321  bool has_hint;
8322  PT_HINT_ENUM *hint;
8323  PT_NODE *node = NULL;
8324 
8325  if (plan->use_iscan_descending == true && qo_plan_multi_range_opt (plan) == false)
8326  {
8327  qo_set_use_desc (plan);
8328  }
8329 
8330  tree = QO_ENV_PT_TREE (planner->env);
8331  assert (tree != NULL);
8332 
8333  hint = &(tree->info.query.q.select.hint);
8334  has_hint = (*hint & PT_HINT_USE_IDX_DESC) > 0;
8335 
8336  /* check direction of the first order by column. */
8337  node = tree->info.query.order_by;
8338  if (node != NULL)
8339  {
8340  if (tree->info.query.q.select.connect_by)
8341  {
8342  ;
8343  }
8344  /* if we have order by and the hint, we allow the hint only if we have order by descending on first column.
8345  * Otherwise we clear it */
8346  else if (has_hint && node->info.sort_spec.asc_or_desc == PT_ASC)
8347  {
8348  *hint = (PT_HINT_ENUM) (*hint & ~PT_HINT_USE_IDX_DESC);
8349  }
8350  }
8351 
8352  /* check direction of the first order by column. */
8353  node = tree->info.query.q.select.group_by;
8354  if (node != NULL)
8355  {
8356  if (node->flag.with_rollup);
8357  /* if we have group by and the hint, we allow the hint only if we have group by descending on first column.
8358  * Otherwise we clear it */
8359  else if (has_hint && node->info.sort_spec.asc_or_desc == PT_ASC)
8360  {
8361  *hint = (PT_HINT_ENUM) (*hint & ~PT_HINT_USE_IDX_DESC);
8362  }
8363  }
8364  }
8365 
8366  /* some indexes may be marked with multi range optimization (as candidates) However, if the chosen top plan is not
8367  * marked as using multi range optimization it means that the optimization has been invalidated, or maybe another
8368  * plan was chosen. Make sure to un-mark indexes in this case
8369  */
8370  if (plan != NULL && !qo_plan_multi_range_opt (plan))
8371  {
8373  if (plan->info->env != NULL && plan->info->env->multi_range_opt_candidate)
8374  {
8376  }
8377  }
8378 
8379  if (plan != NULL && qo_is_interesting_order_scan (plan))
8380  {
8381  if (plan->plan_un.scan.index && plan->plan_un.scan.index->head)
8382  {
8383  if (plan->plan_un.scan.index->head->use_descending)
8384  {
8385  /* We no longer need to set the USE_DESC_IDX hint if the planner wants a descending index, because the
8386  * requirement is copied to each scan_ptr's index info at XASL generation.
8387  * plan->info->env->pt_tree->info.query.q.select.hint |= PT_HINT_USE_IDX_DESC;
8388  */
8389  }
8390  else if (plan->plan_un.scan.index->head->orderby_skip || qo_is_index_mro_scan (plan))
8391  {
8392  if (plan->info->env != NULL)
8393  {
8394  plan->info->env->pt_tree->info.query.q.select.hint =
8396  }
8397  }
8398  }
8399  }
8400 
8401 end:
8402 
8403  bitset_delset (&nodes);
8404  bitset_delset (&subqueries);
8405  bitset_delset (&remaining_subqueries);
8406 
8407  return plan;
8408 }
8409 
8410 
8411 /*
8412  * qo_clean_planner () -
8413  * return:
8414  * planner(in):
8415  */
8416 static void
8418 {
8419  /*
8420  * This cleans up everything that isn't needed for the surviving
8421  * plan. In particular, it will give back all excess QO_PLAN
8422  * structures that we have allocated during the search. All
8423  * detachable QO_INFO should already have been detached, so we don't
8424  * worry about them here.
8425  */
8426  planner->cleanup_needed = false;
8427  bitset_delset (&(planner->all_subqueries));
8428  bitset_delset (&(planner->final_segs));
8429  qo_plans_teardown (planner->env);
8430 }
8431 
8432 /* Tables considered at a time during a join
8433  * -------------------------------------------
8434  * Tables joined | Tables considered at a time
8435  * --------------+----------------------------
8436  * 4..25 | 4
8437  * 26..37 | 3
8438  * 38.. | 2
8439  * -------------------------------------------
8440  * Refer Sybase Ataptive Server
8441  */
8442 
8443 /*
8444  * qo_search_partition_join () -
8445  * return:
8446  * planner(in):
8447  * partition(in):
8448  * remaining_subqueries(in):
8449  */
8450 static QO_INFO *
8451 qo_search_partition_join (QO_PLANNER * planner, QO_PARTITION * partition, BITSET * remaining_subqueries)
8452 {
8453  QO_ENV *env;
8454  int i, nodes_cnt, node_idx;
8455  PT_NODE *tree;
8456  PT_HINT_ENUM hint;
8457  QO_TERM *term;
8458  QO_NODE *node;
8459  int num_path_inner;
8460  QO_INFO *visited_info;
8461  BITSET visited_nodes;
8462  BITSET visited_rel_nodes;
8463  BITSET visited_terms;
8464  BITSET first_nodes;
8465  BITSET nested_path_nodes;
8466  BITSET remaining_nodes;
8467  BITSET remaining_terms;
8468 
8469  env = planner->env;
8470  bitset_init (&visited_nodes, env);
8471  bitset_init (&visited_rel_nodes, env);
8472  bitset_init (&visited_terms, env);
8473  bitset_init (&first_nodes, env);
8474  bitset_init (&nested_path_nodes, env);
8475  bitset_init (&remaining_nodes, env);
8476  bitset_init (&remaining_terms, env);
8477 
8478  /* include useful nodes */
8479  bitset_assign (&remaining_nodes, &(QO_PARTITION_NODES (partition)));
8480  nodes_cnt = bitset_cardinality (&remaining_nodes);
8481 
8482  num_path_inner = 0; /* init */
8483 
8484  /* include useful terms */
8485  for (i = 0; i < (signed) planner->T; i++)
8486  {
8487  term = &planner->term[i];
8489  {
8490  continue; /* skip and go ahead */
8491  }
8492 
8493  if (bitset_subset (&remaining_nodes, &(QO_TERM_NODES (term))))
8494  {
8495  bitset_add (&remaining_terms, i);
8496  if (QO_TERM_CLASS (term) == QO_TC_PATH)
8497  {
8498  num_path_inner++; /* path-expr sargs */
8499  }
8500  }
8501 
8502  } /* for (i = ...) */
8503 
8504  /* set hint info */
8505  tree = QO_ENV_PT_TREE (env);
8506  hint = tree->info.query.q.select.hint;
8507 
8508  /* set #tables consider at a time */
8509  if (num_path_inner || (hint & PT_HINT_ORDERED))
8510  {
8511  /* inner join type path term exist; WHERE x.y.z = ? or there is a SQL hint ORDERED */
8512  planner->join_unit = nodes_cnt; /* give up */
8513  }
8514  else
8515  {
8516  planner->join_unit = (nodes_cnt <= 25) ? MIN (4, nodes_cnt) : (nodes_cnt <= 37) ? 3 : 2;
8517  }
8518 
8519  if (num_path_inner || (hint & PT_HINT_ORDERED))
8520  {
8521  ; /* skip and go ahead */
8522  }
8523  else
8524  {
8525  int r, f, t;
8526  QO_NODE *r_node, *f_node;
8527  QO_INFO *r_info, *f_info;
8528  QO_PLAN *r_plan, *f_plan;
8529  PT_NODE *entity;
8530  bool found_f_edge, found_other_edge;
8531  BITSET_ITERATOR bi, bj, bt;
8533  BITSET derived_nodes;
8534  BITSET idx_inner_nodes;
8535 
8536  bitset_init (&derived_nodes, env);
8537  bitset_init (&idx_inner_nodes, env);
8538 
8539  for (r = bitset_iterate (&remaining_nodes, &bi); r != -1; r = bitset_next_member (&bi))
8540  {
8541  r_node = QO_ENV_NODE (env, r);
8542  /* node dependency check; emptyness check */
8543  if (!bitset_is_empty (&(QO_NODE_DEP_SET (r_node))))
8544  {
8545  continue;
8546  }
8547  if (!bitset_is_empty (&(QO_NODE_OUTER_DEP_SET (r_node))))
8548  {
8549  continue;
8550  }
8551 
8552  entity = QO_NODE_ENTITY_SPEC (r_node);
8553  /* do not check node for inline view */
8554  if (entity->info.spec.derived_table)
8555  { /* inline view */
8556  bitset_add (&derived_nodes, r);
8557  continue; /* OK */
8558  }
8559 
8560  if (bitset_is_empty (&first_nodes))
8561  { /* the first time */
8562  bitset_add (&first_nodes, r);
8563  continue; /* OK */
8564  }
8565 
8566  /* current prefix has only one node */
8567  r_info = planner->node_info[QO_NODE_IDX (r_node)];
8568 
8569  r_plan = qo_find_best_plan_on_info (r_info, QO_UNORDERED, 1.0);
8570 
8571  if (qo_plan_multi_range_opt (r_plan))
8572  {
8573  /* skip removing the other edge from first plan */
8574  bitset_add (&first_nodes, r);
8575  continue;
8576  }
8577 
8578  BITSET_CLEAR (idx_inner_nodes);
8579 
8580  for (f = bitset_iterate (&first_nodes, &bj); f != -1; f = bitset_next_member (&bj))
8581  {
8582  f_node = QO_ENV_NODE (env, f);
8583  if ((QO_IS_LIMIT_NODE (env, r_node) && !QO_IS_LIMIT_NODE (env, f_node))
8584  || (!QO_IS_LIMIT_NODE (env, r_node) && QO_IS_LIMIT_NODE (env, f_node)))
8585  {
8586  /* Also keep the best plan from limit nodes, otherwise we might not get a chance to create a
8587  * SORT-LIMIT plan
8588  */
8589  continue;
8590  }
8591 
8592  /* current prefix has only one node */
8593  f_info = planner->node_info[QO_NODE_IDX (f_node)];
8594 
8595  f_plan = qo_find_best_plan_on_info (f_info, QO_UNORDERED, 1.0);
8596 
8597  if (qo_plan_multi_range_opt (f_plan))
8598  {
8599  /* allow adding the other edge to the first_nodes */
8600  continue;
8601  }
8602 
8603  cmp = qo_plan_cmp (f_plan, r_plan);
8604 
8605  if (cmp == PLAN_COMP_LT)
8606  { /* r_plan is worse */
8607  if (QO_NODE_TCARD (f_node) <= 1)
8608  { /* one page heap file */
8609  ; /* f_node is always winner */
8610  }
8611  else
8612  {
8613  /* check for info cardinality */
8614  if (r_info->cardinality < f_info->cardinality + 1.0)
8615  {
8616  continue; /* do not skip out smaller card */
8617  }
8618 
8619  if (qo_is_iscan (r_plan))
8620  {
8621  continue; /* do not skip out index scan plan */
8622  }
8623  }
8624 
8625  /* do not add r_node to the first_nodes */
8626  break;
8627  }
8628  else if (cmp == PLAN_COMP_GT)
8629  { /* found new first */
8630  if (QO_NODE_TCARD (r_node) <= 1)
8631  { /* one page heap file */
8632  ; /* r_node is always winner */
8633  }
8634  else
8635  {
8636  /* check for info cardinality */
8637  if (f_info->cardinality < r_info->cardinality + 1.0)
8638  {
8639  continue; /* do not skip out smaller card */
8640  }
8641 
8642  if (qo_is_iscan (f_plan))
8643  {
8644  continue; /* do not skip out index scan plan */
8645  }
8646  }
8647 
8648  /* check for join-connectivity of f_node to r_node */
8649  found_f_edge = found_other_edge = false; /* init */
8650  for (t = bitset_iterate (&remaining_terms, &bt); t != -1 && !found_other_edge;
8651  t = bitset_next_member (&bt))
8652  {
8653  term = QO_ENV_TERM (env, t);
8654 
8655  if (!QO_IS_EDGE_TERM (term))
8656  {
8657  continue;
8658  }
8659 
8660  if (!BITSET_MEMBER (QO_TERM_NODES (term), QO_NODE_IDX (f_node)))
8661  {
8662  continue;
8663  }
8664 
8665  /* check for f_node's edges */
8666  if (BITSET_MEMBER (QO_TERM_NODES (term), QO_NODE_IDX (r_node)))
8667  {
8668  /* edge between f_node and r_node */
8669 
8670  for (i = 0; i < QO_TERM_CAN_USE_INDEX (term) && !found_f_edge; i++)
8671  {
8672  if (QO_NODE_IDX (QO_SEG_HEAD (QO_TERM_INDEX_SEG (term, i))) == QO_NODE_IDX (f_node))
8673  {
8674  found_f_edge = true; /* indexable edge */
8675  }
8676  }
8677  }
8678  else
8679  {
8680  /* edge between f_node and other_node */
8681  found_other_edge = true;
8682  }
8683  }
8684 
8685  if (found_f_edge && !found_other_edge)
8686  {
8687  bitset_add (&idx_inner_nodes, f);
8688  }
8689  }
8690  }
8691 
8692  /* exclude idx-join's inner nodes from the first_nodes */
8693  bitset_difference (&first_nodes, &idx_inner_nodes);
8694 
8695  if (f == -1)
8696  { /* add new plan */
8697  bitset_add (&first_nodes, r);
8698  }
8699  }
8700 
8701  /* finally, add derived nodes to the first nodes */
8702  bitset_union (&first_nodes, &derived_nodes);
8703 
8704  bitset_delset (&idx_inner_nodes);
8705  bitset_delset (&derived_nodes);
8706  }
8707 
8708  /* STEP 1: do join search with visited nodes */
8709 
8710  node = NULL; /* init */
8711 
8712  while (1)
8713  {
8714  node_idx = -1; /* init */
8715  (void) planner_permutate (planner, partition, hint, node, /* previous head node */
8716  &visited_nodes, &visited_rel_nodes, &visited_terms, &first_nodes, &nested_path_nodes,
8717  &remaining_nodes, &remaining_terms, remaining_subqueries, num_path_inner,
8718  (planner->join_unit < nodes_cnt) ? &node_idx
8719  /* partial join search */
8720  : NULL /* total join search */ );
8721  if (planner->best_info)
8722  { /* OK */
8723  break; /* found best total join plan */
8724  }
8725 
8726  if (planner->join_unit >= nodes_cnt)
8727  {
8728  /* something wrong for total join search */
8729  break; /* give up */
8730  }
8731  else
8732  {
8733  if (node_idx == -1)
8734  {
8735  /* something wrong for partial join search; rollback and retry total join search */
8736  bitset_union (&remaining_nodes, &visited_nodes);
8737  bitset_union (&remaining_terms, &visited_terms);
8738 
8739  BITSET_CLEAR (first_nodes);
8740  BITSET_CLEAR (nested_path_nodes);
8741  BITSET_CLEAR (visited_nodes);
8742  BITSET_CLEAR (visited_rel_nodes);
8743  BITSET_CLEAR (visited_terms);
8744 
8745  /* set #tables consider at a time */
8746  planner->join_unit = nodes_cnt;
8747 
8748  /* STEP 2: do total join search without visited nodes */
8749 
8750  continue;
8751  }
8752  }
8753 
8754  /* at here, still do partial join search */
8755 
8756  /* extract the outermost nodes at this join level */
8757  node = QO_ENV_NODE (env, node_idx);
8758  bitset_add (&visited_nodes, node_idx);
8759  bitset_add (&visited_rel_nodes, QO_NODE_REL_IDX (node));
8760  bitset_remove (&remaining_nodes, node_idx);
8761 
8762  /* extract already used terms at this join level */
8763  if (bitset_cardinality (&visited_nodes) == 1)
8764  {
8765  /* current prefix has only one node */
8766  visited_info = planner->node_info[node_idx];
8767  }
8768  else
8769  {
8770  /* current prefix has two or more nodes */
8771  visited_info = planner->join_info[QO_INFO_INDEX (QO_PARTITION_M_OFFSET (partition), visited_rel_nodes)];
8772  }
8773 
8774  if (visited_info == NULL)
8775  { /* something wrong */
8776  break; /* give up */
8777  }
8778 
8779  bitset_assign (&visited_terms, &(visited_info->terms));
8780  bitset_difference (&remaining_terms, &(visited_info->terms));
8781 
8782  planner->join_unit++; /* increase join unit level */
8783 
8784  }
8785 
8786  bitset_delset (&visited_rel_nodes);
8787  bitset_delset (&visited_nodes);
8788  bitset_delset (&visited_terms);
8789  bitset_delset (&first_nodes);
8790  bitset_delset (&nested_path_nodes);
8791  bitset_delset (&remaining_nodes);
8792  bitset_delset (&remaining_terms);
8793 
8794  return planner->best_info;
8795 }
8796 
8797 /*
8798  * qo_search_partition () -
8799  * return:
8800  * planner(in):
8801  * partition(in):
8802  * order(in):
8803  * remaining_subqueries(in):
8804  */
8805 static QO_PLAN *
8806 qo_search_partition (QO_PLANNER * planner, QO_PARTITION * partition, QO_EQCLASS * order, BITSET * remaining_subqueries)
8807 {
8808  int i, nodes_cnt;
8809 
8810  nodes_cnt = bitset_cardinality (&(QO_PARTITION_NODES (partition)));
8811 
8812  /* nodes are multi if there is a join to be done. If not, this is just a degenerate search to determine which of the
8813  * indexes (if available) to use for the (single) class involved in the query.
8814  */
8815  if (nodes_cnt > 1)
8816  {
8817  planner->best_info = qo_search_partition_join (planner, partition, remaining_subqueries);
8818  }
8819  else
8820  {
8821  QO_NODE *node;
8822 
8823  i = bitset_first_member (&(QO_PARTITION_NODES (partition)));
8824  node = QO_ENV_NODE (planner->env, i);
8825  planner->best_info = planner->node_info[QO_NODE_IDX (node)];
8826  }
8827 
8828  if (planner->env->dump_enable)
8829  {
8830  qo_dump_planner_info (planner, partition, stdout);
8831  }
8832 
8833  if (planner->best_info)
8834  {
8835  QO_PARTITION_PLAN (partition) = qo_plan_finalize (qo_find_best_plan_on_info (planner->best_info, order, 1.0));
8836  }
8837  else
8838  {
8839  QO_PARTITION_PLAN (partition) = NULL;
8840  }
8841 
8842  /* Now clean up after ourselves. Free all of the plans that aren't part of the winner for this partition, but retain
8843  * the nodes: they contain information that the winning plan requires.
8844  */
8845 
8846  if (nodes_cnt > 1)
8847  {
8848  QO_INFO *info;
8849 
8850  for (info = planner->info_list; info; info = info->next)
8851  {
8852  if (bitset_subset (&(QO_PARTITION_NODES (partition)), &(info->nodes)))
8853  {
8854  qo_detach_info (info);
8855  }
8856  }
8857  }
8858  else
8859  { /* single class */
8860  for (i = 0; i < (signed) planner->N; i++)
8861  {
8862  if (BITSET_MEMBER (QO_PARTITION_NODES (partition), i))
8863  {
8864  qo_detach_info (planner->node_info[i]);
8865  }
8866  }
8867  }
8868 
8869  return QO_PARTITION_PLAN (partition);
8870 }
8871 
8872 /*
8873  * sort_partitions () -
8874  * return:
8875  * planner(in):
8876  */
8877 static void
8879 {
8880  int i, j;
8881  QO_PARTITION *i_part, *j_part;
8882  QO_PARTITION tmp;
8883 
8884  for (i = 1; i < (signed) planner->P; ++i)
8885  {
8886  i_part = &planner->partition[i];
8887  for (j = 0; j < i; ++j)
8888  {
8889  j_part = &planner->partition[j];
8890  /*
8891  * If the higher partition (i_part) supplies something that
8892  * the lower partition (j_part) needs, swap them.
8893  */
8894  if (bitset_intersects (&(QO_PARTITION_NODES (i_part)), &(QO_PARTITION_DEPENDENCIES (j_part))))
8895  {
8896  tmp = *i_part;
8897  *i_part = *j_part;
8898  *j_part = tmp;
8899  }
8900  }
8901  }
8902 }
8903 
8904 /*
8905  * qo_combine_partitions () -
8906  * return:
8907  * planner(in):
8908  * reamining_subqueries(in):
8909  */
8910 static QO_PLAN *
8911 qo_combine_partitions (QO_PLANNER * planner, BITSET * reamining_subqueries)
8912 {
8913  QO_PARTITION *partition = planner->partition;
8914  QO_PLAN *plan, *t_plan;
8915  BITSET nodes;
8916  BITSET terms;
8917  BITSET eqclasses;
8918  BITSET sarged_terms;
8919  BITSET subqueries;
8920  BITSET_ITERATOR bi;
8921  int i, t, s;
8922  double cardinality;
8923  QO_PLAN *next_plan;
8924 
8925  bitset_init (&nodes, planner->env);
8926  bitset_init (&terms, planner->env);
8927  bitset_init (&eqclasses, planner->env);
8928  bitset_init (&sarged_terms, planner->env);
8929  bitset_init (&subqueries, planner->env);
8930 
8931  /*
8932  * Order the partitions by dependency information. We could probably
8933  * undertake a more sophisticated search here that takes the
8934  * remaining sargable terms into account, but this code is probably
8935  * hardly ever exercised anyway, and this query is already known to
8936  * be a loser, so don't worry about it.
8937  */
8938  sort_partitions (planner);
8939 
8940  for (i = 0; i < (signed) planner->P; ++i)
8941  {
8942  (QO_PARTITION_PLAN (&planner->partition[i]))->refcount--;
8943  }
8944 
8945  /*
8946  * DON'T initialize these until after the sorting is done.
8947  */
8948  plan = QO_PARTITION_PLAN (partition);
8949  cardinality = (plan->info)->cardinality;
8950 
8951  bitset_assign (&nodes, &((plan->info)->nodes));
8952  bitset_assign (&terms, &((plan->info)->terms));
8953  bitset_assign (&eqclasses, &((plan->info)->eqclasses));
8954 
8955  for (++partition, i = 1; i < (signed) planner->P; ++partition, ++i)
8956  {
8957  next_plan = QO_PARTITION_PLAN (partition);
8958 
8959  bitset_union (&nodes, &((next_plan->info)->nodes));
8960  bitset_union (&terms, &((next_plan->info)->terms));
8961  bitset_union (&eqclasses, &((next_plan->info)->eqclasses));
8962  cardinality *= (next_plan->info)->cardinality;
8963 
8964  planner->cp_info[i] = qo_alloc_info (planner, &nodes, &terms, &eqclasses, cardinality);
8965 
8966  for (t = planner->E; t < (signed) planner->T; ++t)
8967  {
8968  if (!bitset_is_empty (&(QO_TERM_NODES (&planner->term[t]))) && !BITSET_MEMBER (terms, t)
8969  && bitset_subset (&nodes, &(QO_TERM_NODES (&planner->term[t])))
8970  && (QO_TERM_CLASS (&planner->term[t]) != QO_TC_TOTALLY_AFTER_JOIN))
8971  {
8972  bitset_add (&sarged_terms, t);
8973  }
8974  }
8975 
8976  BITSET_CLEAR (subqueries);
8977  for (s = bitset_iterate (reamining_subqueries, &bi); s != -1; s = bitset_next_member (&bi))
8978  {
8979  QO_SUBQUERY *subq = &planner->subqueries[s];
8980  if (bitset_subset (&nodes, &(subq->nodes)) && bitset_subset (&sarged_terms, &(subq->terms)))
8981  {
8982  bitset_add (&subqueries, s);
8983  bitset_remove (reamining_subqueries, s);
8984  }
8985  }
8986 
8987  plan = qo_cp_new (planner->cp_info[i], plan, next_plan, &sarged_terms, &subqueries);
8988  qo_detach_info (planner->cp_info[i]);
8989  BITSET_CLEAR (sarged_terms);
8990  }
8991 
8992  /*
8993  * Now finalize the topmost node of the tree.
8994  */
8995  if (plan != NULL)
8996  {
8997  qo_plan_finalize (plan);
8998  }
8999 
9000  for (i = planner->E; i < (signed) planner->T; ++i)
9001  {
9002  if (bitset_is_empty (&(QO_TERM_NODES (&planner->term[i]))))
9003  {
9004  bitset_add (&sarged_terms, i);
9005  }
9006  }
9007 
9008  /* skip empty sort plan */
9009  for (t_plan = plan; t_plan && t_plan->plan_type == QO_PLANTYPE_SORT; t_plan = t_plan->plan_un.sort.subplan)
9010  {
9011  if (!bitset_is_empty (&(t_plan->sarged_terms)))
9012  {
9013  break;
9014  }
9015  }
9016 
9017  if (t_plan)
9018  {
9019  bitset_union (&(t_plan->sarged_terms), &sarged_terms);
9020  }
9021  else if (plan != NULL)
9022  {
9023  /* invalid plan structure. occur error */
9024  qo_plan_discard (plan);
9025  plan = NULL;
9026  }
9027 
9028  bitset_delset (&nodes);
9029  bitset_delset (&terms);
9030  bitset_delset (&eqclasses);
9031  bitset_delset (&sarged_terms);
9032  bitset_delset (&subqueries);
9033 
9034  return plan;
9035 }
9036 
9037 /*
9038  * qo_expr_selectivity () -
9039  * return: double
9040  * env(in): optimizer environment
9041  * pt_expr(in): expression to evaluate
9042  */
9043 double
9045 {
9046  double lhs_selectivity, rhs_selectivity, selectivity, total_selectivity;
9047  PT_NODE *node;
9048 
9049  QO_ASSERT (env, pt_expr != NULL);
9050  QO_ASSERT (env, pt_expr->node_type == PT_EXPR);
9051 
9052  selectivity = 0.0;
9053  total_selectivity = 0.0;
9054 
9055  /* traverse OR list */
9056  for (node = pt_expr; node; node = node->or_next)
9057  {
9058  switch (node->info.expr.op)
9059  {
9060  case PT_OR:
9061  lhs_selectivity = qo_expr_selectivity (env, node->info.expr.arg1);
9062  rhs_selectivity = qo_expr_selectivity (env, node->info.expr.arg2);
9063  selectivity = qo_or_selectivity (env, lhs_selectivity, rhs_selectivity);
9064  break;
9065 
9066  case PT_AND:
9067  lhs_selectivity = qo_expr_selectivity (env, node->info.expr.arg1);
9068  rhs_selectivity = qo_expr_selectivity (env, node->info.expr.arg2);
9069  selectivity = qo_and_selectivity (env, lhs_selectivity, rhs_selectivity);
9070  break;
9071 
9072  case PT_NOT:
9073  lhs_selectivity = qo_expr_selectivity (env, node->info.expr.arg1);
9074  selectivity = qo_not_selectivity (env, lhs_selectivity);
9075  break;
9076 
9077  case PT_EQ:
9078  selectivity = qo_equal_selectivity (env, node);
9079  break;
9080 
9081  case PT_NE:
9082  lhs_selectivity = qo_equal_selectivity (env, node);
9083  selectivity = qo_not_selectivity (env, lhs_selectivity);
9084  break;
9085 
9086  case PT_NULLSAFE_EQ:
9087  selectivity = qo_equal_selectivity (env, node);
9088  break;
9089 
9090  case PT_GE:
9091  case PT_GT:
9092  case PT_LT:
9093  case PT_LE:
9094  selectivity = qo_comp_selectivity (env, node);
9095  break;
9096 
9097  case PT_BETWEEN:
9098  selectivity = qo_between_selectivity (env, node);
9099  break;
9100 
9101  case PT_NOT_BETWEEN:
9102  lhs_selectivity = qo_between_selectivity (env, node);
9103  selectivity = qo_not_selectivity (env, lhs_selectivity);
9104  break;
9105 
9106  case PT_RANGE:
9107  selectivity = qo_range_selectivity (env, node);
9108  break;
9109 
9110  case PT_LIKE_ESCAPE:
9111  case PT_LIKE:
9112  selectivity = (double) prm_get_float_value (PRM_ID_LIKE_TERM_SELECTIVITY);
9113  break;
9114 
9115  case PT_SETNEQ:
9116  case PT_SETEQ:
9117  case PT_SUPERSETEQ:
9118  case PT_SUPERSET:
9119  case PT_SUBSET:
9120  case PT_SUBSETEQ:
9121  case PT_IS:
9122  case PT_XOR:
9123  selectivity = DEFAULT_SELECTIVITY;
9124  break;
9125 
9126  case PT_NOT_LIKE:
9127  case PT_IS_NOT:
9128  selectivity = qo_not_selectivity (env, DEFAULT_SELECTIVITY);
9129  break;
9130 
9131  case PT_EQ_SOME:
9132  case PT_NE_SOME:
9133  case PT_GE_SOME:
9134  case PT_GT_SOME:
9135  case PT_LT_SOME:
9136  case PT_LE_SOME:
9137  case PT_EQ_ALL:
9138  case PT_NE_ALL:
9139  case PT_GE_ALL:
9140  case PT_GT_ALL:
9141  case PT_LT_ALL:
9142  case PT_LE_ALL:
9143  case PT_IS_IN:
9144  selectivity = qo_all_some_in_selectivity (env, node);
9145  break;
9146 
9147  case PT_IS_NOT_IN:
9148  lhs_selectivity = qo_all_some_in_selectivity (env, node);
9149  selectivity = qo_not_selectivity (env, lhs_selectivity);
9150  break;
9151 
9152  case PT_IS_NULL:
9153  selectivity = DEFAULT_NULL_SELECTIVITY; /* make a guess */
9154  break;
9155 
9156  case PT_IS_NOT_NULL:
9157  selectivity = qo_not_selectivity (env, DEFAULT_NULL_SELECTIVITY);
9158  break;
9159 
9160  case PT_EXISTS:
9161  selectivity = DEFAULT_EXISTS_SELECTIVITY; /* make a guess */
9162  break;
9163 
9164  default:
9165  break;
9166  }
9167 
9168  total_selectivity = qo_or_selectivity (env, total_selectivity, selectivity);
9169  total_selectivity = MAX (total_selectivity, 0.0);
9170  total_selectivity = MIN (total_selectivity, 1.0);
9171  }
9172 
9173  return total_selectivity;
9174 }
9175 
9176 /*
9177  * qo_or_selectivity () - Calculate the selectivity of an OR expression
9178  * from the selectivities of the lhs and rhs
9179  * return: double
9180  * env(in):
9181  * lhs_sel(in):
9182  * rhs_sel(in):
9183  */
9184 static double
9185 qo_or_selectivity (QO_ENV * env, double lhs_sel, double rhs_sel)
9186 {
9187  double result;
9188 
9189  QO_ASSERT (env, lhs_sel >= 0.0);
9190  QO_ASSERT (env, lhs_sel <= 1.0);
9191  QO_ASSERT (env, rhs_sel >= 0.0);
9192  QO_ASSERT (env, rhs_sel <= 1.0);
9193 
9194  result = lhs_sel + rhs_sel - (lhs_sel * rhs_sel);
9195 
9196  return result;
9197 }
9198 
9199 /*
9200  * qo_and_selectivity () -
9201  * return:
9202  * env(in):
9203  * lhs_sel(in):
9204  * rhs_sel(in):
9205  */
9206 static double
9207 qo_and_selectivity (QO_ENV * env, double lhs_sel, double rhs_sel)
9208 {
9209  double result;
9210 
9211  QO_ASSERT (env, lhs_sel >= 0.0);
9212  QO_ASSERT (env, lhs_sel <= 1.0);
9213  QO_ASSERT (env, rhs_sel >= 0.0);
9214  QO_ASSERT (env, rhs_sel <= 1.0);
9215 
9216  result = lhs_sel * rhs_sel;
9217 
9218  return result;
9219 }
9220 
9221 /*
9222  * qo_not_selectivity () - Calculate the selectivity of a not expresssion
9223  * return: double
9224  * env(in):
9225  * sel(in):
9226  */
9227 static double
9228 qo_not_selectivity (QO_ENV * env, double sel)
9229 {
9230  QO_ASSERT (env, sel >= 0.0);
9231  QO_ASSERT (env, sel <= 1.0);
9232 
9233  return 1.0 - sel;
9234 }
9235 
9236 /*
9237  * qo_equal_selectivity () - Compute the selectivity of an equality predicate
9238  * return: double
9239  * env(in):
9240  * pt_expr(in):
9241  *
9242  * Note: This uses the System R algorithm
9243  */
9244 static double
9246 {
9247  PT_NODE *lhs, *rhs, *multi_attr;
9248  PRED_CLASS pc_lhs, pc_rhs;
9249  int lhs_icard, rhs_icard, icard;
9250  double selectivity;
9251 
9252  lhs = pt_expr->info.expr.arg1;
9253  rhs = pt_expr->info.expr.arg2;
9254 
9255  /* the class of lhs and rhs */
9256  pc_lhs = qo_classify (lhs);
9257  pc_rhs = qo_classify (rhs);
9258 
9259  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9260 
9261  switch (pc_lhs)
9262  {
9263  case PC_ATTR:
9264 
9265  switch (pc_rhs)
9266  {
9267  case PC_ATTR:
9268  /* attr = attr */
9269 
9270  /* check for indexes on either of the attributes */
9271  lhs_icard = qo_index_cardinality (env, lhs);
9272  rhs_icard = qo_index_cardinality (env, rhs);
9273 
9274  icard = MAX (lhs_icard, rhs_icard);
9275  if (icard != 0)
9276  {
9277  selectivity = (1.0 / icard);
9278  }
9279  else
9280  {
9281  selectivity = DEFAULT_EQUIJOIN_SELECTIVITY;
9282  }
9283 
9284  break;
9285 
9286  case PC_CONST:
9287  case PC_HOST_VAR:
9288  case PC_SUBQUERY:
9289  case PC_SET:
9290  case PC_OTHER:
9291  /* attr = const */
9292 
9293  /* check for index on the attribute. NOTE: For an equality predicate, we treat subqueries as constants. */
9294  lhs_icard = qo_index_cardinality (env, lhs);
9295  if (lhs_icard != 0)
9296  {
9297  selectivity = (1.0 / lhs_icard);
9298  }
9299  else
9300  {
9301  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9302  }
9303 
9304  break;
9305 
9306  case PC_MULTI_ATTR:
9307  /* attr = (attr,attr) syntactic impossible case */
9308  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9309  break;
9310  }
9311 
9312  break;
9313 
9314  case PC_CONST:
9315  case PC_HOST_VAR:
9316  case PC_SUBQUERY:
9317  case PC_SET:
9318  case PC_OTHER:
9319 
9320  switch (pc_rhs)
9321  {
9322  case PC_ATTR:
9323  /* const = attr */
9324 
9325  /* check for index on the attribute. NOTE: For an equality predicate, we treat subqueries as constants. */
9326  rhs_icard = qo_index_cardinality (env, rhs);
9327  if (rhs_icard != 0)
9328  {
9329  selectivity = (1.0 / rhs_icard);
9330  }
9331  else
9332  {
9333  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9334  }
9335 
9336  break;
9337 
9338  case PC_CONST:
9339  case PC_HOST_VAR:
9340  case PC_SUBQUERY:
9341  case PC_SET:
9342  case PC_OTHER:
9343  /* const = const */
9344 
9345  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9346  break;
9347 
9348  case PC_MULTI_ATTR:
9349  /* const = (attr,attr) */
9350  multi_attr = rhs->info.function.arg_list;
9351  rhs_icard = 0;
9352  for ( /* none */ ; multi_attr; multi_attr = multi_attr->next)
9353  {
9354  /* get index cardinality */
9355  icard = qo_index_cardinality (env, multi_attr);
9356  if (icard <= 0)
9357  {
9358  /* the only interesting case is PT_BETWEEN_EQ_NA */
9359  icard = 1 / DEFAULT_EQUAL_SELECTIVITY;
9360  }
9361  if (rhs_icard == 0)
9362  {
9363  /* first time */
9364  rhs_icard = icard;
9365  }
9366  else
9367  {
9368  rhs_icard *= icard;
9369  }
9370  }
9371  if (rhs_icard != 0)
9372  {
9373  selectivity = (1.0 / rhs_icard);
9374  }
9375  else
9376  {
9377  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9378  }
9379  break;
9380  }
9381  break;
9382 
9383  case PC_MULTI_ATTR:
9384  switch (pc_rhs)
9385  {
9386  case PC_ATTR:
9387  /* (attr,attr) = attr syntactic impossible case */
9388  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9389  break;
9390 
9391  case PC_CONST:
9392  case PC_HOST_VAR:
9393  case PC_SUBQUERY:
9394  case PC_SET:
9395  case PC_OTHER:
9396  /* (attr,attr) = const */
9397 
9398  multi_attr = lhs->info.function.arg_list;
9399  lhs_icard = 0;
9400  for ( /* none */ ; multi_attr; multi_attr = multi_attr->next)
9401  {
9402  /* get index cardinality */
9403  icard = qo_index_cardinality (env, multi_attr);
9404  if (icard <= 0)
9405  {
9406  /* the only interesting case is PT_BETWEEN_EQ_NA */
9407  icard = 1 / DEFAULT_EQUAL_SELECTIVITY;
9408  }
9409  if (lhs_icard == 0)
9410  {
9411  /* first time */
9412  lhs_icard = icard;
9413  }
9414  else
9415  {
9416  lhs_icard *= icard;
9417  }
9418  }
9419  if (lhs_icard != 0)
9420  {
9421  selectivity = (1.0 / lhs_icard);
9422  }
9423  else
9424  {
9425  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9426  }
9427  break;
9428 
9429  case PC_MULTI_ATTR:
9430  /* (attr,attr) = (attr,attr) */
9431  multi_attr = lhs->info.function.arg_list;
9432  lhs_icard = 0;
9433  for ( /* none */ ; multi_attr; multi_attr = multi_attr->next)
9434  {
9435  /* get index cardinality */
9436  icard = qo_index_cardinality (env, multi_attr);
9437  if (icard <= 0)
9438  {
9439  /* the only interesting case is PT_BETWEEN_EQ_NA */
9440  icard = 1 / DEFAULT_EQUAL_SELECTIVITY;
9441  }
9442  if (lhs_icard == 0)
9443  {
9444  /* first time */
9445  lhs_icard = icard;
9446  }
9447  else
9448  {
9449  lhs_icard *= icard;
9450  }
9451  }
9452 
9453  multi_attr = rhs->info.function.arg_list;
9454  rhs_icard = 0;
9455  for ( /* none */ ; multi_attr; multi_attr = multi_attr->next)
9456  {
9457  /* get index cardinality */
9458  icard = qo_index_cardinality (env, multi_attr);
9459  if (icard <= 0)
9460  {
9461  /* the only interesting case is PT_BETWEEN_EQ_NA */
9462  icard = 1 / DEFAULT_EQUAL_SELECTIVITY;
9463  }
9464  if (rhs_icard == 0)
9465  {
9466  /* first time */
9467  rhs_icard = icard;
9468  }
9469  else
9470  {
9471  rhs_icard *= icard;
9472  }
9473  }
9474 
9475  icard = MAX (lhs_icard, rhs_icard);
9476  if (icard != 0)
9477  {
9478  selectivity = (1.0 / icard);
9479  }
9480  else
9481  {
9482  selectivity = DEFAULT_EQUIJOIN_SELECTIVITY;
9483  }
9484  break;
9485  }
9486 
9487  break;
9488  break;
9489  }
9490 
9491  return selectivity;
9492 }
9493 
9494 /*
9495  * qo_comp_selectivity () - Compute the selectivity of a comparison predicate.
9496  * return: double
9497  * env(in): Pointer to an environment structure
9498  * pt_expr(in): comparison expression
9499  *
9500  * Note: This uses the System R algorithm
9501  */
9502 static double
9504 {
9505  return DEFAULT_COMP_SELECTIVITY;
9506 }
9507 
9508 /*
9509  * qo_between_selectivity () - Compute the selectivity of a between predicate
9510  * return: double
9511  * env(in): Pointer to an environment structure
9512  * pt_expr(in): between expression
9513  *
9514  * Note: This uses the System R algorithm
9515  */
9516 static double
9518 {
9519  PT_NODE *and_node;
9520 
9521  and_node = pt_expr->info.expr.arg2;
9522 
9523  QO_ASSERT (env, and_node->node_type == PT_EXPR);
9524  QO_ASSERT (env, pt_is_between_range_op (and_node->info.expr.op));
9525 
9527 }
9528 
9529 /*
9530  * qo_range_selectivity () -
9531  * return:
9532  * env(in):
9533  * pt_expr(in):
9534  */
9535 static double
9537 {
9538  PT_NODE *lhs, *arg1, *arg2;
9539  PRED_CLASS pc1, pc2;
9540  double total_selectivity, selectivity;
9541  int lhs_icard = 0, rhs_icard = 0, icard = 0;
9542  PT_NODE *range_node;
9543  PT_OP_TYPE op_type;
9544 
9545  lhs = pt_expr->info.expr.arg1;
9546 
9547  pc2 = qo_classify (lhs);
9548 
9549  /* the only interesting case is 'attr RANGE {=1,=2}' or '(attr,attr) RANGE {={..},..}' */
9550  if (pc2 == PC_MULTI_ATTR)
9551  {
9552  lhs = lhs->info.function.arg_list;
9553  lhs_icard = 0;
9554  for ( /* none */ ; lhs; lhs = lhs->next)
9555  {
9556  /* get index cardinality */
9557  icard = qo_index_cardinality (env, lhs);
9558  if (icard <= 0)
9559  {
9560  /* the only interesting case is PT_BETWEEN_EQ_NA */
9561  icard = 1 / DEFAULT_EQUAL_SELECTIVITY;
9562  }
9563  if (lhs_icard == 0)
9564  {
9565  /* first time */
9566  lhs_icard = icard;
9567  }
9568  else
9569  {
9570  lhs_icard *= icard;
9571  }
9572  }
9573  }
9574  else if (pc2 == PC_ATTR)
9575  {
9576  /* get index cardinality */
9577  lhs_icard = qo_index_cardinality (env, lhs);
9578  }
9579  else
9580  {
9582  }
9583 #if 1 /* unused anymore - DO NOT DELETE ME */
9585 #endif
9586 
9587  total_selectivity = 0.0;
9588 
9589  for (range_node = pt_expr->info.expr.arg2; range_node; range_node = range_node->or_next)
9590  {
9591  QO_ASSERT (env, range_node->node_type == PT_EXPR);
9592 
9593  op_type = range_node->info.expr.op;
9594  QO_ASSERT (env, pt_is_between_range_op (op_type));
9595 
9596  arg1 = range_node->info.expr.arg1;
9597  arg2 = range_node->info.expr.arg2;
9598 
9599  pc1 = qo_classify (arg1);
9600 
9601  if (op_type == PT_BETWEEN_GE_LE || op_type == PT_BETWEEN_GE_LT || op_type == PT_BETWEEN_GT_LE
9602  || op_type == PT_BETWEEN_GT_LT)
9603  {
9604  selectivity = DEFAULT_BETWEEN_SELECTIVITY;
9605  }
9606  else if (op_type == PT_BETWEEN_EQ_NA)
9607  {
9608  /* PT_BETWEEN_EQ_NA have only one argument */
9609 
9610  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9611 
9612  if (pc1 == PC_ATTR)
9613  {
9614  /* attr1 range (attr2 = ) */
9615  rhs_icard = qo_index_cardinality (env, arg1);
9616 
9617  icard = MAX (lhs_icard, rhs_icard);
9618  if (icard != 0)
9619  {
9620  selectivity = (1.0 / icard);
9621  }
9622  else
9623  {
9624  selectivity = DEFAULT_EQUIJOIN_SELECTIVITY;
9625  }
9626  }
9627  else
9628  {
9629  /* attr1 range (const = ) */
9630  if (lhs_icard != 0)
9631  {
9632  selectivity = (1.0 / lhs_icard);
9633  }
9634  else
9635  {
9636  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9637  }
9638  }
9639  }
9640  else
9641  {
9642  /* PT_BETWEEN_INF_LE, PT_BETWEEN_INF_LT, PT_BETWEEN_GE_INF, and PT_BETWEEN_GT_INF have only one argument */
9643 
9644  selectivity = DEFAULT_COMP_SELECTIVITY;
9645  }
9646 
9647  selectivity = MAX (selectivity, 0.0);
9648  selectivity = MIN (selectivity, 1.0);
9649 
9650  total_selectivity = qo_or_selectivity (env, total_selectivity, selectivity);
9651  total_selectivity = MAX (total_selectivity, 0.0);
9652  total_selectivity = MIN (total_selectivity, 1.0);
9653  }
9654 
9655  return total_selectivity;
9656 }
9657 
9658 /*
9659  * qo_all_some_in_selectivity () - Compute the selectivity of an in predicate
9660  * return: double
9661  * env(in): Pointer to an environment structure
9662  * pt_expr(in): in expression
9663  *
9664  * Note: This uses the System R algorithm
9665  */
9666 static double
9668 {
9669  PRED_CLASS pc_lhs, pc_rhs;
9670  double list_card = 0, icard;
9671  PT_NODE *lhs;
9672  double equal_selectivity, in_selectivity, selectivity;
9673 
9674  /* determine the class of each side of the range */
9675  pc_lhs = qo_classify (pt_expr->info.expr.arg1);
9676  pc_rhs = qo_classify (pt_expr->info.expr.arg2);
9677 
9678  /* The only interesting cases are: attr IN set or (attr,attr) IN set or attr IN subquery */
9679  if ((pc_lhs == PC_MULTI_ATTR || pc_lhs == PC_ATTR) && (pc_rhs == PC_SET || pc_rhs == PC_SUBQUERY))
9680  {
9681  if (pc_lhs == PC_MULTI_ATTR)
9682  {
9683  lhs = pt_expr->info.expr.arg1->info.function.arg_list;
9684  equal_selectivity = 1;
9685  for ( /* none */ ; lhs; lhs = lhs->next)
9686  {
9687  /* get index cardinality */
9688  icard = qo_index_cardinality (env, lhs);
9689  if (icard != 0)
9690  {
9691  selectivity = (1.0 / icard);
9692  }
9693  else
9694  {
9695  selectivity = DEFAULT_EQUAL_SELECTIVITY;
9696  }
9697  equal_selectivity *= selectivity;
9698  }
9699  }
9700  else if (pc_lhs == PC_ATTR)
9701  {
9702  /* check for index on the attribute. */
9703  icard = qo_index_cardinality (env, pt_expr->info.expr.arg1);
9704 
9705  if (icard != 0)
9706  {
9707  equal_selectivity = (1.0 / icard);
9708  }
9709  else
9710  {
9711  equal_selectivity = DEFAULT_EQUAL_SELECTIVITY;
9712  }
9713  }
9714  /* determine cardinality of set or subquery */
9715  if (pc_rhs == PC_SET)
9716  {
9717  if (pt_is_function (pt_expr->info.expr.arg2))
9718  {
9719  list_card = pt_length_of_list (pt_expr->info.expr.arg2->info.function.arg_list);
9720  }
9721  else
9722  {
9723  list_card = pt_length_of_list (pt_expr->info.expr.arg2->info.value.data_value.set);
9724  }
9725  }
9726  else if (pc_rhs == PC_SUBQUERY)
9727  {
9728  if (pt_expr->info.expr.arg2->info.query.xasl)
9729  {
9730  list_card = ((XASL_NODE *) pt_expr->info.expr.arg2->info.query.xasl)->cardinality;
9731  }
9732  else
9733  {
9734  /* legacy default list_card is 1000. Maybe it won't come in here */
9735  list_card = 1000;
9736  }
9737  }
9738 
9739  /* compute selectivity--cap at 0.5 */
9740  in_selectivity = list_card * equal_selectivity;
9741  return in_selectivity > 0.5 ? 0.5 : in_selectivity;
9742  }
9743 
9744  return DEFAULT_IN_SELECTIVITY;
9745 }
9746 
9747 /*
9748  * qo_classify () - Determine which predicate class the node belongs in
9749  * return: PRED_CLASS
9750  * attr(in): pt node to classify
9751  */
9752 static PRED_CLASS
9754 {
9755  switch (attr->node_type)
9756  {
9757  case PT_NAME:
9758  case PT_DOT_:
9759  return PC_ATTR;
9760 
9761  case PT_VALUE:
9762  if (PT_IS_SET_TYPE (attr))
9763  {
9764  return PC_SET;
9765  }
9766  else if (attr->type_enum == PT_TYPE_NULL)
9767  {
9768  return PC_OTHER;
9769  }
9770  else
9771  {
9772  return PC_CONST;
9773  }
9774 
9775  case PT_HOST_VAR:
9776  return PC_HOST_VAR;
9777 
9778  case PT_SELECT:
9779  case PT_UNION:
9780  case PT_INTERSECTION:
9781  case PT_DIFFERENCE:
9782  return PC_SUBQUERY;
9783 
9784  case PT_FUNCTION:
9785  /* (attr,attr) or (?,?) */
9786  if (PT_IS_SET_TYPE (attr))
9787  {
9788  PT_NODE *func_arg;
9789  func_arg = attr->info.function.arg_list;
9790  for ( /* none */ ; func_arg; func_arg = func_arg->next)
9791  {
9792  if (func_arg->node_type == PT_NAME)
9793  {
9794  /* none */
9795  }
9796  else if (func_arg->node_type == PT_HOST_VAR)
9797  {
9798  return PC_SET;
9799  }
9800  else
9801  {
9802  return PC_OTHER;
9803  }
9804  }
9805  return PC_MULTI_ATTR;
9806  }
9807  else
9808  {
9809  return PC_OTHER;
9810  }
9811 
9812  default:
9813  return PC_OTHER;
9814  }
9815 }
9816 
9817 /*
9818  * qo_index_cardinality () - Determine if the attribute has an index
9819  * return: cardinality of the index if the index exists, otherwise return 0
9820  * env(in): optimizer environment
9821  * attr(in): pt node for the attribute for which we want the index cardinality
9822  */
9823 static int
9825 {
9826  PT_NODE *dummy;
9827  QO_NODE *nodep;
9828  QO_SEGMENT *segp;
9829  QO_ATTR_INFO *info;
9830 
9831  if (attr->node_type == PT_DOT_)
9832  {
9833  attr = attr->info.dot.arg2;
9834  }
9835 
9836  QO_ASSERT (env, attr->node_type == PT_NAME);
9837 
9838  nodep = lookup_node (attr, env, &dummy);
9839  if (nodep == NULL)
9840  {
9841  return 0;
9842  }
9843 
9844  segp = lookup_seg (nodep, attr, env);
9845  if (segp == NULL)
9846  {
9847  return 0;
9848  }
9849 
9850  if (attr->info.name.meta_class == PT_RESERVED)
9851  {
9852  return 0;
9853  }
9854 
9855  info = QO_SEG_INFO (segp);
9856  if (info == NULL)
9857  {
9858  return 0;
9859  }
9860 
9861  if (info->cum_stats.is_indexed != true)
9862  {
9863  return 0;
9864  }
9865 
9866  QO_ASSERT (env, info->cum_stats.pkeys_size > 0);
9868  QO_ASSERT (env, info->cum_stats.pkeys != NULL);
9869 
9870  /* return number of the first partial-key of the index on the attribute shown in the expression */
9871  return info->cum_stats.pkeys[0];
9872 }
9873 
9874 /*
9875  * qo_is_all_unique_index_columns_are_equi_terms () -
9876  * check if the current plan uses and
9877  * index scan with all_unique_index_columns_are_equi_terms
9878  *
9879  * return : true/false
9880  * plan (in) : plan to verify
9881  */
9882 bool
9884 {
9885  if (qo_is_iscan (plan) && plan->plan_un.scan.index && plan->plan_un.scan.index->head
9886  && (plan->plan_un.scan.index->head->all_unique_index_columns_are_equi_terms))
9887  {
9888  return true;
9889  }
9890  return false;
9891 }
9892 
9893 /*
9894  * qo_is_iscan_from_orderby ()
9895  * return: true/false
9896  * plan(in):
9897  */
9898 bool
9900 {
9901  if (plan && plan->plan_type == QO_PLANTYPE_SCAN && plan->plan_un.scan.scan_method == QO_SCANMETHOD_INDEX_ORDERBY_SCAN)
9902  {
9903  return true;
9904  }
9905 
9906  return false;
9907 }
9908 
9909 /*
9910  * qo_validate_index_term_notnull ()
9911  * return: true/false
9912  */
9913 static bool
9915 {
9916  bool term_notnull = false; /* init */
9917  PT_NODE *node;
9918  const char *node_name;
9919  QO_CLASS_INFO_ENTRY *index_class;
9920  int t;
9921  QO_TERM *termp;
9922  int iseg;
9923  QO_SEGMENT *segp;
9924 
9925  assert (env != NULL);
9926  assert (index_entryp != NULL);
9927  assert (index_entryp->class_ != NULL);
9928 
9929  index_class = index_entryp->class_;
9930 
9931  /* do a check on the first column - it should be present in the where clause check if exists a simple expression
9932  * with PT_IS_NOT_NULL on the first key this should not contain OR operator and the PT_IS_NOT_NULL should contain the
9933  * column directly as parameter (PT_NAME)
9934  */
9935  for (t = 0; t < env->nterms && !term_notnull; t++)
9936  {
9937  /* get the pointer to QO_TERM structure */
9938  termp = QO_ENV_TERM (env, t);
9939  assert (termp != NULL);
9940  if (QO_ON_COND_TERM (termp))
9941  {
9942  continue;
9943  }
9944 
9945  node = QO_TERM_PT_EXPR (termp);
9946  if (node == NULL)
9947  {
9948  continue;
9949  }
9950 
9951  if (node && node->or_next)
9952  {
9953  continue;
9954  }
9955 
9956  if (node->node_type == PT_EXPR && node->info.expr.op == PT_IS_NOT_NULL
9957  && node->info.expr.arg1->node_type == PT_NAME)
9958  {
9959  iseg = index_entryp->seg_idxs[0];
9960  if (iseg != -1 && BITSET_MEMBER (QO_TERM_SEGS (termp), iseg))
9961  {
9962  /* check it's the same column as the first in the index */
9963  node_name = pt_get_name (node->info.expr.arg1);
9964  segp = QO_ENV_SEG (env, iseg);
9965  assert (segp != NULL);
9966  if (!intl_identifier_casecmp (node_name, QO_SEG_NAME (segp)))
9967  {
9968  /* we have found a term with no OR and with IS_NOT_NULL on our key. The plan is ready for group by
9969  * skip!
9970  */
9971  term_notnull = true;
9972  break;
9973  }
9974  }
9975  }
9976  }
9977 
9978  return term_notnull;
9979 }
9980 
9981 /*
9982  * qo_validate_index_attr_notnull ()
9983  * return: true/false
9984  */
9985 static bool
9987 {
9988  bool attr_notnull = false; /* init */
9989  QO_NODE *node;
9990  PT_NODE *dummy;
9991  int i;
9992  QO_CLASS_INFO_ENTRY *index_class;
9993  QO_SEGMENT *segp = NULL;
9994  SM_ATTRIBUTE *attr;
9995  void *env_seg[2];
9996 
9997  /* key_term_status is -1 if no term with key, 0 if isnull or is not null terms with key and 1 if other term with key */
9998  int old_bail_out, key_term_status;
9999 
10000  assert (env != NULL);
10001  assert (index_entryp != NULL);
10002  assert (index_entryp->class_ != NULL);
10003  assert (index_entryp->class_->smclass != NULL);
10004  assert (col != NULL);
10005 
10006  index_class = index_entryp->class_;
10007 
10008  if (col->node_type != PT_NAME)
10009  {
10010  return false; /* give up */
10011  }
10012 
10013  node = lookup_node (col, env, &dummy);
10014  if (node == NULL)
10015  {
10016  return false;
10017  }
10018 
10019  segp = lookup_seg (node, col, env);
10020  if (segp == NULL)
10021  { /* is invalid case */
10022  assert (false);
10023  return false;
10024  }
10025 
10026  for (i = 0; i < index_entryp->col_num; i++)
10027  {
10028  if (index_entryp->seg_idxs[i] == QO_SEG_IDX (segp))
10029  {
10030  break; /* found */
10031  }
10032  }
10033  if (i >= index_entryp->col_num)
10034  {
10035  /* col is not included in this index */
10036  return false;
10037  }
10038 
10039  assert (segp != NULL);
10040 #if !defined(NDEBUG)
10041  {
10042  const char *col_name = pt_get_name (col);
10043 
10044  assert (!intl_identifier_casecmp (QO_SEG_NAME (segp), col_name));
10045  }
10046 #endif
10047 
10048  /* we now search in the class columns for the index key */
10049  for (i = 0; i < index_class->smclass->att_count; i++)
10050  {
10051  attr = &index_class->smclass->attributes[i];
10052  if (attr && !intl_identifier_casecmp (QO_SEG_NAME (segp), attr->header.name))
10053  {
10054  if (attr->flags & SM_ATTFLAG_NON_NULL)
10055  {
10056  attr_notnull = true;
10057  }
10058  else
10059  {
10060  attr_notnull = false;
10061  }
10062 
10063  break;
10064  }
10065  }
10066  if (i >= index_class->smclass->att_count)
10067  {
10068  /* column wasn't found - this should not happen! */
10069  assert (false);
10070  return false;
10071  }
10072 
10073  /* now search for not terms with the key */
10074  if (attr_notnull != true)
10075  {
10076  /* save old value of bail_out */
10077  old_bail_out = env->bail_out;
10078  env->bail_out = -1; /* no term found value */
10079 
10080  /* check for isnull terms with the key */
10081  env_seg[0] = (void *) env;
10082  env_seg[1] = (void *) segp;
10083  parser_walk_tree (env->parser, QO_ENV_PT_TREE (env)->info.query.q.select.where, qo_search_isnull_key_expr,
10084  env_seg, NULL, NULL);
10085 
10086  /* restore old value and keep walk_tree result in key_term_status */
10087  key_term_status = env->bail_out;
10088  env->bail_out = old_bail_out;
10089 
10090  /* if there is no isnull on the key, check that the key appears in some term and if so, make sure that that term
10091  * doesn't have a OR
10092  */
10093  if (key_term_status == 1)
10094  {
10095  BITSET expr_segments, key_segment;
10096  QO_TERM *termp;
10097  PT_NODE *pt_expr;
10098 
10099  bitset_init (&expr_segments, env);
10100  bitset_init (&key_segment, env);
10101 
10102  /* key segment bitset */
10103  bitset_add (&key_segment, QO_SEG_IDX (segp));
10104 
10105  /* key found in a term */
10106  for (i = 0; i < env->nterms; i++)
10107  {
10108  termp = QO_ENV_TERM (env, i);
10109  assert (termp != NULL);
10110 
10111  pt_expr = QO_TERM_PT_EXPR (termp);
10112  if (pt_expr == NULL)
10113  {
10114  continue;
10115  }
10116 
10117  if (pt_expr->or_next)
10118  {
10119  BITSET_CLEAR (expr_segments);
10120 
10121  qo_expr_segs (env, pt_expr, &expr_segments);
10122  if (bitset_intersects (&expr_segments, &key_segment))
10123  {
10124  break; /* give up */
10125  }
10126  }
10127  }
10128 
10129  if (i >= env->nterms)
10130  {
10131  attr_notnull = true; /* OK */
10132  }
10133 
10134  bitset_delset (&key_segment);
10135  bitset_delset (&expr_segments);
10136  }
10137  }
10138 
10139  return attr_notnull;
10140 }
10141 
10142 /*
10143  * qo_validate_index_for_orderby () - checks for isnull(key) or not null flag
10144  * env(in): pointer to the optimizer environment
10145  * ni_entryp(in): pointer to QO_NODE_INDEX_ENTRY (node index entry)
10146  * return: 1 if the index can be used, 0 elseware
10147  */
10148 static int
10150 {
10151  bool key_notnull = false; /* init */
10152  QO_INDEX_ENTRY *index_entryp;
10153  QO_CLASS_INFO_ENTRY *index_class;
10154 
10155  int pos;
10156  PT_NODE *node = NULL;
10157 
10158  assert (ni_entryp != NULL);
10159  assert (ni_entryp->head != NULL);
10160  assert (ni_entryp->head->class_ != NULL);
10161 
10162  index_entryp = ni_entryp->head;
10163  index_class = index_entryp->class_;
10164 
10165  if (!QO_ENV_PT_TREE (env) || !QO_ENV_PT_TREE (env)->info.query.order_by)
10166  {
10167  goto end;
10168  }
10169 
10170  key_notnull = qo_validate_index_term_notnull (env, index_entryp);
10171  if (key_notnull)
10172  {
10173  goto final_;
10174  }
10175 
10176  pos = QO_ENV_PT_TREE (env)->info.query.order_by->info.sort_spec.pos_descr.pos_no;
10177  node = QO_ENV_PT_TREE (env)->info.query.q.select.list;
10178 
10179  while (pos > 1 && node)
10180  {
10181  node = node->next;
10182  pos--;
10183  }
10184  if (!node)
10185  {
10186  goto end;
10187  }
10188 
10189  if (node->node_type == PT_EXPR && node->info.expr.op == PT_CAST)
10190  {
10191  node = node->info.expr.arg1;
10192  if (!node)
10193  {
10194  goto end;
10195  }
10196  }
10197 
10198  node = pt_get_end_path_node (node);
10199 
10200  assert (key_notnull == false);
10201 
10202  key_notnull = qo_validate_index_attr_notnull (env, index_entryp, node);
10203  if (key_notnull)
10204  {
10205  goto final_;
10206  }
10207 
10208  /* Now we have the information we need: if the key column can be null and if there is a PT_IS_NULL or PT_IS_NOT_NULL
10209  * expression with this key column involved and also if we have other terms with the key. We must decide if there can
10210  * be NULLs in the results and if so, drop this index. 1. If the key cannot have null values, we have a winner. 2.
10211  * Otherwise, if we found a term isnull/isnotnull(key) we drop it (because we cannot evaluate if this yields true or
10212  * false so we skip all, for safety) 3. If we have a term with other operator except isnull/isnotnull and does not
10213  * have an OR following we have a winner again! (because we cannot have a null value).
10214  */
10215 final_:
10216  if (key_notnull)
10217  {
10218  return 1;
10219  }
10220 end:
10221  return 0;
10222 }
10223 
10224 /*
10225  * qo_search_isnull_key_expr () -
10226  * return: PT_NODE *
10227  * parser(in): parser environment
10228  * tree(in): tree to walk
10229  * arg(in):
10230  * continue_walk(in):
10231  *
10232  * Note: for env->bail_out values, check key_term_status in
10233  * qo_validate_index_for_groupby, qo_validate_index_for_orderby
10234  */
10235 static PT_NODE *
10236 qo_search_isnull_key_expr (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
10237 {
10238  BITSET expr_segments, key_segment;
10239  QO_ENV *env;
10240  QO_SEGMENT *segm;
10241  void **env_seg = (void **) arg;
10242 
10243  env = (QO_ENV *) env_seg[0];
10244  segm = (QO_SEGMENT *) env_seg[1];
10245 
10246  *continue_walk = PT_CONTINUE_WALK;
10247 
10248  /* key segment bitset */
10249  bitset_init (&key_segment, env);
10250  bitset_add (&key_segment, QO_SEG_IDX (segm));
10251 
10252  bitset_init (&expr_segments, env);
10253  if (tree->node_type == PT_EXPR)
10254  {
10255  /* get all segments in this expression */
10256  qo_expr_segs (env, tree, &expr_segments);
10257 
10258  /* now check if the key segment is in there */
10259  if (bitset_intersects (&expr_segments, &key_segment))
10260  {
10261  /* this expr contains the key segment */
10262  if (tree->info.expr.op == PT_IS_NULL || tree->info.expr.op == PT_IS_NOT_NULL
10263  || tree->info.expr.op == PT_IFNULL || tree->info.expr.op == PT_NULLSAFE_EQ)
10264  {
10265  /* 0 all the way, suppress other terms found */
10266  env->bail_out = 0;
10267  *continue_walk = PT_STOP_WALK;
10268 
10269  return tree;
10270  }
10271  else if (env->bail_out == -1)
10272  {
10273  /* set as 1 only if we haven't found any isnull terms */
10274  env->bail_out = 1;
10275  }
10276  }
10277  }
10278 
10279  return tree;
10280 }
10281 
10282 /*
10283  * qo_plan_iscan_terms_cmp () - compare 2 index scan plans with terms
10284  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
10285  * a(in):
10286  * b(in):
10287  */
10290 {
10291  QO_NODE_INDEX_ENTRY *a_ni, *b_ni;
10292  QO_INDEX_ENTRY *a_ent, *b_ent;
10293  QO_ATTR_CUM_STATS *a_cum, *b_cum;
10294  int a_range, b_range; /* num iscan range terms */
10295  int a_filter, b_filter; /* num iscan filter terms */
10296 
10298  {
10301 
10302  return PLAN_COMP_UNK;
10303  }
10304 
10305  /* index entry of spec 'a' */
10306  a_ni = a->plan_un.scan.index;
10307  a_ent = (a_ni)->head;
10308  a_cum = &(a_ni)->cum_stats;
10309  assert (a_cum != NULL);
10310 
10311  /* index range terms */
10312  a_range = bitset_cardinality (&(a->plan_un.scan.terms));
10313  if (a_range > 0 && !(a->plan_un.scan.index_equi))
10314  {
10315  a_range--; /* set the last equal range term */
10316  }
10317 
10318  /* index filter terms */
10319  a_filter = bitset_cardinality (&(a->plan_un.scan.kf_terms));
10320 
10321  /* index entry of spec 'b' */
10322  b_ni = b->plan_un.scan.index;
10323  b_ent = (b_ni)->head;
10324  b_cum = &(b_ni)->cum_stats;
10325  assert (b_cum != NULL);
10326 
10327  /* index range terms */
10328  b_range = bitset_cardinality (&(b->plan_un.scan.terms));
10329  if (b_range > 0 && !(b->plan_un.scan.index_equi))
10330  {
10331  b_range--; /* set the last equal range term */
10332  }
10333 
10334  /* index filter terms */
10335  b_filter = bitset_cardinality (&(b->plan_un.scan.kf_terms));
10336 
10337  assert (a_range >= 0);
10338  assert (b_range >= 0);
10339 
10340  /* STEP 1: check by terms containment */
10341 
10342  if (bitset_is_equivalent (&(a->plan_un.scan.terms), &(b->plan_un.scan.terms)))
10343  {
10344  /* both plans have the same range terms we will check now the key filter terms */
10345  if (a_filter > b_filter)
10346  {
10347  return PLAN_COMP_LT;
10348  }
10349  else if (a_filter < b_filter)
10350  {
10351  return PLAN_COMP_GT;
10352  }
10353 
10354  /* both have the same range terms and same number of filters */
10355  if (a_cum && b_cum)
10356  {
10357  /* take the smaller index pages */
10358  if (a_cum->pages < b_cum->pages)
10359  {
10360  return PLAN_COMP_LT;
10361  }
10362  else if (a_cum->pages > b_cum->pages)
10363  {
10364  return PLAN_COMP_GT;
10365  }
10366 
10369 
10370  /* take the smaller index pkeys_size */
10371  if (a_cum->pkeys_size < b_cum->pkeys_size)
10372  {
10373  return PLAN_COMP_LT;
10374  }
10375  else if (a_cum->pkeys_size > b_cum->pkeys_size)
10376  {
10377  return PLAN_COMP_GT;
10378  }
10379  }
10380 
10381  /* both have the same number of index pages and pkeys_size */
10382  return PLAN_COMP_EQ;
10383  }
10384  else if (a_range > 0 && bitset_subset (&(a->plan_un.scan.terms), &(b->plan_un.scan.terms)))
10385  {
10386  return PLAN_COMP_LT;
10387  }
10388  else if (b_range > 0 && bitset_subset (&(b->plan_un.scan.terms), &(a->plan_un.scan.terms)))
10389  {
10390  return PLAN_COMP_GT;
10391  }
10392 
10393  /* STEP 2: check by term cardinality */
10394 
10395  if (a->plan_un.scan.index_equi == b->plan_un.scan.index_equi)
10396  {
10397  if (a_range > b_range)
10398  {
10399  return PLAN_COMP_LT;
10400  }
10401  else if (a_range < b_range)
10402  {
10403  return PLAN_COMP_GT;
10404  }
10405 
10406  assert (a_range == b_range);
10407 
10408  /* both plans have the same number of range terms we will check now the key filter terms */
10409  if (a_filter > b_filter)
10410  {
10411  return PLAN_COMP_LT;
10412  }
10413  else if (a_filter < b_filter)
10414  {
10415  return PLAN_COMP_GT;
10416  }
10417 
10418  /* both have the same number of range terms and same number of filters */
10419  return PLAN_COMP_EQ;
10420  }
10421 
10422  return PLAN_COMP_EQ; /* is equal with terms not cost */
10423 }
10424 
10425 /*
10426  * qo_group_by_skip_plans_cmp () - compare 2 index scan plans by group by skip
10427  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
10428  * a(in):
10429  * b(in):
10430  */
10433 {
10434  QO_INDEX_ENTRY *a_ent, *b_ent;
10435 
10437  {
10438  return PLAN_COMP_UNK;
10439  }
10440 
10441  a_ent = a->plan_un.scan.index->head;
10442  b_ent = b->plan_un.scan.index->head;
10443 
10444  if (a_ent == NULL || b_ent == NULL)
10445  {
10446  assert (false);
10447  return PLAN_COMP_UNK;
10448  }
10449 
10451  {
10452  return PLAN_COMP_UNK;
10453  }
10454 
10456  {
10457  return PLAN_COMP_UNK;
10458  }
10459 
10460  if (a_ent->groupby_skip)
10461  {
10462  if (b_ent->groupby_skip)
10463  {
10464  return qo_plan_iscan_terms_cmp (a, b);
10465  }
10466  else
10467  {
10468  return PLAN_COMP_LT;
10469  }
10470  }
10471  else
10472  {
10473  if (b_ent->groupby_skip)
10474  {
10475  return PLAN_COMP_GT;
10476  }
10477  }
10478 
10479  return PLAN_COMP_EQ;
10480 }
10481 
10482 /*
10483  * qo_order_by_skip_plans_cmp () - compare 2 index scan plans by order by skip
10484  * return: one of {PLAN_COMP_UNK, PLAN_COMP_LT, PLAN_COMP_EQ, PLAN_COMP_GT}
10485  * a(in):
10486  * b(in):
10487  */
10490 {
10491  QO_INDEX_ENTRY *a_ent, *b_ent;
10492 
10494  {
10495  return PLAN_COMP_UNK;
10496  }
10497 
10498  a_ent = a->plan_un.scan.index->head;
10499  b_ent = b->plan_un.scan.index->head;
10500 
10501  if (a_ent == NULL || b_ent == NULL)
10502  {
10503  assert (false);
10504  return PLAN_COMP_UNK;
10505  }
10506 
10508  {
10509  return PLAN_COMP_UNK;
10510  }
10511 
10513  {
10514  return PLAN_COMP_UNK;
10515  }
10516 
10517  if (a_ent->orderby_skip)
10518  {
10519  if (b_ent->orderby_skip)
10520  {
10521  return qo_plan_iscan_terms_cmp (a, b);
10522  }
10523  else
10524  {
10525  return PLAN_COMP_LT;
10526  }
10527  }
10528  else
10529  {
10530  if (b_ent->orderby_skip)
10531  {
10532  return PLAN_COMP_GT;
10533  }
10534  }
10535 
10536  return PLAN_COMP_EQ;
10537 }
10538 
10539 /*
10540  * qo_check_orderby_skip_descending - checks whether an index plan will
10541  * skip order by if its columns changes their direction.
10542  * return: true or false
10543  * plan (in): input index plan to be analyzed
10544  */
10545 static bool
10547 {
10548  bool orderby_skip = false;
10549  QO_ENV *env;
10550  PT_NODE *tree, *trav, *order_by;
10551 
10552  env = NULL;
10553  tree = order_by = NULL;
10554 
10555  if (plan == NULL)
10556  {
10557  return false;
10558  }
10559  if (plan->info)
10560  {
10561  env = plan->info->env;
10562  }
10563 
10564  if (env == NULL)
10565  {
10566  return false;
10567  }
10568 
10569  tree = QO_ENV_PT_TREE (env);
10570 
10571  if (tree == NULL)
10572  {
10573  return false;
10574  }
10575 
10576  if (tree->info.query.q.select.hint & PT_HINT_NO_IDX_DESC)
10577  {
10578  return false;
10579  }
10580 
10581  order_by = tree->info.query.order_by;
10582 
10583  for (trav = plan->iscan_sort_list; trav; trav = trav->next)
10584  {
10585  /* change PT_ASC to PT_DESC and vice-versa */
10587  }
10588 
10589  /* test again the order by skip */
10590  orderby_skip = pt_sort_spec_cover (plan->iscan_sort_list, order_by);
10591 
10592  /* change back directions */
10593  for (trav = plan->iscan_sort_list; trav; trav = trav->next)
10594  {
10595  /* change PT_ASC to PT_DESC and vice-versa */
10597  }
10598 
10599  return orderby_skip;
10600 }
10601 
10602 /*
10603  * qo_is_iscan_from_groupby ()
10604  * return: true/false
10605  * plan(in):
10606  */
10607 bool
10609 {
10610  if (plan && plan->plan_type == QO_PLANTYPE_SCAN && plan->plan_un.scan.scan_method == QO_SCANMETHOD_INDEX_GROUPBY_SCAN)
10611  {
10612  return true;
10613  }
10614 
10615  return false;
10616 }
10617 
10618 /*
10619  * qo_validate_index_for_groupby () - checks for isnull(key) or not null flag
10620  * env(in): pointer to the optimizer environment
10621  * ni_entryp(in): pointer to QO_NODE_INDEX_ENTRY (node index entry)
10622  * return: 1 if the index can be used, 0 elseware
10623  */
10624 static int
10626 {
10627  bool key_notnull = false; /* init */
10628  QO_INDEX_ENTRY *index_entryp;
10629  QO_CLASS_INFO_ENTRY *index_class;
10630 
10631  PT_NODE *groupby_expr = NULL;
10632 
10633  assert (ni_entryp != NULL);
10634  assert (ni_entryp->head != NULL);
10635  assert (ni_entryp->head->class_ != NULL);
10636 
10637  index_entryp = ni_entryp->head;
10638  index_class = index_entryp->class_;
10639 
10640  if (!QO_ENV_PT_TREE (env) || !QO_ENV_PT_TREE (env)->info.query.q.select.group_by)
10641  {
10642  goto end;
10643  }
10644 
10645  key_notnull = qo_validate_index_term_notnull (env, index_entryp);
10646  if (key_notnull)
10647  {
10648  goto final;
10649  }
10650 
10651  /* get the name of the first column in the group by list */
10652  groupby_expr = QO_ENV_PT_TREE (env)->info.query.q.select.group_by->info.sort_spec.expr;
10653 
10654  assert (key_notnull == false);
10655 
10656  key_notnull = qo_validate_index_attr_notnull (env, index_entryp, groupby_expr);
10657  if (key_notnull)
10658  {
10659  goto final;
10660  }
10661 
10662  /* Now we have the information we need: if the key column can be null and if there is a PT_IS_NULL or PT_IS_NOT_NULL
10663  * expression with this key column involved and also if we have other terms with the key. We must decide if there can
10664  * be NULLs in the results and if so, drop this index. 1. If the key cannot have null values, we have a winner. 2.
10665  * Otherwise, if we found a term isnull/isnotnull(key) we drop it (because we cannot evaluate if this yields true or
10666  * false so we skip all, for safety) 3. If we have a term with other operator except isnull/isnotnull and does not
10667  * have an OR following we have a winner again! (because we cannot have a null value).
10668  */
10669 final:
10670  if (key_notnull)
10671  {
10672  return 1;
10673  }
10674 end:
10675  return 0;
10676 }
10677 
10678 /*
10679  * qo_check_groupby_skip_descending - checks whether an index plan will
10680  * skip group by if its columns changes their direction.
10681  * return: true or false
10682  * plan (in): input index plan to be analyzed
10683  */
10684 static bool
10686 {
10687  bool groupby_skip = false;
10688  QO_ENV *env;
10689  PT_NODE *tree, *trav, *group_by;
10690 
10691  env = NULL;
10692  tree = group_by = NULL;
10693 
10694  if (plan == NULL)
10695  {
10696  return false;
10697  }
10698 
10699  if (plan->info)
10700  {
10701  env = plan->info->env;
10702  }
10703 
10704  if (env == NULL)
10705  {
10706  return false;
10707  }
10708 
10709  tree = QO_ENV_PT_TREE (env);
10710 
10711  if (tree == NULL)
10712  {
10713  return false;
10714  }
10715 
10716  if (tree->info.query.q.select.hint & PT_HINT_NO_IDX_DESC)
10717  {
10718  return false;
10719  }
10720 
10721  group_by = tree->info.query.q.select.group_by;
10722 
10723  for (trav = list; trav; trav = trav->next)
10724  {
10725  /* change PT_ASC to PT_DESC and vice-versa */
10727  }
10728 
10729  /* test again the group by skip */
10730  groupby_skip = pt_sort_spec_cover_groupby (env->parser, list, group_by, tree);
10731 
10732  /* change back directions */
10733  for (trav = list; trav; trav = trav->next)
10734  {
10735  /* change PT_ASC to PT_DESC and vice-versa */
10737  }
10738 
10739  return groupby_skip;
10740 }
10741 
10742 /*
10743  * qo_plan_compute_iscan_sort_list () -
10744  * return: sort_list
10745  * root(in):
10746  * group_by(in):
10747  * is_index_w_prefix(out):
10748  *
10749  */
10750 static PT_NODE *
10751 qo_plan_compute_iscan_sort_list (QO_PLAN * root, PT_NODE * group_by, bool * is_index_w_prefix)
10752 {
10753  QO_PLAN *plan;
10754  QO_ENV *env;
10756  PT_NODE *tree, *sort_list, *sort, *col, *node, *expr;
10757  QO_NODE_INDEX_ENTRY *ni_entryp;
10758  QO_INDEX_ENTRY *index_entryp;
10759  int nterms, equi_nterms, seg_idx, i, j;
10760  QO_SEGMENT *seg;
10761  PT_MISC_TYPE asc_or_desc;
10762  QFILE_TUPLE_VALUE_POSITION pos_descr;
10763  TP_DOMAIN *key_type, *col_type;
10764  BITSET *terms;
10765  BITSET_ITERATOR bi;
10766  bool is_const_eq_term;
10767 
10768  sort_list = NULL; /* init */
10769  col = NULL;
10770  *is_index_w_prefix = false;
10771 
10772  /* find sortable plan */
10773  plan = root;
10774  while (plan && plan->plan_type != QO_PLANTYPE_SCAN)
10775  {
10776  switch (plan->plan_type)
10777  {
10778  case QO_PLANTYPE_FOLLOW:
10779  plan = plan->plan_un.follow.head;
10780  break;
10781 
10782  case QO_PLANTYPE_JOIN:
10783  if (plan->plan_un.join.join_method == QO_JOINMETHOD_NL_JOIN
10784  || plan->plan_un.join.join_method == QO_JOINMETHOD_IDX_JOIN)
10785  {
10786  plan = plan->plan_un.join.outer;
10787  }
10788  else
10789  {
10790  /* QO_JOINMETHOD_MERGE_JOIN */
10791  plan = NULL;
10792  }
10793  break;
10794 
10795  case QO_PLANTYPE_SORT:
10796  if (plan->plan_un.sort.sort_type == SORT_LIMIT)
10797  {
10798  plan = plan->plan_un.sort.subplan;
10799  }
10800  else
10801  {
10802  plan = NULL;
10803  }
10804  break;
10805 
10806  default:
10807  plan = NULL;
10808  break;
10809  }
10810  }
10811 
10812  /* check for plan type */
10813  if (plan == NULL || plan->plan_type != QO_PLANTYPE_SCAN)
10814  {
10815  goto exit_on_end; /* nop */
10816  }
10817  else if (QO_NODE_INFO (plan->plan_un.scan.node) == NULL)
10818  {
10819  /* if there's no class information or the class is not normal class */
10820  goto exit_on_end; /* nop */
10821  }
10822  else if (QO_NODE_IS_CLASS_HIERARCHY (plan->plan_un.scan.node))
10823  {
10824  /* exclude class hierarchy scan */
10825  goto exit_on_end; /* nop */
10826  }
10827 
10828  /* check for index scan plan */
10829  if (!qo_is_interesting_order_scan (plan) || (env = (plan->info)->env) == NULL
10830  || (parser = QO_ENV_PARSER (env)) == NULL || (tree = QO_ENV_PT_TREE (env)) == NULL)
10831  {
10832  goto exit_on_end; /* nop */
10833  }
10834 
10835  /* pointer to QO_NODE_INDEX_ENTRY structure in QO_PLAN */
10836  ni_entryp = plan->plan_un.scan.index;
10837  /* pointer to linked list of index node, 'head' field(QO_INDEX_ENTRY strucutre) of QO_NODE_INDEX_ENTRY */
10838  index_entryp = (ni_entryp)->head;
10839 
10840  nterms = bitset_cardinality (&(plan->plan_un.scan.terms));
10841  if (nterms > 0)
10842  {
10843  equi_nterms = plan->plan_un.scan.index_equi ? nterms : nterms - 1;
10844  }
10845  else
10846  {
10847  equi_nterms = 0;
10848  }
10849  assert (equi_nterms >= 0);
10850 
10851  if (index_entryp->rangelist_seg_idx != -1)
10852  {
10853  equi_nterms = MIN (equi_nterms, index_entryp->rangelist_seg_idx);
10854  }
10855 
10856  /* we must have the first index column appear as the first sort column, so we pretend the number of index_equi
10857  * columns is zero, to force it to match the sort list and the index columns one-for-one.
10858  */
10859  if (qo_is_index_iss_scan (plan) || index_entryp->constraints->func_index_info != NULL)
10860  {
10861  equi_nterms = 0;
10862  }
10863  assert (equi_nterms >= 0);
10864  assert (equi_nterms <= index_entryp->nsegs);
10865 
10866  if (equi_nterms >= index_entryp->nsegs)
10867  {
10868  /* is all constant col's order node */
10869  goto exit_on_end; /* nop */
10870  }
10871 
10872  /* check if this is an index with prefix */
10873  *is_index_w_prefix = qo_is_prefix_index (index_entryp);
10874 
10875  asc_or_desc = (SM_IS_CONSTRAINT_REVERSE_INDEX_FAMILY (index_entryp->constraints->type) ? PT_DESC : PT_ASC);
10876 
10877  key_type = index_entryp->key_type;
10878  if (key_type == NULL)
10879  { /* is invalid case */
10880  assert (false);
10881  goto exit_on_end; /* nop */
10882  }
10883 
10884  if (asc_or_desc == PT_DESC || index_entryp->constraints->func_index_info != NULL)
10885  {
10886  col_type = NULL; /* nop; do not care asc_or_desc anymore */
10887  }
10888  else
10889  {
10890  if (TP_DOMAIN_TYPE (key_type) == DB_TYPE_MIDXKEY)
10891  {
10892  assert (QO_ENTRY_MULTI_COL (index_entryp));
10893 
10894  col_type = key_type->setdomain;
10895  assert (col_type != NULL);
10896 
10897  /* get the first non-equal range key domain */
10898  for (j = 0; j < equi_nterms && col_type; j++)
10899  {
10900  col_type = col_type->next;
10901  }
10902  }
10903  else
10904  {
10905  col_type = key_type;
10906 
10907  assert (col_type != NULL);
10908  assert (col_type->next == NULL);
10909  assert (equi_nterms <= 1);
10910 
10911  /* get the first non-equal range key domain */
10912  if (equi_nterms > 0)
10913  {
10914  col_type = NULL; /* give up */
10915  }
10916  }
10917 
10918  assert (col_type != NULL || equi_nterms > 0);
10919  }
10920 
10921  for (i = equi_nterms; i < index_entryp->nsegs; i++)
10922  {
10923  if (index_entryp->ils_prefix_len > 0 && i >= index_entryp->ils_prefix_len)
10924  {
10925  /* sort list should contain only prefix when using loose index scan */
10926  break;
10927  }
10928 
10929  seg_idx = (index_entryp->seg_idxs[i]);
10930  if (seg_idx == -1)
10931  { /* not exist in query */
10932  break; /* give up */
10933  }
10934 
10935  seg = QO_ENV_SEG (env, seg_idx);
10936  node = QO_SEG_PT_NODE (seg);
10937  if (node->node_type == PT_DOT_)
10938  {
10939  /* FIXME :: we do not handle path-expr here */
10940  break; /* give up */
10941  }
10942 
10943  if (index_entryp->constraints->func_index_info != NULL)
10944  {
10945  if (QO_SEG_FUNC_INDEX (seg) == true)
10946  {
10947  asc_or_desc = index_entryp->constraints->func_index_info->fi_domain->is_desc ? PT_DESC : PT_ASC;
10948  }
10949  }
10950  else
10951  {
10952  if (col_type)
10953  {
10954  asc_or_desc = (col_type->is_desc) ? PT_DESC : PT_ASC;
10955  col_type = col_type->next;
10956  }
10957 
10958  /* skip segment of const eq term */
10959  terms = &(QO_SEG_INDEX_TERMS (seg));
10960  is_const_eq_term = false;
10961  for (j = bitset_iterate (terms, &bi); j != -1; j = bitset_next_member (&bi))
10962  {
10963  expr = QO_TERM_PT_EXPR (QO_ENV_TERM (env, j));
10965  && (PT_IS_CONST (expr->info.expr.arg1) || PT_IS_CONST (expr->info.expr.arg2)))
10966  {
10967  is_const_eq_term = true;
10968  }
10969  }
10970  if (is_const_eq_term)
10971  {
10972  continue;
10973  }
10974  }
10975 
10976  /* is for order_by skip */
10977 
10978  /* check for constant col's order node */
10979  pt_to_pos_descr (parser, &pos_descr, node, tree, NULL);
10980  if (pos_descr.pos_no > 0)
10981  {
10982  col = tree->info.query.q.select.list;
10983  for (j = 1; j < pos_descr.pos_no && col; j++)
10984  {
10985  col = col->next;
10986  }
10987 
10988  if (col)
10989  {
10990  col = pt_get_end_path_node (col);
10991  if (col && col->node_type == PT_NAME && PT_NAME_INFO_IS_FLAGED (col, PT_NAME_INFO_CONSTANT))
10992  {
10993  continue; /* skip out constant order */
10994  }
10995  }
10996  }
10997 
10998  /* is for group_by skip */
10999  if (group_by != NULL)
11000  {
11001  assert (!group_by->flag.with_rollup);
11002 
11003  /* check for constant col's group node */
11004  pt_to_pos_descr_groupby (parser, &pos_descr, node, tree);
11005  if (pos_descr.pos_no > 0)
11006  {
11007  assert (group_by == tree->info.query.q.select.group_by);
11008  for (col = group_by, j = 1; j < pos_descr.pos_no && col; j++)
11009  {
11010  col = col->next;
11011  }
11012 
11013  while (col && col->node_type == PT_SORT_SPEC)
11014  {
11015  col = col->info.sort_spec.expr;
11016  }
11017 
11018  if (col)
11019  {
11020  col = pt_get_end_path_node (col);
11021  if (col && col->node_type == PT_NAME && PT_NAME_INFO_IS_FLAGED (col, PT_NAME_INFO_CONSTANT))
11022  {
11023  continue; /* skip out constant order */
11024  }
11025  }
11026  }
11027  }
11028 
11029  if (pos_descr.pos_no <= 0 || col == NULL)
11030  { /* not found i-th key element */
11031  break; /* give up */
11032  }
11033 
11034  /* set sort info */
11035  sort = parser_new_node (parser, PT_SORT_SPEC);
11036  if (sort == NULL)
11037  {
11039  break; /* give up */
11040  }
11041 
11042  sort->info.sort_spec.expr = pt_point (parser, col);
11043  sort->info.sort_spec.pos_descr = pos_descr;
11044  sort->info.sort_spec.asc_or_desc = asc_or_desc;
11045 
11046  sort_list = parser_append_node (sort, sort_list);
11047  }
11048 
11049 exit_on_end:
11050 
11051  return sort_list;
11052 }
11053 
11054 /*
11055  * qo_is_interesting_order_scan ()
11056  * return: true/false
11057  * plan(in):
11058  */
11059 bool
11061 {
11062  if (qo_is_iscan (plan) || qo_is_iscan_from_groupby (plan) || qo_is_iscan_from_orderby (plan))
11063  {
11064  return true;
11065  }
11066 
11067  return false;
11068 }
11069 
11070 /*
11071  * qo_plan_is_orderby_skip_candidate () - verify if a plan is a candidate for
11072  * orderby skip
11073  * return : true/false
11074  * plan (in) : plan to verify
11075  */
11076 static bool
11078 {
11080  PT_NODE *order_by, *statement;
11081  QO_ENV *env;
11082  bool is_prefix = false, is_orderby_skip = false;
11083 
11084  if (plan == NULL || plan->info == NULL)
11085  {
11086  assert (false);
11087  return false;
11088  }
11089 
11090  env = plan->info->env;
11091  parser = QO_ENV_PARSER (env);
11092  statement = QO_ENV_PT_TREE (env);
11093  order_by = statement->info.query.order_by;
11094 
11095  plan->iscan_sort_list = qo_plan_compute_iscan_sort_list (plan, NULL, &is_prefix);
11096 
11097  if (plan->iscan_sort_list == NULL || is_prefix)
11098  {
11099  is_orderby_skip = false;
11100  goto cleanup;
11101  }
11102 
11103  is_orderby_skip = pt_sort_spec_cover (plan->iscan_sort_list, order_by);
11104  if (!is_orderby_skip)
11105  {
11106  /* verify descending */
11107  is_orderby_skip = qo_check_orderby_skip_descending (plan);
11108  }
11109 
11110 cleanup:
11111  if (plan->iscan_sort_list)
11112  {
11113  parser_free_tree (parser, plan->iscan_sort_list);
11114  plan->iscan_sort_list = NULL;
11115  }
11116  return is_orderby_skip;
11117 }
11118 
11119 /*
11120  * qo_is_sort_limit () - verify if plan is a SORT-LIMIT plan
11121  * return : true/false
11122  * plan (in) :
11123  */
11124 static bool
11126 {
11127  return (plan != NULL && plan->plan_type == QO_PLANTYPE_SORT && plan->plan_un.sort.sort_type == SORT_LIMIT);
11128 }
11129 
11130 /*
11131  * qo_has_sort_limit_subplan () - verify if a plan has a SORT-LIMIT subplan
11132  * return : true if plan has SORT-LIMIT subplan, false otherwise
11133  * plan (in) : plan to verify
11134  */
11135 bool
11137 {
11138  if (plan == NULL)
11139  {
11140  return false;
11141  }
11142 
11143  switch (plan->plan_type)
11144  {
11145  case QO_PLANTYPE_SCAN:
11146  return false;
11147 
11148  case QO_PLANTYPE_SORT:
11149  if (plan->plan_un.sort.sort_type == SORT_LIMIT)
11150  {
11151  return true;
11152  }
11153  return qo_has_sort_limit_subplan (plan->plan_un.sort.subplan);
11154 
11155  case QO_PLANTYPE_JOIN:
11156  return (qo_has_sort_limit_subplan (plan->plan_un.join.outer)
11157  || qo_has_sort_limit_subplan (plan->plan_un.join.inner));
11158 
11159  case QO_PLANTYPE_FOLLOW:
11160  case QO_PLANTYPE_WORST:
11161  return false;
11162  }
11163 
11164  return false;
11165 }
11166 
11167 /*
11168  * plan dump for query profile
11169  */
11170 
11171 /*
11172  * qo_plan_scan_print_json ()
11173  * return:
11174  * plan(in):
11175  */
11176 static json_t *
11178 {
11179  BITSET_ITERATOR bi;
11180  QO_ENV *env;
11181  bool natural_desc_index = false;
11182  json_t *scan, *range, *filter;
11183  const char *scan_string = "";
11184  const char *class_name;
11185  int i;
11186 
11187  scan = json_object ();
11188 
11189  class_name = QO_NODE_NAME (plan->plan_un.scan.node);
11190  if (class_name == NULL)
11191  {
11192  class_name = "unknown";
11193  }
11194 
11195  json_object_set_new (scan, "table", json_string (class_name));
11196 
11197  switch (plan->plan_un.scan.scan_method)
11198  {
11200  scan_string = "TABLE SCAN";
11201  break;
11202 
11207  scan_string = "INDEX SCAN";
11208  json_object_set_new (scan, "index", json_string (plan->plan_un.scan.index->head->constraints->name));
11209 
11210  env = (plan->info)->env;
11211  range = json_array ();
11212 
11213  for (i = bitset_iterate (&(plan->plan_un.scan.terms), &bi); i != -1; i = bitset_next_member (&bi))
11214  {
11215  json_array_append_new (range, json_string (qo_term_string (QO_ENV_TERM (env, i))));
11216  }
11217 
11218  json_object_set_new (scan, "key range", range);
11219 
11220  if (bitset_cardinality (&(plan->plan_un.scan.kf_terms)) > 0)
11221  {
11222  filter = json_array ();
11223  for (i = bitset_iterate (&(plan->plan_un.scan.kf_terms), &bi); i != -1; i = bitset_next_member (&bi))
11224  {
11225  json_array_append_new (filter, json_string (qo_term_string (QO_ENV_TERM (env, i))));
11226  }
11227 
11228  json_object_set_new (scan, "key filter", filter);
11229  }
11230 
11231  if (qo_is_index_covering_scan (plan))
11232  {
11233  json_object_set_new (scan, "covered", json_true ());
11234  }
11235 
11236  if (plan->plan_un.scan.index && plan->plan_un.scan.index->head->use_descending)
11237  {
11238  json_object_set_new (scan, "desc_index", json_true ());
11239  natural_desc_index = true;
11240  }
11241 
11242  if (!natural_desc_index && (QO_ENV_PT_TREE (plan->info->env)->info.query.q.select.hint & PT_HINT_USE_IDX_DESC))
11243  {
11244  json_object_set_new (scan, "desc_index forced", json_true ());
11245  }
11246 
11247  if (qo_is_index_loose_scan (plan))
11248  {
11249  json_object_set_new (scan, "loose", json_true ());
11250  }
11251 
11252  break;
11253  }
11254 
11255  return json_pack ("{s:o}", scan_string, scan);
11256 }
11257 
11258 /*
11259  * qo_plan_sort_print_json ()
11260  * return:
11261  * plan(in):
11262  */
11263 static json_t *
11265 {
11266  json_t *sort, *subplan = NULL;
11267  const char *type;
11268 
11269  switch (plan->plan_un.sort.sort_type)
11270  {
11271  case SORT_TEMP:
11272  type = "SORT (temp)";
11273  break;
11274 
11275  case SORT_GROUPBY:
11276  type = "SORT (group by)";
11277  break;
11278 
11279  case SORT_ORDERBY:
11280  type = "SORT (order by)";
11281  break;
11282 
11283  case SORT_DISTINCT:
11284  type = "SORT (distinct)";
11285  break;
11286 
11287  case SORT_LIMIT:
11288  type = "SORT (limit)";
11289  break;
11290 
11291  default:
11292  assert (false);
11293  type = "";
11294  break;
11295  }
11296 
11297  sort = json_object ();
11298 
11299  if (plan->plan_un.sort.subplan)
11300  {
11301  subplan = qo_plan_print_json (plan->plan_un.sort.subplan);
11302  json_object_set_new (sort, type, subplan);
11303  }
11304  else
11305  {
11306  json_object_set_new (sort, type, json_string (""));
11307  }
11308 
11309  return sort;
11310 }
11311 
11312 /*
11313  * qo_plan_join_print_json ()
11314  * return:
11315  * plan(in):
11316  */
11317 static json_t *
11319 {
11320  json_t *join, *outer, *inner;
11321  const char *type, *method = "";
11322  char buf[32];
11323 
11324  switch (plan->plan_un.join.join_method)
11325  {
11326  case QO_JOINMETHOD_NL_JOIN:
11328  method = "NESTED LOOPS";
11329  break;
11330 
11332  method = "MERGE JOIN";
11333  break;
11334  }
11335 
11336  switch (plan->plan_un.join.join_type)
11337  {
11338  case JOIN_INNER:
11339  if (!bitset_is_empty (&(plan->plan_un.join.join_terms)))
11340  {
11341  type = "inner join";
11342  }
11343  else
11344  {
11345  if (plan->plan_un.join.join_method == QO_JOINMETHOD_IDX_JOIN)
11346  {
11347  type = "inner join";
11348  }
11349  else
11350  {
11351  type = "cross join";
11352  }
11353  }
11354  break;
11355  case JOIN_LEFT:
11356  type = "left outer join";
11357  break;
11358  case JOIN_RIGHT:
11359  type = "right outer join";
11360  break;
11361  case JOIN_OUTER: /* not used */
11362  type = "full outer join";
11363  break;
11364  case JOIN_CSELECT:
11365  type = "cselect";
11366  break;
11367  case NO_JOIN:
11368  default:
11369  type = "unknown";
11370  break;
11371  }
11372 
11373  outer = qo_plan_print_json (plan->plan_un.join.outer);
11374  inner = qo_plan_print_json (plan->plan_un.join.inner);
11375 
11376  sprintf (buf, "%s (%s)", method, type);
11377 
11378  join = json_pack ("{s:[o,o]}", buf, outer, inner);
11379 
11380  return join;
11381 }
11382 
11383 /*
11384  * qo_plan_follow_print_json ()
11385  * return:
11386  * plan(in):
11387  */
11388 static json_t *
11390 {
11391  json_t *head, *follow;
11392 
11393  head = qo_plan_print_json (plan->plan_un.follow.head);
11394 
11395  follow = json_object ();
11396  json_object_set_new (follow, "edge", json_string (qo_term_string (plan->plan_un.follow.path)));
11397  json_object_set_new (follow, "head", head);
11398 
11399  return json_pack ("{s:o}", "FOLLOW", follow);
11400 }
11401 
11402 /*
11403  * qo_plan_print_json ()
11404  * return:
11405  * plan(in):
11406  */
11407 static json_t *
11409 {
11410  json_t *json = NULL;
11411 
11412  switch (plan->plan_type)
11413  {
11414  case QO_PLANTYPE_SCAN:
11415  json = qo_plan_scan_print_json (plan);
11416  break;
11417 
11418  case QO_PLANTYPE_SORT:
11419  json = qo_plan_sort_print_json (plan);
11420  break;
11421 
11422  case QO_PLANTYPE_JOIN:
11423  json = qo_plan_join_print_json (plan);
11424  break;
11425 
11426  case QO_PLANTYPE_FOLLOW:
11427  json = qo_plan_follow_print_json (plan);
11428  break;
11429 
11430  default:
11431  break;
11432  }
11433 
11434  return json;
11435 }
11436 
11437 /*
11438  * qo_top_plan_print_json ()
11439  * return:
11440  * parser(in):
11441  * xasl(in):
11442  * select(in):
11443  * plan(in):
11444  */
11445 void
11447 {
11448  json_t *json;
11449  unsigned int save_custom;
11450 
11451  assert (parser != NULL && xasl != NULL && plan != NULL && select != NULL);
11452 
11453  if (parser->num_plan_trace >= MAX_NUM_PLAN_TRACE)
11454  {
11455  return;
11456  }
11457 
11458  json = qo_plan_print_json (plan);
11459 
11460  if (select->info.query.order_by)
11461  {
11462  if (xasl && xasl->spec_list && xasl->spec_list->indexptr && xasl->spec_list->indexptr->orderby_skip)
11463  {
11464  json_object_set_new (json, "skip order by", json_true ());
11465  }
11466  }
11467 
11468  if (select->info.query.q.select.group_by)
11469  {
11470  if (xasl && xasl->spec_list && xasl->spec_list->indexptr && xasl->spec_list->indexptr->groupby_skip)
11471  {
11472  json_object_set_new (json, "group by nosort", json_true ());
11473  }
11474  }
11475 
11476  save_custom = parser->custom_print;
11477  parser->custom_print |= PT_CONVERT_RANGE;
11478 
11479  json_object_set_new (json, "rewritten query", json_string (parser_print_tree (parser, select)));
11480 
11481  parser->custom_print = save_custom;
11482 
11483  parser->plan_trace[parser->num_plan_trace].format = QUERY_TRACE_JSON;
11484  parser->plan_trace[parser->num_plan_trace].trace.json_plan = json;
11485  parser->num_plan_trace++;
11486 
11487  return;
11488 }
11489 
11490 /*
11491  * qo_plan_scan_print_text ()
11492  * return:
11493  * fp(in):
11494  * plan(in):
11495  * indent(in):
11496  */
11497 static void
11498 qo_plan_scan_print_text (FILE * fp, QO_PLAN * plan, int indent)
11499 {
11500  BITSET_ITERATOR bi;
11501  QO_ENV *env;
11502  bool natural_desc_index = false;
11503  const char *class_name;
11504  int i;
11505 
11506  indent += 2;
11507  fprintf (fp, "%*c", indent, ' ');
11508 
11509  class_name = QO_NODE_NAME (plan->plan_un.scan.node);
11510  if (class_name == NULL)
11511  {
11512  class_name = "unknown";
11513  }
11514 
11515  switch (plan->plan_un.scan.scan_method)
11516  {
11518  fprintf (fp, "TABLE SCAN (%s)", class_name);
11519  break;
11520 
11525  fprintf (fp, "INDEX SCAN (%s.%s)", class_name, plan->plan_un.scan.index->head->constraints->name);
11526 
11527  env = (plan->info)->env;
11528  fprintf (fp, " (");
11529 
11530  for (i = bitset_iterate (&(plan->plan_un.scan.terms), &bi); i != -1; i = bitset_next_member (&bi))
11531  {
11532  fprintf (fp, "key range: %s", qo_term_string (QO_ENV_TERM (env, i)));
11533  }
11534 
11535  if (bitset_cardinality (&(plan->plan_un.scan.kf_terms)) > 0)
11536  {
11537  for (i = bitset_iterate (&(plan->plan_un.scan.kf_terms), &bi); i != -1; i = bitset_next_member (&bi))
11538  {
11539  fprintf (fp, ", key filter: %s", qo_term_string (QO_ENV_TERM (env, i)));
11540  }
11541  }
11542 
11543  if (qo_is_index_covering_scan (plan))
11544  {
11545  fprintf (fp, ", covered: true");
11546  }
11547 
11548  if (plan->plan_un.scan.index && plan->plan_un.scan.index->head->use_descending)
11549  {
11550  fprintf (fp, ", desc_index: true");
11551  natural_desc_index = true;
11552  }
11553 
11554  if (!natural_desc_index && (QO_ENV_PT_TREE (plan->info->env)->info.query.q.select.hint & PT_HINT_USE_IDX_DESC))
11555  {
11556  fprintf (fp, ", desc_index forced: true");
11557  }
11558 
11559  if (qo_is_index_loose_scan (plan))
11560  {
11561  fprintf (fp, ", loose: true");
11562  }
11563 
11564  fprintf (fp, ")");
11565  break;
11566  }
11567 
11568  fprintf (fp, "\n");
11569 }
11570 
11571 /*
11572  * qo_plan_sort_print_text ()
11573  * return:
11574  * fp(in):
11575  * plan(in):
11576  * indent(in):
11577  */
11578 static void
11579 qo_plan_sort_print_text (FILE * fp, QO_PLAN * plan, int indent)
11580 {
11581  const char *type;
11582 
11583  indent += 2;
11584 
11585  switch (plan->plan_un.sort.sort_type)
11586  {
11587  case SORT_TEMP:
11588  type = "SORT (temp)";
11589  break;
11590 
11591  case SORT_GROUPBY:
11592  type = "SORT (group by)";
11593  break;
11594 
11595  case SORT_ORDERBY:
11596  type = "SORT (order by)";
11597  break;
11598 
11599  case SORT_DISTINCT:
11600  type = "SORT (distinct)";
11601  break;
11602 
11603  case SORT_LIMIT:
11604  type = "SORT (limit)";
11605  break;
11606 
11607  default:
11608  assert (false);
11609  type = "";
11610  break;
11611  }
11612 
11613  fprintf (fp, "%*c%s\n", indent, ' ', type);
11614 
11615  if (plan->plan_un.sort.subplan)
11616  {
11617  qo_plan_print_text (fp, plan->plan_un.sort.subplan, indent);
11618  }
11619 }
11620 
11621 /*
11622  * qo_plan_join_print_text ()
11623  * return:
11624  * fp(in):
11625  * plan(in):
11626  * indent(in):
11627  */
11628 static void
11629 qo_plan_join_print_text (FILE * fp, QO_PLAN * plan, int indent)
11630 {
11631  const char *type, *method = "";
11632 
11633  indent += 2;
11634 
11635  switch (plan->plan_un.join.join_method)
11636  {
11637  case QO_JOINMETHOD_NL_JOIN:
11639  method = "NESTED LOOPS";
11640  break;
11641 
11643  method = "MERGE JOIN";
11644  break;
11645  }
11646 
11647  switch (plan->plan_un.join.join_type)
11648  {
11649  case JOIN_INNER:
11650  if (!bitset_is_empty (&(plan->plan_un.join.join_terms)))
11651  {
11652  type = "inner join";
11653  }
11654  else
11655  {
11656  if (plan->plan_un.join.join_method == QO_JOINMETHOD_IDX_JOIN)
11657  {
11658  type = "inner join";
11659  }
11660  else
11661  {
11662  type = "cross join";
11663  }
11664  }
11665  break;
11666  case JOIN_LEFT:
11667  type = "left outer join";
11668  break;
11669  case JOIN_RIGHT:
11670  type = "right outer join";
11671  break;
11672  case JOIN_OUTER: /* not used */
11673  type = "full outer join";
11674  break;
11675  case JOIN_CSELECT:
11676  type = "cselect";
11677  break;
11678  case NO_JOIN:
11679  default:
11680  type = "unknown";
11681  break;
11682  }
11683 
11684  fprintf (fp, "%*c%s (%s)\n", indent, ' ', method, type);
11685  qo_plan_print_text (fp, plan->plan_un.join.outer, indent);
11686  qo_plan_print_text (fp, plan->plan_un.join.inner, indent);
11687 }
11688 
11689 /*
11690  * qo_plan_follow_print_text ()
11691  * return:
11692  * fp(in):
11693  * plan(in):
11694  * indent(in):
11695  */
11696 static void
11697 qo_plan_follow_print_text (FILE * fp, QO_PLAN * plan, int indent)
11698 {
11699  indent += 2;
11700 
11701  fprintf (fp, "%*cFOLLOW (edge: %s)\n", indent, ' ', qo_term_string (plan->plan_un.follow.path));
11702 
11703  qo_plan_print_text (fp, plan->plan_un.follow.head, indent);
11704 }
11705 
11706 /*
11707  * qo_plan_print_text ()
11708  * return:
11709  * fp(in):
11710  * plan(in):
11711  * indent(in):
11712  */
11713 static void
11714 qo_plan_print_text (FILE * fp, QO_PLAN * plan, int indent)
11715 {
11716  switch (plan->plan_type)
11717  {
11718  case QO_PLANTYPE_SCAN:
11719  qo_plan_scan_print_text (fp, plan, indent);
11720  break;
11721 
11722  case QO_PLANTYPE_SORT:
11723  qo_plan_sort_print_text (fp, plan, indent);
11724  break;
11725 
11726  case QO_PLANTYPE_JOIN:
11727  qo_plan_join_print_text (fp, plan, indent);
11728  break;
11729 
11730  case QO_PLANTYPE_FOLLOW:
11731  qo_plan_follow_print_text (fp, plan, indent);
11732  break;
11733 
11734  default:
11735  break;
11736  }
11737 }
11738 
11739 /*
11740  * qo_top_plan_print_text ()
11741  * return:
11742  * parser(in):
11743  * xasl(in):
11744  * select(in):
11745  * plan(in):
11746  */
11747 void
11749 {
11750  size_t sizeloc;
11751  char *ptr, *sql;
11752  FILE *fp;
11753  int indent;
11754  unsigned int save_custom;
11755 
11756  assert (parser != NULL && xasl != NULL && plan != NULL && select != NULL);
11757 
11758  if (parser->num_plan_trace >= MAX_NUM_PLAN_TRACE)
11759  {
11760  return;
11761  }
11762 
11763  fp = port_open_memstream (&ptr, &sizeloc);
11764  if (fp == NULL)
11765  {
11766  return;
11767  }
11768 
11769  indent = 0;
11770  qo_plan_print_text (fp, plan, indent);
11771 
11772  indent += 2;
11773 
11774  if (select->info.query.order_by)
11775  {
11776  if (xasl && xasl->spec_list && xasl->spec_list->indexptr && xasl->spec_list->indexptr->orderby_skip)
11777  {
11778  fprintf (fp, "%*cskip order by: true\n", indent, ' ');
11779  }
11780  }
11781 
11782  if (select->info.query.q.select.group_by)
11783  {
11784  if (xasl && xasl->spec_list && xasl->spec_list->indexptr && xasl->spec_list->indexptr->groupby_skip)
11785  {
11786  fprintf (fp, "%*cgroup by nosort: true\n", indent, ' ');
11787  }
11788  }
11789 
11790  save_custom = parser->custom_print;
11791  parser->custom_print |= PT_CONVERT_RANGE;
11792  sql = parser_print_tree (parser, select);
11793  parser->custom_print = save_custom;
11794 
11795  if (sql != NULL)
11796  {
11797  fprintf (fp, "\n%*crewritten query: %s\n", indent, ' ', sql);
11798  }
11799 
11800  port_close_memstream (fp, &ptr, &sizeloc);
11801 
11802  if (ptr != NULL)
11803  {
11804  parser->plan_trace[parser->num_plan_trace].format = QUERY_TRACE_TEXT;
11805  parser->plan_trace[parser->num_plan_trace].trace.text_plan = ptr;
11806  parser->num_plan_trace++;
11807  }
11808 
11809  return;
11810 }
double fixed_cpu_cost
int nsubqueries
Definition: query_graph.h:896
static void qo_plan_print_text(FILE *fp, QO_PLAN *plan, int indent)
bool qo_is_iscan(QO_PLAN *plan)
PT_NODE * order_by
Definition: parse_tree.h:2769
QO_CLASS_INFO_ENTRY * class_
Definition: query_graph.h:105
bool qo_check_iscan_for_multi_range_opt(QO_PLAN *plan)
PT_NODE * next
Definition: parse_tree.h:3447
QO_INFO * info
PT_NAME_INFO name
Definition: parse_tree.h:3318
static void qo_follow_info(QO_PLAN *, FILE *, int)
#define QO_TERM_SUBQUERIES(t)
Definition: query_graph.h:726
QO_PARTITION * partitions
Definition: query_graph.h:870
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: parse_tree.h:2829
static QO_INFO * qo_alloc_info(QO_PLANNER *, BITSET *, BITSET *, BITSET *, double)
static QO_PLAN * qo_worst_new(QO_ENV *)
QO_EQCLASS * order
#define PT_IS_QUERY(n)
Definition: parse_tree.h:296
static json_t * qo_plan_scan_print_json(QO_PLAN *plan)
QO_TERM * terms
Definition: query_graph.h:868
unsigned with_rollup
Definition: parse_tree.h:3472
PT_NODE * arg_list
Definition: parse_tree.h:2258
#define NO_ERROR
Definition: error_code.h:46
PT_UNION_INFO union_
Definition: parse_tree.h:2782
int bail_out
Definition: query_graph.h:913
bool is_iss_candidate
Definition: query_graph.h:155
static void qo_sort_walk(QO_PLAN *, void(*)(QO_PLAN *, void *), void *, void(*)(QO_PLAN *, void *), void *)
int(* QO_WALK_FUNCTION)(QO_PLAN *, void *)
Definition: query_planner.c:92
#define QO_TERM_MULTI_COLL_PRED
Definition: query_graph.h:745
int neqclasses
Definition: query_graph.h:894
struct qo_plan::@100::@103 sort
#define LANG_SYS_COLLATION
static json_t * qo_plan_print_json(QO_PLAN *plan)
static int qo_plans_allocated
Definition: query_planner.c:97
PRED_CLASS
int bitset_is_equivalent(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:342
QO_PLAN * plan[NPLANS]
static QO_PLAN_VTBL qo_worst_plan_vtbl
#define PT_EXPR_INFO_FULL_RANGE
Definition: parse_tree.h:2223
struct qo_summary * qo_summary
Definition: parse_tree.h:2703
#define IO_PAGESIZE
static PRED_CLASS qo_classify(PT_NODE *attr)
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
#define PT_ERRORm(parser, node, setNo, msgNo)
Definition: parse_tree.h:63
bool cover_segments
Definition: query_graph.h:140
#define BITSET_CLEAR(s)
Definition: query_bitset.h:68
static QO_PLAN_VTBL qo_follow_plan_vtbl
void qo_get_optimization_param(void *, QO_PARAM,...)
Definition: query_graph.c:269
void qo_env_free(QO_ENV *env)
Definition: query_graph.c:5808
#define qo_plan_add_ref(p)
#define QO_ASSERT(env, cond)
Definition: optimizer.h:52
BITSET terms
Definition: query_graph.h:134
static void qo_worst_cost(QO_PLAN *)
double qo_expr_selectivity(QO_ENV *env, PT_NODE *pt_expr)
int nsegs
Definition: query_graph.h:892
#define QO_ENV_LIMIT_VALUE(env)
Definition: query_graph.h:967
#define qo_plan_del_ref(p)
SM_PREDICATE_INFO * filter_predicate
Definition: class_object.h:536
static void qo_plan_scan_print_text(FILE *fp, QO_PLAN *plan, int indent)
static QO_PLAN * qo_search_partition(QO_PLANNER *, QO_PARTITION *, QO_EQCLASS *, BITSET *)
#define QO_TERM_IDX(t)
Definition: query_graph.h:723
#define QO_TERM_INDEX_SEG(t, i)
Definition: query_graph.h:732
#define QO_NI_ENTRY(ni, n)
Definition: query_graph.h:238
#define QO_TERM_IS_FLAGED(t, f)
Definition: query_graph.h:749
void pt_to_pos_descr_groupby(PARSER_CONTEXT *parser, QFILE_TUPLE_VALUE_POSITION *pos_p, PT_NODE *node, PT_NODE *root)
Definition: query_graph.h:209
#define DETAILED_DUMP(level)
Definition: optimizer.h:86
bool qo_is_iscan_from_orderby(QO_PLAN *plan)
static double qo_and_selectivity(QO_ENV *env, double lhs_sel, double rhs_sel)
int rangelist_seg_idx
Definition: query_graph.h:125
int bitset_intersects(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:295
PT_MISC_TYPE
Definition: parse_tree.h:983
bool has_sort_limit
void qo_expr_segs(QO_ENV *env, PT_NODE *pt_expr, BITSET *result)
Definition: query_graph.c:2734
static int qo_examine_correlated_index(QO_INFO *, JOIN_TYPE, QO_INFO *, QO_INFO *, BITSET *, BITSET *, BITSET *)
static void qo_uninit_planvec(QO_PLANVEC *)
void qo_eqclass_fprint_wrt(QO_EQCLASS *eqclass, BITSET *nodeset, FILE *f)
Definition: query_graph.c:8740
analytic_list_node * head
static void qo_scan_info(QO_PLAN *, FILE *, int)
#define DEFAULT_EQUIJOIN_SELECTIVITY
int ils_prefix_len
Definition: query_graph.h:158
int bitset_iterate(const BITSET *s, BITSET_ITERATOR *si)
Definition: query_bitset.c:464
void qo_print_stats(FILE *f)
Definition: query_graph.c:9166
static void qo_detach_info(QO_INFO *)
INDX_INFO * indexptr
Definition: xasl.h:927
#define QO_ENV_PARSER(env)
Definition: query_graph.h:964
#define ER_FAILED
Definition: error_code.h:47
#define IS_OUTER_JOIN_TYPE(t)
Definition: query_list.h:42
#define QO_NODE_IS_CLASS_PARTITIONED(node)
Definition: query_graph.h:417
#define QO_CPU_WEIGHT
Definition: query_planner.h:43
#define MSGCAT_SEMANTIC_OUT_OF_MEMORY
static void qo_plan_print_sarged_terms(QO_PLAN *, FILE *, int)
int nsegs
Definition: query_graph.h:119
static int qo_generate_join_index_scan(QO_INFO *, JOIN_TYPE, QO_PLAN *, QO_INFO *, QO_NODE *, QO_NODE_INDEX_ENTRY *, BITSET *, BITSET *, BITSET *, BITSET *)
bool multi_range_opt_candidate
Definition: query_graph.h:954
SM_CLASS * smclass
Definition: query_graph.h:73
struct tp_domain * setdomain
Definition: object_domain.h:82
QO_PLANNER * planner
Definition: query_graph.h:920
#define qo_sort_free
Definition: query_planner.c:79
static void qo_plan_del_ref_func(QO_PLAN *plan, void *ignore)
static bool qo_index_has_bit_attr(QO_INDEX_ENTRY *index_entryp)
static const char * qo_term_string(QO_TERM *)
TP_DOMAIN * domain
Definition: class_object.h:444
PT_SPEC_INFO spec
Definition: parse_tree.h:3346
#define QO_ON_COND_TERM(term)
Definition: query_graph.h:995
#define QO_SEG_HEAD(seg)
Definition: query_graph.h:510
QO_INFO ** node_info
QUERY_TRACE_FORMAT format
Definition: parse_tree.h:3519
static QO_PLANNER * qo_alloc_planner(QO_ENV *)
static double qo_or_selectivity(QO_ENV *env, double lhs_sel, double rhs_sel)
bool qo_is_interesting_order_scan(QO_PLAN *plan)
PT_NODE * arg2
Definition: parse_tree.h:2664
#define VALID_INNER(plan)
Definition: query_planner.c:67
double fixed_io_cost
Definition: optimizer.h:111
static void qo_plan_print_outer_join_terms(QO_PLAN *, FILE *, int)
#define DEFAULT_EQUAL_SELECTIVITY
static void qo_plan_free(QO_PLAN *)
#define QO_JOIN_INFO_SIZE(_partition)
Definition: query_graph.h:1024
bool groupby_skip
Definition: query_graph.h:149
static int qo_validate_index_for_groupby(QO_ENV *env, QO_NODE_INDEX_ENTRY *ni_entryp)
static QO_INFO * qo_search_partition_join(QO_PLANNER *, QO_PARTITION *, BITSET *)
SM_ATTRIBUTE * attributes
Definition: class_object.h:721
PT_NODE * node
Definition: query_graph.h:766
int can_use_index
Definition: query_graph.h:663
QO_PLAN * worst_plan
static bool qo_plan_is_orderby_skip_candidate(QO_PLAN *plan)
analytic_eval_type * next
static QO_PLAN * qo_plan_finalize(QO_PLAN *)
int bitset_is_empty(const BITSET *s)
Definition: query_bitset.c:318
#define QO_UNORDERED
Definition: query_graph.h:553
static QO_PLAN * qo_scan_new(QO_INFO *, QO_NODE *, QO_SCANMETHOD)
static void qo_plan_add_to_free_list(QO_PLAN *, void *ignore)
#define QO_IS_LIMIT_NODE(env, node)
Definition: query_planner.c:86
#define assert_release(e)
Definition: error_manager.h:96
static void qo_set_use_desc(QO_PLAN *plan)
union pt_plan_trace_info::@133 trace
SORT_TYPE
Definition: query_list.h:389
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
#define QO_TERM_LOCATION(t)
Definition: query_graph.h:725
static void qo_plan_walk(QO_PLAN *, void(*)(QO_PLAN *, void *), void *, void(*)(QO_PLAN *, void *), void *)
BITSET sort_limit_nodes
Definition: query_graph.h:901
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2552
void bitset_difference(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:224
void(* cost_fn)(QO_PLAN *)
Definition: query_planner.h:77
#define QO_TERM_PT_EXPR(t)
Definition: query_graph.h:724
static void qo_plan_compute_cost(QO_PLAN *)
PT_NODE * pt_tree
Definition: query_graph.h:863
PT_NODE * pt_get_end_path_node(PT_NODE *node)
static double qo_equal_selectivity(QO_ENV *env, PT_NODE *pt_expr)
#define QO_NI_N(ni)
Definition: query_graph.h:237
#define SM_IS_CONSTRAINT_UNIQUE_FAMILY(c)
Definition: class_object.h:111
unsigned int P
union pt_query_info::@124 q
int detached
QO_INFO * info_list
PT_NODE * node
Definition: parse_tree.h:3133
static void qo_worst_info(QO_PLAN *, FILE *, int)
static void qo_follow_fprint(QO_PLAN *, FILE *, int)
void qo_term_fprint(QO_TERM *term, FILE *f)
Definition: query_graph.c:8792
SM_FUNCTION_INFO * func_index_info
Definition: class_object.h:541
unsigned int custom_print
Definition: parse_tree.h:3556
#define QO_NODE_INFO_N(node)
Definition: query_graph.h:404
QO_PLANNER * planner
PT_NODE * group_by
Definition: parse_tree.h:2688
static void qo_iscan_cost(QO_PLAN *)
#define QO_NODE_HINT(node)
Definition: query_graph.h:407
#define QO_IS_EDGE_TERM(t)
Definition: query_graph.h:584
QO_EQCLASS * eqclasses
Definition: query_graph.h:867
SM_CLASS_CONSTRAINT * constraints
Definition: query_graph.h:108
bool qo_is_seq_scan(QO_PLAN *plan)
#define QO_ENV_USE_SORT_LIMIT(env)
Definition: query_graph.h:969
int npartitions
Definition: query_graph.h:897
#define PT_NAME_INFO_IS_FLAGED(e, f)
Definition: parse_tree.h:2574
struct qo_plan::@100::@104 join
bool orderby_skip
Definition: query_graph.h:146
QO_PARTITION * partition
static QO_PLAN_COMPARE_RESULT qo_index_covering_plans_cmp(QO_PLAN *, QO_PLAN *)
#define QO_NODE_INFO(node)
Definition: query_graph.h:403
Definition: query_graph.h:44
static void qo_plans_teardown(QO_ENV *env)
static void qo_plan_print_sort_spec(QO_PLAN *, FILE *, int)
bool qo_check_join_for_multi_range_opt(QO_PLAN *plan)
QO_SCANMETHOD
Definition: query_planner.h:54
JOIN_TYPE
Definition: query_list.h:32
int nedges
Definition: query_graph.h:898
static void qo_follow_cost(QO_PLAN *)
unsigned int S
#define QO_EQCLASS_IDX(e)
Definition: query_graph.h:558
static QO_PLAN * qo_top_plan_new(QO_PLAN *)
QO_SUBQUERY * subqueries
Definition: query_graph.h:869
#define QO_SEG_NAME(seg)
Definition: query_graph.h:514
#define NPLANS
#define SIMPLE_DUMP(level)
Definition: optimizer.h:85
#define TITLE_FMT
Definition: query_planner.c:58
static QO_PLAN_COMPARE_RESULT qo_plan_cmp_prefer_covering_index(QO_PLAN *, QO_PLAN *)
#define DEFAULT_SELECTIVITY
const char * pt_get_name(PT_NODE *nam)
#define QO_NODE_REL_IDX(node)
Definition: query_graph.h:393
#define QO_SEG_INDEX_TERMS(seg)
Definition: query_graph.h:523
bool all_unique_index_columns_are_equi_terms
Definition: query_graph.h:137
QO_SUBQUERY * subqueries
PT_DOT_INFO dot
Definition: parse_tree.h:3287
void qo_plan_lite_print(QO_PLAN *, FILE *, int)
PT_NODE * arg2
Definition: parse_tree.h:2086
QO_PLAN_VTBL * all_vtbls[]
int projected_size
#define qo_scan_walk
Definition: query_planner.c:75
static void qo_free_info(QO_INFO *)
#define QO_PARTITION_PLAN(p)
Definition: query_graph.h:832
static void qo_plan_join_print_text(FILE *fp, QO_PLAN *plan, int indent)
#define QO_NODE_DEP_SET(node)
Definition: query_graph.h:387
static double qo_all_some_in_selectivity(QO_ENV *env, PT_NODE *pt_expr)
QO_SEGMENT * segment
void qo_plan_discard(QO_PLAN *plan)
static QO_PLAN * qo_seq_scan_new(QO_INFO *, QO_NODE *)
PT_CTE_INFO cte
Definition: parse_tree.h:3282
PT_PRINT_VALUE_FUNC print_db_value
Definition: parse_tree.h:3553
#define QO_NODE_NCARD(node)
Definition: query_graph.h:405
static int qo_examine_merge_join(QO_INFO *, JOIN_TYPE, QO_INFO *, QO_INFO *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *)
QO_PLAN * plan
Definition: query_graph.h:817
#define QO_TERM_CLASS(t)
Definition: query_graph.h:716
PT_TYPE_ENUM type_enum
Definition: parse_tree.h:3457
static QO_PLAN_VTBL qo_set_follow_plan_vtbl
static int qo_plans_deallocated
Definition: query_planner.c:98
bool qo_is_iscan_from_groupby(QO_PLAN *plan)
const char * lang_get_collation_name(const int coll_id)
PT_NODE * or_next
Definition: parse_tree.h:3448
static char * node_name
Definition: cas_runner.c:174
#define QO_PARTITION_M_OFFSET(p)
Definition: query_graph.h:831
static void qo_generate_seq_scan(QO_INFO *, QO_NODE *)
int db_make_string(DB_VALUE *value, DB_CONST_C_CHAR str)
static PT_NODE * qo_search_isnull_key_expr(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
static int infos_deallocated
Definition: query_planner.c:95
int att_count
Definition: class_object.h:720
double QO_INFINITY
Definition: query_graph.c:160
static QO_PLAN_COMPARE_RESULT qo_group_by_skip_plans_cmp(QO_PLAN *, QO_PLAN *)
#define TEMP_SETUP_COST
Definition: query_planner.c:72
void port_close_memstream(FILE *fp, char **ptr, size_t *sizeloc)
Definition: porting.c:2220
#define NONGROUPED_SCAN_COST
Definition: query_planner.c:73
unsigned int M
bool qo_is_index_loose_scan(QO_PLAN *plan)
static int qo_plans_demalloced
bool use_descending
Definition: query_graph.h:152
PT_MISC_TYPE derived_table_type
Definition: parse_tree.h:2147
static void qo_compute_projected_segs(QO_PLANNER *, BITSET *, BITSET *, BITSET *)
static QO_PLAN_VTBL qo_index_scan_plan_vtbl
static int qo_has_is_not_null_term(QO_NODE *node)
static double log3(double)
static QO_PLAN_COMPARE_RESULT qo_order_by_skip_plans_cmp(QO_PLAN *, QO_PLAN *)
static void qo_join_walk(QO_PLAN *, void(*)(QO_PLAN *, void *), void *, void(*)(QO_PLAN *, void *), void *)
PT_NODE * arg1
Definition: parse_tree.h:2663
TP_DOMAIN * key_type
Definition: query_graph.h:116
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int bitset_subset(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:263
PT_HINT_ENUM
Definition: parse_tree.h:1161
PT_NODE * arg2
Definition: parse_tree.h:2198
PT_FUNCTION_INFO function
Definition: parse_tree.h:3301
static void qo_join_info(QO_PLAN *, FILE *, int)
#define QO_PLAN_CMP_CHECK_COST(a, b)
static void qo_plan_print_costs(QO_PLAN *, FILE *, int)
void qo_termset_fprint(QO_ENV *env, BITSET *terms, FILE *f)
Definition: query_graph.c:8845
#define assert(x)
QO_ATTR_CUM_STATS cum_stats
Definition: query_graph.h:215
static void qo_scan_free(QO_PLAN *)
static bool qo_validate_index_term_notnull(QO_ENV *env, QO_INDEX_ENTRY *index_entryp)
BITSET terms
BITSET final_segs
Definition: query_graph.h:886
unsigned long node_mask
static void planner_permutate(QO_PLANNER *, QO_PARTITION *, PT_HINT_ENUM, QO_NODE *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, int, int *)
#define QO_TERM_TAIL(t)
Definition: query_graph.h:722
void bitset_print(const BITSET *s, FILE *fp)
Definition: query_bitset.c:527
void bitset_delset(BITSET *s)
Definition: query_bitset.c:571
#define INDENT_FMT
Definition: query_planner.c:56
void qo_top_plan_print_text(PARSER_CONTEXT *parser, xasl_node *xasl, PT_NODE *select, QO_PLAN *plan)
static PT_NODE * qo_plan_compute_iscan_sort_list(QO_PLAN *root, PT_NODE *group_by, bool *is_index_w_prefix)
static void sort_partitions(QO_PLANNER *)
void bitset_assign(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:120
#define QO_NODE_ENV(node)
Definition: query_graph.h:380
bool pt_sort_spec_cover_groupby(PARSER_CONTEXT *parser, PT_NODE *sort_list, PT_NODE *group_list, PT_NODE *tree)
PT_POINTER_INFO pointer
Definition: parse_tree.h:3359
int prm_get_integer_value(PARAM_ID prm_id)
PT_MISC_TYPE asc_or_desc
Definition: parse_tree.h:2830
#define ER_GENERIC_ERROR
Definition: error_code.h:49
static double qo_range_selectivity(QO_ENV *env, PT_NODE *pt_expr)
static double qo_between_selectivity(QO_ENV *env, PT_NODE *pt_expr)
#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
QO_NODE * node
static bool qo_validate_index_attr_notnull(QO_ENV *env, QO_INDEX_ENTRY *index_entryp, PT_NODE *col)
#define INDENT_INCR
Definition: query_planner.c:55
PT_NODE * cte_pointer
Definition: parse_tree.h:2132
static QO_PLAN * qo_plan_malloc(QO_ENV *)
struct sort_list * next
Definition: query_list.h:415
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static QO_PLAN_VTBL qo_nl_join_plan_vtbl
unsigned int BITSET
Definition: esql_misc.h:94
static int qo_unset_multi_range_optimization(QO_PLAN *plan, void *arg)
PT_DATA_VALUE data_value
Definition: parse_tree.h:3058
PT_NODE * recursive_part
Definition: parse_tree.h:1978
QO_SEGMENT * index_seg[2]
Definition: query_graph.h:664
static int qo_check_plan_on_info(QO_INFO *, QO_PLAN *)
PT_NODE * flat_entity_list
Definition: parse_tree.h:2140
static int qo_examine_follow(QO_INFO *, QO_TERM *, QO_INFO *, BITSET *, BITSET *)
void qo_plans_stats(FILE *f)
bool qo_is_index_mro_scan(QO_PLAN *plan)
#define qo_worst_walk
Definition: query_planner.c:76
PT_MISC_TYPE all_distinct
Definition: parse_tree.h:2746
unsigned is_desc
bool pt_has_analytic(PARSER_CONTEXT *parser, PT_NODE *node)
static QO_PLAN_COMPARE_RESULT qo_cmp_planvec(QO_PLANVEC *, QO_PLAN *)
int qo_plan_get_cost_fn(const char *plan_name)
PT_HINT_ENUM hint
Definition: parse_tree.h:2707
static void qo_plan_print_projected_segs(QO_PLAN *, FILE *, int)
int intl_identifier_casecmp(const char *str1, const char *str2)
#define BTREE_STATS_PKEYS_NUM
Definition: statistics.h:41
struct qo_plan::@100::@105 follow
static QO_PLAN * qo_sort_new(QO_PLAN *, QO_EQCLASS *, SORT_TYPE)
int orderby_skip
Definition: access_spec.hpp:95
#define QO_NODE_IS_CLASS_HIERARCHY(node)
Definition: query_graph.h:411
static double qo_comp_selectivity(QO_ENV *env, PT_NODE *pt_expr)
static QO_PLAN_COMPARE_RESULT qo_multi_range_opt_plans_cmp(QO_PLAN *, QO_PLAN *)
#define TP_DOMAIN_COLLATION(dom)
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
PARSER_CONTEXT * parser
Definition: query_graph.h:856
static QO_PLAN * qo_find_best_nljoin_inner_plan_on_info(QO_PLAN *, QO_INFO *, JOIN_TYPE, int)
#define DEFAULT_RANGE_SELECTIVITY
bool qo_is_all_unique_index_columns_are_equi_terms(QO_PLAN *plan)
unsigned int Q
int qo_seg_width(QO_SEGMENT *seg)
Definition: query_graph.c:8313
BITSET nodes
Definition: query_graph.h:773
QO_INFO * best_info
bool top_rooted
#define QO_NODE_SUBQUERIES(node)
Definition: query_graph.h:390
QO_INFO ** cp_info
QO_NODE * nodes
Definition: query_graph.h:866
void qo_top_plan_print_json(PARSER_CONTEXT *parser, xasl_node *xasl, PT_NODE *select, QO_PLAN *plan)
#define PT_NAME_INFO_CONSTANT
Definition: parse_tree.h:2562
#define PT_IS_CONST(n)
Definition: parse_tree.h:364
union qo_plan::@100 plan_un
BITSET multi_col_range_segs
Definition: query_graph.h:184
static void qo_plan_fprint(QO_PLAN *, FILE *, int, const char *)
#define TP_DOMAIN_TYPE(dom)
TP_DOMAIN * fi_domain
Definition: class_object.h:502
static void cleanup(int signo)
Definition: broker.c:717
SP_PARSER_CTX * parser
double variable_io_cost
Definition: optimizer.h:112
PT_NODE * arg1
Definition: parse_tree.h:2197
#define NULL
Definition: freelistheap.h:34
bool qo_is_index_covering_scan(QO_PLAN *plan)
static QO_PLAN_VTBL qo_seq_scan_plan_vtbl
int groupby_skip
Definition: access_spec.hpp:96
BITSET all_subqueries
bool use_iscan_descending
struct qo_info * next
unsigned int E
static bool qo_is_sort_limit(QO_PLAN *plan)
#define qo_follow_free
Definition: query_planner.c:80
int nterms
Definition: query_graph.h:895
#define DEFAULT_COMP_SELECTIVITY
static void qo_sort_fprint(QO_PLAN *, FILE *, int)
static json_t * qo_plan_join_print_json(QO_PLAN *plan)
#define QO_NODE_SARGS(node)
Definition: query_graph.h:388
if(extra_options)
Definition: dynamic_load.c:958
int refcount
QO_INFO * worst_info
BITSET projected_segs
#define DEFAULT_IN_SELECTIVITY
BITSET final_segs
bool well_rooted
char * parser_print_tree_list(PARSER_CONTEXT *parser, const PT_NODE *node)
int cleanup_needed
void bitset_intersect(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:200
static QO_PLAN * qo_index_scan_new(QO_INFO *, QO_NODE *, QO_NODE_INDEX_ENTRY *, QO_SCANMETHOD, BITSET *, BITSET *)
#define QO_SEG_FUNC_INDEX(seg)
Definition: query_graph.h:524
static void qo_dump_info(QO_INFO *, FILE *)
const char * plan_string
Definition: query_planner.h:73
unsigned int EQ
double fixed_cpu_cost
Definition: optimizer.h:111
#define QO_SEG_PT_NODE(seg)
Definition: query_graph.h:509
static void qo_plan_compute_subquery_cost(PT_NODE *, double *, double *)
static double qo_not_selectivity(QO_ENV *env, double sel)
QO_PLAN_ULTI_RANGE_OPT_USE multi_range_opt_use
QO_PLAN_VTBL * vtbl
static void qo_plan_sort_print_text(FILE *fp, QO_PLAN *plan, int indent)
JOIN_ORDER_TRY
Definition: query_planner.c:89
#define QO_TERM_MERGEABLE_EDGE
Definition: query_graph.h:743
bool qo_plan_multi_range_opt(QO_PLAN *plan)
static json_t * qo_plan_follow_print_json(QO_PLAN *plan)
static void qo_scan_fprint(QO_PLAN *, FILE *, int)
#define UNEXPECTED_CASE
Definition: optimizer.h:49
PT_QUERY_INFO query
Definition: parse_tree.h:3325
bool qo_is_index_iss_scan(QO_PLAN *plan)
unsigned int N
static int qo_set_orderby_skip(QO_PLAN *plan, void *arg)
#define QO_TERM_CAN_USE_INDEX(t)
Definition: query_graph.h:731
static QO_PLAN_COMPARE_RESULT qo_plan_cmp(QO_PLAN *, QO_PLAN *)
static QO_PLAN * qo_combine_partitions(QO_PLANNER *, BITSET *)
void qo_seg_fprint(QO_SEGMENT *seg, FILE *f)
Definition: query_graph.c:8361
unsigned int T
int pt_is_between_range_op(PT_OP_TYPE op)
#define cmp
Definition: mprec.h:351
DB_BIGINT db_get_bigint(const DB_VALUE *value)
static QO_PLAN * qo_join_new(QO_INFO *, JOIN_TYPE, QO_JOINMETHOD, QO_PLAN *, QO_PLAN *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *)
static QO_PLAN * qo_follow_new(QO_INFO *, QO_PLAN *, QO_TERM *, BITSET *, BITSET *)
static int qo_examine_idx_join(QO_INFO *, JOIN_TYPE, QO_INFO *, QO_INFO *, BITSET *, BITSET *, BITSET *)
QO_PLANVEC best_no_order
static int qo_accumulating_plans
#define QO_NODE_SELECTIVITY(node)
Definition: query_graph.h:389
#define DEFAULT_EXISTS_SELECTIVITY
BITSET terms
Definition: query_graph.h:782
PT_NODE * set
Definition: parse_tree.h:3047
int bitset_next_member(BITSET_ITERATOR *si)
Definition: query_bitset.c:478
static void qo_zero_cost(QO_PLAN *)
#define DEFAULT_BETWEEN_SELECTIVITY
static QO_PLAN * qo_find_best_plan_on_planvec(QO_PLANVEC *, double)
static void qo_clean_planner(QO_PLANNER *)
static void qo_sort_info(QO_PLAN *, FILE *, int)
static void qo_worst_fprint(QO_PLAN *, FILE *, int)
#define QO_ENV_SORT_LIMIT_NODES(env)
Definition: query_graph.h:968
PT_NODE * parser_append_node(PT_NODE *node, PT_NODE *list)
void bitset_remove(BITSET *dst, int x)
Definition: query_bitset.c:158
#define QO_TERM_ENV(t)
Definition: query_graph.h:715
#define QO_NODE_EQCLASSES(node)
Definition: query_graph.h:385
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
#define qo_worst_free
Definition: query_planner.c:81
PT_NODE * entity_spec
Definition: query_graph.h:279
static int qo_generate_sort_limit_plan(QO_ENV *, QO_INFO *, QO_PLAN *)
#define QO_ENTRY_MULTI_COL(entry)
Definition: query_graph.h:187
void parser_free_node(const PARSER_CONTEXT *parser, PT_NODE *node)
Definition: parse_tree.c:869
static QO_PLAN * qo_plan_free_list
unsigned int flags
Definition: class_object.h:459
static void qo_dump_planvec(QO_PLANVEC *, FILE *, int)
static void qo_plans_init(QO_ENV *env)
BITSET subqueries
static int qo_validate_indexes_for_orderby(QO_PLAN *plan, void *arg)
static void qo_init_planvec(QO_PLANVEC *)
#define QO_NODE_TCARD(node)
Definition: query_graph.h:406
#define TP_TYPE_HAS_COLLATION(typeid)
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
struct qo_plan::@100::@102 scan
#define QO_TERM_SELECTIVITY(t)
Definition: query_graph.h:719
static int qo_generate_loose_index_scan(QO_INFO *, QO_NODE *, QO_NODE_INDEX_ENTRY *)
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
static QO_PLAN * qo_search_planner(QO_PLANNER *)
PT_NODE * iscan_sort_list
static void qo_generic_walk(QO_PLAN *, void(*)(QO_PLAN *, void *), void *, void(*)(QO_PLAN *, void *), void *)
#define QO_TERM_NON_IDX_SARG_COLL
Definition: query_graph.h:744
double variable_cpu_cost
float prm_get_float_value(PARAM_ID prm_id)
QO_JOINMETHOD
Definition: query_planner.h:63
const char * fcode_get_lowercase_name(FUNC_TYPE ftype)
static json_t * qo_plan_sort_print_json(QO_PLAN *plan)
QO_ENV * env
Definition: query_graph.h:271
#define MSGCAT_SET_PARSER_SEMANTIC
QO_INFO ** join_info
int db_make_error(DB_VALUE *value, const int errcode)
#define QO_NODE_LOCATION(node)
Definition: query_graph.h:383
static QO_PLAN_VTBL qo_merge_join_plan_vtbl
#define QO_TERM_RANGELIST
Definition: query_graph.h:740
int qo_find_subplan_using_multi_range_opt(QO_PLAN *plan, QO_PLAN **result, int *join_idx)
static QO_PLAN_COMPARE_RESULT qo_plan_iscan_terms_cmp(QO_PLAN *a, QO_PLAN *b)
#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 strlen(s1)
Definition: intl_support.c:43
static int qo_compute_projected_size(QO_PLANNER *, BITSET *)
#define BITSET_MEMBER(s, x)
Definition: query_bitset.h:70
QO_PLAN * qo_planner_search(QO_ENV *env)
QO_ATTR_CUM_STATS cum_stats
Definition: query_graph.h:96
BITSET * seg_equal_terms
Definition: query_graph.h:128
static QO_PLAN_VTBL qo_sort_plan_vtbl
SM_COMPONENT header
Definition: class_object.h:441
PT_NODE * pt_point(PARSER_CONTEXT *parser, const PT_NODE *in_tree)
PT_OP_TYPE
Definition: parse_tree.h:1320
static bool qo_check_groupby_skip_descending(QO_PLAN *plan, PT_NODE *list)
int intl_mbs_ncasecmp(const char *mbs1, const char *mbs2, size_t n)
Definition: intl_support.c:441
BITSET sarged_terms
PT_NODE * connect_by
Definition: parse_tree.h:2689
struct qo_plan::@100::@101 free
bool qo_has_sort_limit_subplan(QO_PLAN *plan)
static bool qo_check_new_best_plan_on_info(QO_INFO *, QO_PLAN *)
#define INDENTED_TITLE_FMT
Definition: query_planner.c:59
bool prm_get_bool_value(PARAM_ID prm_id)
#define QO_TERM_EQCLASS(t)
Definition: query_graph.h:729
static QO_PLAN * qo_cp_new(QO_INFO *, QO_PLAN *, QO_PLAN *, BITSET *, BITSET *)
const char * qo_plan_set_cost_fn(const char *plan_name, int fn)
SM_ATTRIBUTE ** attributes
Definition: class_object.h:533
BITSET nodes
#define SORT_SPEC_FMT(spec)
Definition: query_planner.c:62
static QO_PLAN * qo_find_best_plan_on_info(QO_INFO *, QO_EQCLASS *, double)
int pt_is_single_tuple(PARSER_CONTEXT *parser, PT_NODE *select_node)
static void qo_dump_planner_info(QO_PLANNER *, QO_PARTITION *, FILE *)
bool pt_sort_spec_cover(PT_NODE *cur_list, PT_NODE *new_list)
#define QO_TERM_HEAD(t)
Definition: query_graph.h:721
#define QO_NODE_NAME(node)
Definition: query_graph.h:401
PARSER_VARCHAR * pt_print_node_value(PARSER_CONTEXT *parser, const PT_NODE *val)
static bool qo_check_orderby_skip_descending(QO_PLAN *plan)
static void planner_visit_node(QO_PLANNER *, QO_PARTITION *, PT_HINT_ENUM, QO_NODE *, QO_NODE *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, int)
int join_unit
static void qo_plan_print_analytic_eval(QO_PLAN *, FILE *, int)
void qo_plan_dump(QO_PLAN *plan, FILE *output)
int * seg_idxs
Definition: query_graph.h:122
#define QO_ENV_NODE(env, n)
Definition: query_graph.h:958
static void qo_plan_print_sort_spec_helper(PT_NODE *, bool, FILE *, int)
static int qo_validate_index_for_orderby(QO_ENV *env, QO_NODE_INDEX_ENTRY *ni_entryp)
#define QO_ENV_TERM(env, n)
Definition: query_graph.h:960
#define SM_IS_CONSTRAINT_REVERSE_INDEX_FAMILY(c)
Definition: class_object.h:124
SM_CONSTRAINT_TYPE type
Definition: class_object.h:540
char * parser_print_tree(PARSER_CONTEXT *parser, const PT_NODE *node)
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
QO_SEGMENT * segs
Definition: query_graph.h:865
#define QO_ENV_SEG(env, n)
Definition: query_graph.h:957
#define MAX_NUM_PLAN_TRACE
Definition: parse_tree.h:617
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
#define QO_TERM_NODES(t)
Definition: query_graph.h:717
double cardinality
#define ISCAN_OVERHEAD_FACTOR
Definition: query_planner.c:71
static void qo_nljoin_cost(QO_PLAN *)
PT_NODE * list
Definition: parse_tree.h:2685
static int qo_generate_index_scan(QO_INFO *, QO_NODE *, QO_NODE_INDEX_ENTRY *, int)
static void qo_follow_walk(QO_PLAN *, void(*)(QO_PLAN *, void *), void *, void(*)(QO_PLAN *, void *), void *)
QO_PLAN_COMPARE_RESULT
Definition: query_planner.h:83
PT_OP_TYPE op
Definition: parse_tree.h:2200
static QO_PLAN_COMPARE_RESULT qo_check_planvec(QO_PLANVEC *, QO_PLAN *)
struct tp_domain * next
Definition: object_domain.h:74
#define QO_PARTITION_DEPENDENCIES(p)
Definition: query_graph.h:830
PARSER_VARCHAR *(* PT_PRINT_VALUE_FUNC)(PARSER_CONTEXT *parser, const PT_NODE *val)
Definition: parse_tree.h:1691
#define QO_TERM_SEGS(t)
Definition: query_graph.h:718
const char * name
Definition: class_object.h:385
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
QO_EQCLASS * eqclass
static QO_PLAN * qo_plan_order_by(QO_PLAN *, QO_EQCLASS *)
QO_NODE * lookup_node(PT_NODE *attr, QO_ENV *env, PT_NODE **entity)
Definition: query_graph.c:1357
BITSET eqclasses
#define PT_IS_SET_TYPE(n)
Definition: parse_tree.h:336
#define QO_NODE_IDX(node)
Definition: query_graph.h:392
PT_NODE * orderby_for
Definition: parse_tree.h:2770
#define pt_is_function(n)
Definition: parse_tree.h:262
PT_PLAN_TRACE_INFO plan_trace[MAX_NUM_PLAN_TRACE]
Definition: parse_tree.h:3596
static QO_PLAN_VTBL qo_idx_join_plan_vtbl
analytic_list_node * next
int bitset_cardinality(const BITSET *s)
Definition: query_bitset.c:393
static void qo_plan_print_subqueries(QO_PLAN *, FILE *, int)
void pt_to_pos_descr(PARSER_CONTEXT *parser, QFILE_TUPLE_VALUE_POSITION *pos_p, PT_NODE *node, PT_NODE *root, PT_NODE **referred_node)
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
double variable_io_cost
#define QO_NODE_ENTITY_SPEC(node)
Definition: query_graph.h:381
static void qo_sscan_cost(QO_PLAN *)
#define PT_IS_EXPR_NODE_WITH_OPERATOR(n, op_type)
Definition: parse_tree.h:464
QO_SEGMENT * lookup_seg(QO_NODE *head, PT_NODE *name, QO_ENV *env)
Definition: query_graph.c:1558
#define QO_PARTITION_NODES(p)
Definition: query_graph.h:828
int bitset_first_member(const BITSET *s)
Definition: query_bitset.c:514
#define qo_plan_release(p)
static double planner_nodeset_join_cost(QO_PLANNER *, BITSET *)
static int qo_index_cardinality(QO_ENV *env, PT_NODE *attr)
#define QO_NODE_INDEXES(node)
Definition: query_graph.h:394
#define QO_NODE_OUTER_DEP_SET(node)
Definition: query_graph.h:397
void qo_planner_free(QO_PLANNER *planner)
static int infos_allocated
Definition: query_planner.c:94
#define QO_NODE_SEGS(node)
Definition: query_graph.h:391
QO_ENV * env
void bitset_add(BITSET *dst, int x)
Definition: query_bitset.c:138
QO_PLANTYPE plan_type
int pt_length_of_list(const PT_NODE *list)
struct parser_node::@132 flag
Definition: query_graph.h:99
int force
Definition: query_graph.h:110
bool dump_enable
Definition: query_graph.h:941
QO_INDEX_ENTRY * head
Definition: query_graph.h:212
PT_SELECT_INFO select
Definition: parse_tree.h:2781
static void qo_join_fprint(QO_PLAN *, FILE *, int)
#define QO_NODE_SORT_LIMIT_CANDIDATE(node)
Definition: query_graph.h:409
struct json_t * json_plan
Definition: parse_tree.h:3523
static int qo_next_tmpfile
cubxasl::analytic_eval_type * analytic_eval_list
void qo_node_fprint(QO_NODE *node, FILE *f)
Definition: query_graph.c:8162
QO_PLANVEC * planvec
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)
QO_NODE * tail
Definition: query_graph.h:683
#define PT_EXPR_INFO_IS_FLAGED(e, f)
Definition: parse_tree.h:2238
void(* default_cost)(QO_PLAN *)
Definition: query_planner.h:78
void qo_set_cost(DB_OBJECT *target, DB_VALUE *result, DB_VALUE *plan, DB_VALUE *cost)
double variable_cpu_cost
Definition: optimizer.h:112
BITSET * seg_other_terms
Definition: query_graph.h:131
#define QO_PARTITION_EDGES(p)
Definition: query_graph.h:829
static void qo_plan_follow_print_text(FILE *fp, QO_PLAN *plan, int indent)
QO_TERM * term
#define FUDGE_FACTOR
Definition: query_planner.c:70
#define QO_TERM_EQUAL_OP
Definition: query_graph.h:739
#define QO_SEG_INFO(seg)
Definition: query_graph.h:518
static void qo_sort_cost(QO_PLAN *)
const char ** p
Definition: dynamic_load.c:945
#define DEFAULT_NULL_SELECTIVITY
int col_num
Definition: query_graph.h:113
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
int n
Definition: query_graph.h:218
#define QO_TERM_JOIN_TYPE(t)
Definition: query_graph.h:733
double fixed_io_cost
#define DB_UINT32_MAX
Definition: dbtype_def.h:635
static int qo_examine_nl_join(QO_INFO *, JOIN_TYPE, QO_INFO *, QO_INFO *, BITSET *, BITSET *, BITSET *, BITSET *, BITSET *, int, BITSET *)
static int qo_walk_plan_tree(QO_PLAN *plan, QO_WALK_FUNCTION f, void *arg)
QO_ENV * env
static void qo_mjoin_cost(QO_PLAN *)
int Nnodes
Definition: query_graph.h:893
#define QO_EQCLASS_SEGS(e)
Definition: query_graph.h:556
static void qo_info_nodes_init(QO_ENV *)
#define TP_DOMAIN_COLLATION_FLAG(dom)
PT_NODE * derived_table
Definition: parse_tree.h:2134
int nnodes
Definition: query_graph.h:893
static int qo_plans_malloced
Definition: query_planner.c:99
FILE * port_open_memstream(char **ptr, size_t *sizeloc)
Definition: porting.c:2198
BITSET fake_terms
Definition: query_graph.h:935
int * multi_col_segs
Definition: query_graph.h:703
void qo_info_stats(FILE *f)
int multi_col_cnt
Definition: query_graph.h:704
#define QO_INFO_INDEX(_M_offset, _bitset)
Definition: query_planner.c:83
static void qo_join_free(QO_PLAN *)