CUBRID Engine  latest
query_graph.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_graph.c - builds a query graph from a parse tree and
21  * transforms the tree by unfolding path expressions.
22  */
23 
24 #ident "$Id$"
25 
26 #include "config.h"
27 
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <math.h>
33 #include <assert.h>
34 #if !defined(WINDOWS)
35 #include <values.h>
36 #endif /* !WINDOWS */
37 
38 #include "parser.h"
39 #include "error_code.h"
40 #include "error_manager.h"
41 #include "object_primitive.h"
42 #include "object_representation.h"
43 #include "optimizer.h"
44 #include "query_graph.h"
45 #include "query_planner.h"
46 #include "schema_manager.h"
47 #include "statistics.h"
48 #include "system_parameter.h"
49 #include "environment_variable.h"
50 #include "xasl_generation.h"
51 #include "query_list.h"
52 #include "db.h"
53 #include "system_parameter.h"
54 #include "memory_alloc.h"
55 #include "environment_variable.h"
56 #include "util_func.h"
57 #include "locator_cl.h"
58 #include "object_domain.h"
59 #include "network_interface_cl.h"
60 #include "dbtype.h"
61 #include "xasl.h"
62 
63 /* figure out how many bytes a QO_USING_INDEX struct with n entries requires */
64 #define SIZEOF_USING_INDEX(n) \
65  (sizeof(QO_USING_INDEX) + (((n)-1) * sizeof(QO_USING_INDEX_ENTRY)))
66 
67 /* any number that won't overlap PT_MISC_TYPE */
68 #define PREDICATE_TERM -2
69 
70 #define RANK_DEFAULT 0 /* default */
71 #define RANK_NAME RANK_DEFAULT /* name -- use default */
72 #define RANK_VALUE RANK_DEFAULT /* value -- use default */
73 #define RANK_EXPR_LIGHT 1 /* Group 1 */
74 #define RANK_EXPR_MEDIUM 2 /* Group 2 */
75 #define RANK_EXPR_HEAVY 3 /* Group 3 */
76 #define RANK_EXPR_FUNCTION 4 /* agg function, set */
77 #define RANK_QUERY 8 /* subquery */
78 
79 /* log2(sizeof(POINTER)) */
80 #if __WORDSIZE == 64
81 /* log2(8) */
82 #define LOG2_SIZEOF_POINTER 3
83 #else
84 /* log2(4) */
85 #define LOG2_SIZEOF_POINTER 2
86 #endif
87 
88 /*
89  * Figure out how many bytes a QO_INDEX struct with n entries requires.
90  */
91 #define SIZEOF_INDEX(n) \
92  (sizeof(QO_INDEX) + (((n)-1)* sizeof(QO_INDEX_ENTRY)))
93 
94 /*
95  * Figure out how many bytes a QO_CLASS_INFO struct with n entries requires.
96  */
97 #define SIZEOF_CLASS_INFO(n) \
98  (sizeof(QO_CLASS_INFO) + (((n)-1) * sizeof(QO_CLASS_INFO_ENTRY)))
99 
100 /*
101  * Figure out how many bytes a pkeys[] struct with n entries requires.
102  */
103 #define SIZEOF_ATTR_CUM_STATS_PKEYS(n) \
104  ((n) * sizeof(int))
105 
106 #define NOMINAL_HEAP_SIZE(class) 200 /* pages */
107 #define NOMINAL_OBJECT_SIZE(class) 64 /* bytes */
108 
109 /* Figure out how many bytes a QO_NODE_INDEX struct with n entries requires. */
110 #define SIZEOF_NODE_INDEX(n) \
111  (sizeof(QO_NODE_INDEX) + (((n)-1)* sizeof(QO_NODE_INDEX_ENTRY)))
112 
113 #define EXCHANGE_BUILDER(type,e0,e1) \
114  do { type _tmp = e0; e0 = e1; e1 = _tmp; } while (0)
115 
116 #define TERMCLASS_EXCHANGE(e0,e1) EXCHANGE_BUILDER(QO_TERMCLASS,e0,e1)
117 #define DOUBLE_EXCHANGE(e0,e1) EXCHANGE_BUILDER(double,e0,e1)
118 #define PT_NODE_EXCHANGE(e0,e1) EXCHANGE_BUILDER(PT_NODE *,e0,e1)
119 #define INT_EXCHANGE(e0,e1) EXCHANGE_BUILDER(int,e0,e1)
120 #define SEGMENTPTR_EXCHANGE(e0,e1) EXCHANGE_BUILDER(QO_SEGMENT *,e0,e1)
121 #define NODEPTR_EXCHANGE(e0,e1) EXCHANGE_BUILDER(QO_NODE *,e0,e1)
122 #define EQCLASSPTR_EXCHANGE(e0,e1) EXCHANGE_BUILDER(QO_EQCLASS *,e0,e1)
123 #define BOOL_EXCHANGE(e0,e1) EXCHANGE_BUILDER(bool,e0,e1)
124 #define JOIN_TYPE_EXCHANGE(e0,e1) EXCHANGE_BUILDER(JOIN_TYPE,e0,e1)
125 #define FLAG_EXCHANGE(e0,e1) EXCHANGE_BUILDER(int,e0,e1)
126 #define INT_PTR_EXCHANGE(e0,e1) EXCHANGE_BUILDER(int *,e0,e1)
127 
128 #define BISET_EXCHANGE(s0,s1) \
129  do { \
130  BITSET tmp; \
131  BITSET_MOVE(tmp, s0); \
132  BITSET_MOVE(s0, s1); \
133  BITSET_MOVE(s1, tmp); \
134  } while (0)
135 
136 #define PUT_FLAG(cond, flag) \
137  do { \
138  if (cond) { \
139  if (extra_info++) { \
140  fputs(flag, f); \
141  } else { \
142  fputs(" (", f); \
143  fputs(flag, f); \
144  } \
145  } \
146  } while (0)
147 typedef enum
148 {
149  QO_BUILD_ENTITY = 0x01, /* 0000 0001 */
150  QO_BUILD_PATH = 0x02 /* 0000 0010 */
152 
153 typedef struct walk_info WALK_INFO;
154 struct walk_info
155 {
158 };
159 
160 double QO_INFINITY = 0.0;
161 
163 static QO_NODE *qo_add_node (PT_NODE * entity, QO_ENV * env);
164 static QO_SEGMENT *qo_insert_segment (QO_NODE * head, QO_NODE * tail, PT_NODE * node, QO_ENV * env,
165  const char *expr_str);
166 static QO_SEGMENT *qo_join_segment (QO_NODE * head, QO_NODE * tail, PT_NODE * name, QO_ENV * env);
167 static PT_NODE *qo_add_final_segment (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
168 static QO_TERM *qo_add_term (PT_NODE * conjunct, int term_type, QO_ENV * env);
169 static void qo_add_dep_term (QO_NODE * derived_node, BITSET * depend_nodes, BITSET * depend_segs, QO_ENV * env);
170 static QO_TERM *qo_add_dummy_join_term (QO_ENV * env, QO_NODE * p_node, QO_NODE * on_node);
171 static void qo_analyze_term (QO_TERM * term, int term_type);
172 static PT_NODE *set_seg_expr (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
173 static void set_seg_node (PT_NODE * attr, QO_ENV * env, BITSET * bitset);
174 static QO_ENV *qo_env_init (PARSER_CONTEXT * parser, PT_NODE * query);
175 static bool qo_validate (QO_ENV * env);
176 static PT_NODE *build_query_graph (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
177 static PT_NODE *build_query_graph_post (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
179  int *continue_walk);
180 static QO_NODE *build_graph_for_entity (QO_ENV * env, PT_NODE * entity, QO_BUILD_STATUS status);
181 static PT_NODE *graph_size_select (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
182 static void graph_size_for_entity (QO_ENV * env, PT_NODE * entity);
183 static bool is_dependent_table (PT_NODE * entity);
184 static void get_term_subqueries (QO_ENV * env, QO_TERM * term);
185 static void get_term_rank (QO_ENV * env, QO_TERM * term);
186 static PT_NODE *check_subquery_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
187 static bool is_local_name (QO_ENV * env, PT_NODE * expr);
188 static void get_local_subqueries (QO_ENV * env, PT_NODE * tree);
189 static void get_rank (QO_ENV * env);
190 static PT_NODE *get_referenced_attrs (PT_NODE * entity);
191 static bool expr_is_mergable (PT_NODE * pt_expr);
192 static bool qo_is_equi_join_term (QO_TERM * term);
193 static void add_hint (QO_ENV * env, PT_NODE * tree);
194 static void add_using_index (QO_ENV * env, PT_NODE * using_index);
195 static int get_opcode_rank (PT_OP_TYPE opcode);
196 static int get_expr_fcode_rank (FUNC_TYPE fcode);
197 static int get_operand_rank (PT_NODE * node);
198 static int count_classes (PT_NODE * p);
200 static int qo_data_compare (DB_DATA * data1, DB_DATA * data2, DB_TYPE type);
201 static void qo_estimate_statistics (MOP class_mop, CLASS_STATS *);
202 
203 static void qo_node_free (QO_NODE *);
204 static void qo_node_dump (QO_NODE *, FILE *);
205 static void qo_node_add_sarg (QO_NODE *, QO_TERM *);
206 
207 static void qo_seg_free (QO_SEGMENT *);
208 
209 static QO_EQCLASS *qo_eqclass_new (QO_ENV *);
210 static void qo_eqclass_free (QO_EQCLASS *);
211 static void qo_eqclass_add (QO_EQCLASS *, QO_SEGMENT *);
212 static void qo_eqclass_dump (QO_EQCLASS *, FILE *);
213 
214 static void qo_term_free (QO_TERM *);
215 static void qo_term_dump (QO_TERM *, FILE *);
216 static void qo_subquery_dump (QO_ENV *, QO_SUBQUERY *, FILE *);
217 static void qo_subquery_free (QO_SUBQUERY *);
218 
219 static void qo_partition_init (QO_ENV *, QO_PARTITION *, int);
220 static void qo_partition_free (QO_PARTITION *);
221 static void qo_partition_dump (QO_PARTITION *, FILE *);
222 static void qo_find_index_terms (QO_ENV * env, BITSET * segsp, QO_INDEX_ENTRY * index_entry);
223 static void qo_find_index_seg_terms (QO_ENV * env, QO_INDEX_ENTRY * index_entry, int idx, BITSET * index_segsp);
224 static bool qo_find_index_segs (QO_ENV *, SM_CLASS_CONSTRAINT *, QO_NODE *, int *, int, int *, BITSET *);
225 static bool qo_is_coverage_index (QO_ENV * env, QO_NODE * nodep, QO_INDEX_ENTRY * index_entry);
226 static void qo_find_node_indexes (QO_ENV *, QO_NODE *);
227 static int is_equivalent_indexes (QO_INDEX_ENTRY * index1, QO_INDEX_ENTRY * index2);
228 static int qo_find_matching_index (QO_INDEX_ENTRY * index_entry, QO_INDEX * class_indexes);
229 static QO_INDEX_ENTRY *is_index_compatible (QO_CLASS_INFO * class_info, int n, QO_INDEX_ENTRY * index_entry);
230 
231 static void qo_discover_sort_limit_nodes (QO_ENV * env);
232 static void qo_equivalence (QO_SEGMENT *, QO_SEGMENT *);
233 static void qo_seg_nodes (QO_ENV *, BITSET *, BITSET *);
234 static QO_ENV *qo_env_new (PARSER_CONTEXT *, PT_NODE *);
235 static void qo_discover_partitions (QO_ENV *);
236 static void qo_discover_indexes (QO_ENV *);
237 static void qo_assign_eq_classes (QO_ENV *);
238 static void qo_discover_edges (QO_ENV *);
239 static void qo_classify_outerjoin_terms (QO_ENV *);
240 static void qo_term_clear (QO_ENV *, int);
241 static void qo_seg_clear (QO_ENV *, int);
242 static void qo_node_clear (QO_ENV *, int);
243 static void qo_get_index_info (QO_ENV * env, QO_NODE * node);
244 static void qo_free_index (QO_ENV * env, QO_INDEX *);
245 static QO_INDEX *qo_alloc_index (QO_ENV * env, int);
246 static void qo_free_node_index_info (QO_ENV * env, QO_NODE_INDEX * node_indexp);
247 static void qo_free_attr_info (QO_ENV * env, QO_ATTR_INFO * info);
249 static QO_ATTR_INFO *qo_get_attr_info_func_index (QO_ENV * env, QO_SEGMENT * seg, const char *expr_str);
250 static void qo_free_class_info (QO_ENV * env, QO_CLASS_INFO *);
251 static QO_CLASS_INFO *qo_get_class_info (QO_ENV * env, QO_NODE * node);
253 static void qo_env_dump (QO_ENV *, FILE *);
254 static int qo_get_ils_prefix_length (QO_ENV * env, QO_NODE * nodep, QO_INDEX_ENTRY * index_entry);
255 static bool qo_is_iss_index (QO_ENV * env, QO_NODE * nodep, QO_INDEX_ENTRY * index_entry);
256 static void qo_discover_sort_limit_join_nodes (QO_ENV * env, QO_NODE * nodep, BITSET * order_nodes, BITSET * dep_nodes);
257 static bool qo_is_pk_fk_full_join (QO_ENV * env, QO_NODE * fk_node, QO_NODE * pk_node);
258 static bool qo_is_non_mvcc_class_with_index (QO_CLASS_INFO_ENTRY * class_entry_p);
259 
260 /*
261  * qo_get_optimization_param () - Return the current value of some (global)
262  * optimization parameter
263  * return: int
264  * retval(in): pointer to area to receive info
265  * param(in): what parameter to retrieve
266  * ...(in): parameter-specific parameters
267  */
268 void
269 qo_get_optimization_param (void *retval, QO_PARAM param, ...)
270 {
271  char *buf;
272  va_list args;
273 
274  va_start (args, param);
275 
276  switch (param)
277  {
278  case QO_PARAM_LEVEL:
280  break;
281  case QO_PARAM_COST:
282  buf = (char *) retval;
283  buf[0] = (char) qo_plan_get_cost_fn (va_arg (args, char *));
284  buf[1] = '\0';
285  break;
286  }
287 
288  va_end (args);
289 }
290 
291 /*
292  * qo_need_skip_execution (void) - check execution level and return skip or not
293  *
294  * return: bool
295  */
296 bool
298 {
299  int level;
300 
302 
303  return level & 0x02;
304 }
305 
306 /*
307  * qo_set_optimization_param () - Return the old value of some (global)
308  * optimization param, and set the global
309  * param to the new value
310  * return: int
311  * retval(in): pointer to area to receive info about old value
312  * param(in): what parameter to retrieve
313  * ...(in): parameter-specific parameters
314  */
315 void
316 qo_set_optimization_param (void *retval, QO_PARAM param, ...)
317 {
318  va_list args;
319  va_start (args, param);
320 
321  switch (param)
322  {
323  case QO_PARAM_LEVEL:
324  if (retval)
325  {
327  }
328  prm_set_integer_value (PRM_ID_OPTIMIZATION_LEVEL, va_arg (args, int));
329  break;
330 
331  case QO_PARAM_COST:
332  {
333  const char *plan_name;
334  int cost_fn;
335 
336  plan_name = va_arg (args, char *);
337  cost_fn = va_arg (args, int);
338  plan_name = qo_plan_set_cost_fn (plan_name, cost_fn);
339  if (retval)
340  {
341  *(const char **) retval = plan_name;
342  }
343  break;
344  }
345  }
346 
347  va_end (args);
348 }
349 
350 /*
351  * qo_optimize_query () - optimize a single select statement, skip nested
352  * selects since embedded selects are optimized first
353  * return: void
354  * parser(in): parser environment
355  * tree(in): select tree to optimize
356  */
357 QO_PLAN *
359 {
360  QO_ENV *env;
361  int level;
362 
363  /*
364  * Give up right away if the optimizer has been turned off in the
365  * user's cubrid.conf file or somewhere else.
366  */
368  if (!OPTIMIZATION_ENABLED (level))
369  {
370  return NULL;
371  }
372 
373  /* if its not a select, we're not interested, also if it is merge we give up. */
374  if (tree->node_type != PT_SELECT)
375  {
376  return NULL;
377  }
378 
379  env = qo_env_init (parser, tree);
380  if (env == NULL)
381  {
382  /* we can't optimize, so bail out */
383  return NULL;
384  }
385 
386  switch (setjmp (env->catch_))
387  {
388  case 0:
389  /*
390  * The return here is ok; we'll take care of freeing the env structure later, when qo_plan_discard is called.
391  * In fact, if we free it now, the plan pointer we're about to return will be worthless.
392  */
393  return qo_optimize_helper (env);
394  case 1:
395  /*
396  * Out of memory during optimization. malloc() has already done an er_set().
397  */
398  break;
399  case 2:
400  /*
401  * Failed some optimizer assertion. QO_ABORT() has already done an er_set().
402  */
403  break;
404  default:
405  /*
406  * No clue.
407  */
409  break;
410  }
411 
412  /*
413  * If we get here, an error of some sort occurred, and we need to tear down everything and get out.
414  */
415 #if defined(CUBRID_DEBUG)
416  fprintf (stderr, "*** optimizer aborting ***\n");
417 #endif /* CUBRID_DEBUG */
418  qo_env_free (env);
419 
420  return NULL;
421 }
422 
423 /*
424  * qo_optimize_helper () -
425  * return:
426  * env(in):
427  */
428 static QO_PLAN *
430 {
432  PT_NODE *tree;
433  PT_NODE *spec, *conj, *next;
434  QO_ENV *local_env; /* So we can safely take its address */
435  QO_PLAN *plan;
436  int level;
437  QO_TERM *term;
438  QO_NODE *node, *p_node;
439  BITSET nodeset;
440  int n;
441 
442  parser = QO_ENV_PARSER (env);
443  tree = QO_ENV_PT_TREE (env);
444  local_env = env;
445 
446  (void) parser_walk_tree (parser, tree, build_query_graph, &local_env, build_query_graph_post, &local_env);
447  (void) parser_walk_tree (parser, tree, build_query_graph_function_index, &local_env, NULL, NULL);
448  (void) add_hint (env, tree);
450 
451  /* add dep term */
452  {
453  BITSET dependencies;
454  BITSET antecedents;
455 
456  bitset_init (&dependencies, env);
457  bitset_init (&antecedents, env);
458 
459  for (n = 0; n < env->nnodes; n++)
460  {
461  node = QO_ENV_NODE (env, n);
462  spec = QO_NODE_ENTITY_SPEC (node);
463 
464  /*
465  * Set up the dependencies; it's simplest just to assume that a
466  * dependent table depends on everything that precedes it.
467  */
468  if (is_dependent_table (spec))
469  {
470  /*
471  * Find all of the segments (i.e., attributes) referenced in
472  * the derived table expression, and then find the set of
473  * nodes that underly those segments. This node can't be
474  * added to a join plan before all of those nodes have, so we
475  * establish some artificial dependency links that force the
476  * planner to maintain that constraint.
477  */
478 
479  BITSET_CLEAR (dependencies);
480  BITSET_CLEAR (antecedents);
481 
482  qo_expr_segs (env, spec->info.spec.derived_table, &dependencies);
483 
484  if (!bitset_is_empty (&dependencies))
485  {
486  qo_seg_nodes (env, &dependencies, &antecedents);
487  qo_add_dep_term (node, &antecedents, &dependencies, env);
488  }
489  }
490  } /* for (n = 0 ...) */
491 
492  bitset_delset (&dependencies);
493  bitset_delset (&antecedents);
494  }
495 
496  bitset_init (&nodeset, env);
497 
498  /* add term in the ON clause */
499  for (spec = tree->info.query.q.select.from; spec; spec = spec->next)
500  {
501  if (spec->node_type == PT_SPEC && spec->info.spec.on_cond)
502  {
503  for (conj = spec->info.spec.on_cond; conj; conj = conj->next)
504  {
505  next = conj->next;
506  conj->next = NULL;
507 
508  /* The conjuct could be PT_VALUE(0) if an explicit join condition was derived/transformed to the
509  * always-false search condition when type checking, expression evaluation or query rewrite
510  * transformation. We should sustained it for correct join plan. It's different from ordinary WHERE
511  * search condition. If an always-false search condition was found in WHERE clause, they did not call
512  * query optimization and return no result to the user unless the query doesn't have aggregation.
513  */
514 
515  term = qo_add_term (conj, PREDICATE_TERM, env);
516 
517  if (QO_TERM_CLASS (term) == QO_TC_JOIN)
518  {
519  QO_ASSERT (env, QO_ON_COND_TERM (term));
520 
521  n = QO_TERM_LOCATION (term);
522  if (QO_NODE_LOCATION (QO_TERM_HEAD (term)) == n - 1 && QO_NODE_LOCATION (QO_TERM_TAIL (term)) == n)
523  {
524  bitset_add (&nodeset, QO_NODE_IDX (QO_TERM_TAIL (term)));
525  }
526  }
527 
528  conj->next = next;
529  }
530  }
531  }
532 
533  /* add term in the WHERE clause */
534  for (conj = tree->info.query.q.select.where; conj; conj = conj->next)
535  {
536  next = conj->next;
537  conj->next = NULL;
538 
539  term = qo_add_term (conj, PREDICATE_TERM, env);
540  conj->next = next;
541  }
542 
543  for (n = 1; n < env->nnodes; n++)
544  {
545  node = QO_ENV_NODE (env, n);
546 
547  /* check join-edge for explicit join */
549  && !BITSET_MEMBER (nodeset, n))
550  {
551  p_node = QO_ENV_NODE (env, n - 1);
552  (void) qo_add_dummy_join_term (env, p_node, node);
553  /* Is it safe to pass node[n-1] as head node? Yes, because the sequence of QO_NODEs corresponds to the
554  * sequence of PT_SPEC list
555  */
556  }
557  }
558 
559  /* classify terms for outer join */
561 
562  bitset_delset (&nodeset);
563 
564  (void) parser_walk_tree (parser, tree->info.query.q.select.list, qo_add_final_segment, &local_env, pt_continue_walk,
565  NULL);
566  (void) parser_walk_tree (parser, tree->info.query.q.select.group_by, qo_add_final_segment, &local_env,
568  (void) parser_walk_tree (parser, tree->info.query.q.select.having, qo_add_final_segment, &local_env, pt_continue_walk,
569  NULL);
570 
571  /* it's necessary to find segments for nodes in predicates that are evaluated after joins, in order to be available
572  * in intermediary output lists
573  */
575  {
576  (void) parser_walk_tree (parser, tree->info.query.q.select.start_with, qo_add_final_segment, &local_env,
578  (void) parser_walk_tree (parser, tree->info.query.q.select.connect_by, qo_add_final_segment, &local_env,
580  (void) parser_walk_tree (parser, tree->info.query.q.select.after_cb_filter, qo_add_final_segment, &local_env,
582  }
583 
584  /* finish the rest of the opt structures */
585  qo_discover_edges (env);
586 
587  /* Don't do these things until *after* qo_discover_edges(); that function may rearrange the QO_TERM structures that
588  * were discovered during the earlier phases, and anyone who grabs the idx of one of the terms (or even a pointer to
589  * one) will be pointing to the wrong term after they're rearranged.
590  */
591  qo_assign_eq_classes (env);
592 
593  get_local_subqueries (env, tree);
594  get_rank (env);
595  qo_discover_indexes (env);
598  /* now optimize */
599 
600  plan = qo_planner_search (env);
601 
602  /* need to set est_card for the select in case it is a subquery */
603 
604  /*
605  * Print out any needed post-optimization info. Leave a way to find
606  * out about environment info if we aren't able to produce a plan.
607  * If this happens in the field at least we'll be able to glean some info.
608  */
610  if (plan && PLAN_DUMP_ENABLED (level) && DETAILED_DUMP (level) && env->plan_dump_enabled)
611  {
613  }
614  if (plan == NULL)
615  {
616  qo_env_free (env);
617  }
618 
619  return plan;
620 }
621 
622 /*
623  * qo_env_init () - initialize an optimizer environment
624  * return: QO_ENV *
625  * parser(in): parser environment
626  * query(in): A pointer to a PT_NODE structure that describes the query to be optimized
627  */
628 static QO_ENV *
630 {
631  QO_ENV *env;
632  int i;
633  size_t size;
634 
635  if (query == NULL)
636  {
637  return NULL;
638  }
639 
640  env = qo_env_new (parser, query);
641  if (env == NULL)
642  {
643  return NULL;
644  }
645 
646  if (qo_validate (env))
647  {
648  goto error;
649  }
650 
651  env->segs = NULL;
652  if (env->nsegs > 0)
653  {
654  size = sizeof (QO_SEGMENT) * env->nsegs;
655  env->segs = (QO_SEGMENT *) malloc (size);
656  if (env->segs == NULL)
657  {
659  goto error;
660  }
661  }
662 
663  env->nodes = NULL;
664  if (env->nnodes > 0)
665  {
666  size = sizeof (QO_NODE) * env->nnodes;
667  env->nodes = (QO_NODE *) malloc (size);
668  if (env->nodes == NULL)
669  {
671  goto error;
672  }
673  }
674 
675  env->terms = NULL;
676  if (env->nterms > 0)
677  {
678  size = sizeof (QO_TERM) * env->nterms;
679  env->terms = (QO_TERM *) malloc (size);
680  if (env->terms == NULL)
681  {
683  goto error;
684  }
685  }
686 
687  env->eqclasses = NULL;
688  size = sizeof (QO_EQCLASS) * (MAX (env->nnodes, env->nterms) + env->nsegs);
689  if (size > 0)
690  {
691  env->eqclasses = (QO_EQCLASS *) malloc (size);
692  if (env->eqclasses == NULL)
693  {
695  goto error;
696  }
697  }
698 
699  env->partitions = NULL;
700  if (env->nnodes > 0)
701  {
702  size = sizeof (QO_PARTITION) * env->nnodes;
703  env->partitions = (QO_PARTITION *) malloc (size);
704  if (env->partitions == NULL)
705  {
707  goto error;
708  }
709  }
710 
711  for (i = 0; i < env->nsegs; ++i)
712  {
713  qo_seg_clear (env, i);
714  }
715 
716  for (i = 0; i < env->nnodes; ++i)
717  {
718  qo_node_clear (env, i);
719  }
720 
721  for (i = 0; i < env->nterms; ++i)
722  {
723  qo_term_clear (env, i);
724  }
725 
726  env->Nnodes = env->nnodes;
727  env->Nsegs = env->nsegs;
728  env->Nterms = env->nterms;
729  env->Neqclasses = MAX (env->nnodes, env->nterms) + env->nsegs;
730 
731  env->nnodes = 0;
732  env->nsegs = 0;
733  env->nterms = 0;
734  env->neqclasses = 0;
735 
737 
738  return env;
739 
740 error:
741  qo_env_free (env);
742  return NULL;
743 }
744 
745 /*
746  * qo_validate () -
747  * return: true iff we reject the query, false otherwise
748  * env(in): A pointer to the environment we are working on
749  *
750  * Note: Determine whether this is a problem that we're willing to
751  * work on. Right now, this means enforcing the constraints
752  * about maximum set sizes. We're not very happy with
753  * set-valued attributes, class attributes, or shared attributes
754  * either, but these are temporary problems and are detected
755  * elsewhere.
756  */
757 static bool
759 {
760 #define OPTIMIZATION_LIMIT 64
761  PT_NODE *tree, *spec, *conj;
762 
763  tree = QO_ENV_PT_TREE (env);
764 
765  /* find out how many nodes and segments will be required for the query graph. */
766  (void) parser_walk_tree (env->parser, tree, graph_size_select, &env, pt_continue_walk, NULL);
767 
768  /* count the number of conjuncts in the ON clause */
769  for (spec = tree->info.query.q.select.from; spec; spec = spec->next)
770  {
771  if (spec->node_type == PT_SPEC && spec->info.spec.on_cond)
772  {
773  for (conj = spec->info.spec.on_cond; conj; conj = conj->next)
774  {
775  if (conj->node_type != PT_EXPR && conj->node_type != PT_VALUE)
776  { /* for outer join */
777  env->bail_out = 1;
778  return true;
779  }
780  env->nterms++;
781  }
782  }
783  }
784 
785  /* count the number of conjuncts in the WHERE clause */
786  for (conj = tree->info.query.q.select.where; conj; conj = conj->next)
787  {
788  if (conj->node_type != PT_EXPR && conj->node_type != PT_VALUE /* is a false conjunct */ )
789  {
790  env->bail_out = 1;
791  return true;
792  }
793  env->nterms++;
794  }
795 
796  if (env->nnodes > OPTIMIZATION_LIMIT)
797  {
798  return true;
799  }
800 
801  return false;
802 
803 }
804 
805 /*
806  * graph_size_select () - This pre walk function will examine the current
807  * select and determine the graph size needed for it
808  * return: PT_NODE *
809  * parser(in): parser environment
810  * tree(in): tree to walk
811  * arg(in):
812  * continue_walk(in):
813  */
814 static PT_NODE *
815 graph_size_select (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
816 {
817  QO_ENV *env = *(QO_ENV **) arg;
818 
819  *continue_walk = PT_CONTINUE_WALK;
820 
821  /*
822  * skip nested selects, they've already been counted
823  */
824  if ((tree->node_type == PT_SELECT) && (tree != env->pt_tree))
825  {
826  *continue_walk = PT_LIST_WALK;
827  return tree;
828  }
829 
830  /* if its not an entity_spec, we're not interested */
831  if (tree->node_type != PT_SPEC)
832  {
833  return tree;
834  }
835 
836  (void) graph_size_for_entity (env, tree);
837 
838  /* don't visit leaves of the entity, graph_size_for_entity already did */
839  *continue_walk = PT_LIST_WALK;
840 
841  return tree;
842 
843 }
844 
845 /*
846  * graph_size_for_entity () - This routine will size the graph for the entity
847  * return: nothing
848  * env(in): optimizer environment
849  * entity(in): entity to build the graph for
850  *
851  * Note: This routine mimics build_graph_for_entity. It is IMPORTANT that
852  * they remain in sync or else we might not allocate enough space for
853  * the graph arrays resulting in memory corruption.
854  */
855 static void
857 {
858  PT_NODE *name, *conj, *next_entity;
859  MOP cls;
860  SM_CLASS_CONSTRAINT *constraints;
861 
862  env->nnodes++;
863 
864  /* create oid segment for the entity */
865  env->nsegs++;
866 
867  for (name = get_referenced_attrs (entity); name != NULL; name = name->next)
868  {
869  env->nsegs++;
870  }
871 
872  /* check if the constraint is a function index info and add a segment for each function index expression */
873  if (entity->info.spec.flat_entity_list)
874  {
876  if (cls)
877  {
878  constraints = sm_class_constraints (cls);
879  while (constraints != NULL)
880  {
881  if (constraints->func_index_info)
882  {
883  env->nsegs++;
884  }
885  constraints = constraints->next;
886  }
887  }
888  }
889 
890  if (is_dependent_table (entity))
891  {
892  env->nterms += env->nnodes;
893  }
894 
895  /* recurse and size the graph for path entities */
896  for (next_entity = entity->info.spec.path_entities; next_entity != NULL; next_entity = next_entity->next)
897  {
898  (void) graph_size_for_entity (env, next_entity);
899  }
900 
901  /* create a term for each conjunct in the entity's path_conjuncts */
902  for (conj = entity->info.spec.path_conjuncts; conj != NULL; conj = conj->next)
903  {
904  env->nterms++;
905  }
906 
907  /* reserve space for explicit join dummy term */
908  switch (entity->info.spec.join_type)
909  {
910  case PT_JOIN_INNER:
911  /* reserve dummy inner join term */
912  env->nterms++;
913  /* reserve additional always-false sarg */
914  env->nterms++;
915  break;
916  case PT_JOIN_LEFT_OUTER:
917  case PT_JOIN_RIGHT_OUTER:
918  case PT_JOIN_FULL_OUTER:
919  /* reserve dummy outer join term */
920  env->nterms++;
921  break;
922  default:
923  break;
924  }
925 
926 }
927 
928 /*
929  * build_query_graph () - This pre walk function will build the portion of the
930  * query graph for each entity in the entity_list (from list)
931  * return: PT_NODE *
932  * parser(in): parser environment
933  * tree(in): tree to walk
934  * arg(in):
935  * continue_walk(in):
936  */
937 static PT_NODE *
938 build_query_graph (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
939 {
940  QO_ENV *env = *(QO_ENV **) arg;
941 
942  *continue_walk = PT_CONTINUE_WALK;
943 
944  /*
945  * skip nested selects, they've already been done and are
946  * constant with respect to the current select statement
947  */
948  if ((tree->node_type == PT_SELECT) && (tree != env->pt_tree))
949  {
950  *continue_walk = PT_LIST_WALK;
951  return tree;
952  }
953 
954  /* if its not an entity_spec, we're not interested */
955  if (tree->node_type != PT_SPEC)
956  {
957  return tree;
958  }
959 
960  (void) build_graph_for_entity (env, tree, QO_BUILD_ENTITY);
961 
962  /* don't visit leaves of the entity, build_graph_for_entity already did */
963  *continue_walk = PT_LIST_WALK;
964 
965  return tree;
966 }
967 
968 /*
969  * build_query_graph_post () - This post walk function will build the portion
970  * of the query graph for each path-entity in the entity_list (from list)
971  * return:
972  * parser(in): parser environment
973  * tree(in): tree to walk
974  * arg(in):
975  * continue_walk(in):
976  */
977 static PT_NODE *
978 build_query_graph_post (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
979 {
980  QO_ENV *env = *(QO_ENV **) arg;
981 
982  *continue_walk = PT_CONTINUE_WALK;
983 
984  /* if its not an entity_spec, we're not interested */
985  if (tree->node_type != PT_SPEC)
986  {
987  return tree;
988  }
989 
990  (void) build_graph_for_entity (env, tree, QO_BUILD_PATH);
991 
992  return tree;
993 }
994 
995 /*
996  * build_query_graph_function_index () - This pre walk function will search the tree for expressions that match
997  * expressions used in function indexes.
998  * For such matched expressions, a corresponding segment is added to the query graph.
999  * return: PT_NODE *
1000  * parser(in): parser environment
1001  * tree(in): tree to walk
1002  * arg(in):
1003  * continue_walk(in):
1004  */
1005 static PT_NODE *
1006 build_query_graph_function_index (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
1007 {
1008  PT_NODE *entity = NULL;
1009  UINTPTR spec_id = 0;
1010  int i, k;
1011  MOP cls;
1012  SM_CLASS_CONSTRAINT *constraints;
1013  QO_SEGMENT *seg;
1014  QO_NODE *node = NULL;
1015  QO_SEGMENT *seg_fi;
1016  const char *seg_name;
1017  QO_ENV *env = *(QO_ENV **) arg;
1018 
1019  *continue_walk = PT_CONTINUE_WALK;
1020 
1021  if (pt_is_function_index_expr (parser, tree, false))
1022  {
1023  if (!pt_is_join_expr (tree, &spec_id))
1024  {
1025  for (i = 0; i < env->nnodes; i++)
1026  {
1027  node = QO_ENV_NODE (env, i);
1028  entity = QO_NODE_ENTITY_SPEC (node);
1029  if (entity->info.spec.id == spec_id)
1030  {
1031  break; /* found the node */
1032  }
1033  }
1034 
1035  if (entity != NULL && entity->info.spec.entity_name
1036  && entity->info.spec.entity_name->node_type == PT_NAME
1037  && ((cls = sm_find_class (entity->info.spec.entity_name->info.name.original)) != NULL))
1038  {
1039  constraints = sm_class_constraints (cls);
1040  k = 0;
1041  while (constraints != NULL)
1042  {
1043  if (constraints->func_index_info)
1044  {
1045  char *expr_str = parser_print_function_index_expr (env->parser, tree);
1046 
1047  if (expr_str != NULL
1048  && !intl_identifier_casecmp (expr_str, constraints->func_index_info->expr_str))
1049  {
1050  for (i = 0; i < env->nsegs; i++)
1051  {
1052  seg_fi = QO_ENV_SEG (env, i);
1053  seg_name = QO_SEG_NAME (seg_fi);
1054  if ((QO_SEG_FUNC_INDEX (seg_fi) == true)
1055  && !intl_identifier_casecmp (seg_name, constraints->func_index_info->expr_str))
1056  {
1057  /* Also need to check whether the class alias names are matched. */
1058  if (!intl_identifier_casecmp (node->class_name, QO_SEG_HEAD (seg_fi)->class_name))
1059  {
1060  /* segment already exists */
1061  break;
1062  }
1063  }
1064  }
1065  if (i == env->nsegs)
1066  {
1067  seg = qo_insert_segment (node, NULL, tree, env, expr_str);
1068  QO_SEG_FUNC_INDEX (seg) = true;
1069  QO_SEG_NAME (seg) = strdup (constraints->func_index_info->expr_str);
1070  if (QO_SEG_NAME (seg) == NULL)
1071  {
1073  (size_t) (strlen (constraints->func_index_info->expr_str) + 1));
1074  *continue_walk = PT_STOP_WALK;
1075  return tree;
1076  }
1077  }
1078  }
1079  }
1080  constraints = constraints->next;
1081  k++;
1082  }
1083  }
1084  }
1085  }
1086  return tree;
1087 }
1088 
1089 /*
1090  * build_graph_for_entity () - This routine will create nodes and segments
1091  * based on the parse tree entity
1092  * return: QO_NODE *
1093  * env(in): optimizer environment
1094  * entity(in): entity to build the graph for
1095  * status(in):
1096  *
1097  * Note: Any changes made to this routine should be reflected in
1098  * graph_size_for_entity. They must remain in sync or else we might not
1099  * allocate enough space for the graph arrays resulting in memory
1100  * corruption.
1101  */
1102 static QO_NODE *
1104 {
1106  QO_NODE *node = NULL, *next_node;
1107  PT_NODE *name, *next_entity, *attr, *attr_list;
1108  QO_SEGMENT *seg;
1109  parser = QO_ENV_PARSER (env);
1110 
1111  if (!(status & QO_BUILD_ENTITY))
1112  {
1113  int i;
1114  for (i = 0; i < env->nnodes; i++)
1115  {
1116  node = QO_ENV_NODE (env, i);
1117  if (QO_NODE_ENTITY_SPEC (node) == entity)
1118  {
1119  break; /* found the node */
1120  }
1121  }
1122 
1123  goto build_path;
1124  }
1125 
1126  node = qo_add_node (entity, env);
1127 
1128  attr_list = get_referenced_attrs (entity);
1129 
1130  /*
1131  * Find the PT_NAME corresponding to this entity spec (i.e., the
1132  * PT_NODE that we want backing the oid segment we're about to
1133  * create), if such exists.
1134  */
1135 
1136  for (attr = attr_list; attr && !PT_IS_OID_NAME (attr); attr = attr->next)
1137  {
1138  ;
1139  }
1140 
1141  /*
1142  * 'attr' will be non-null iff the oid "attribute" of the class
1143  * is explicitly used in some way, e.g., in a comparison or a projection.
1144  * If it is non-null, it will be created with the rest of the symbols.
1145  *
1146  * If it is null, we'll make one unless we're dealing with a derived
1147  * table.
1148  */
1149  if (attr == NULL && entity->info.spec.derived_table == NULL && entity->info.spec.entity_name)
1150  {
1151  attr = parser_new_node (parser, PT_NAME);
1152  if (attr == NULL)
1153  {
1154  PT_INTERNAL_ERROR (parser, "allocate new node");
1155  return NULL;
1156  }
1157 
1159  attr->info.name.original = "";
1160  attr->info.name.spec_id = entity->info.spec.id;
1161  attr->info.name.meta_class = PT_OID_ATTR;
1162 
1163  /* create oid segment for the entity */
1164  seg = qo_insert_segment (node, NULL, attr, env, NULL);
1165  QO_SEG_SET_VALUED (seg) = false; /* oid segments aren't set valued */
1166  QO_SEG_CLASS_ATTR (seg) = false; /* oid segments aren't class attrs */
1167  QO_SEG_SHARED_ATTR (seg) = false; /* oid segments aren't shared attrs */
1168  }
1169 
1170  /*
1171  * Create a segment for each symbol in the entities symbol table.
1172  */
1173  for (name = attr_list; name != NULL; name = name->next)
1174  {
1175  seg = qo_insert_segment (node, NULL, name, env, NULL);
1176 
1177  if ((name->type_enum == PT_TYPE_SET) || (name->type_enum == PT_TYPE_MULTISET)
1178  || (name->type_enum == PT_TYPE_SEQUENCE))
1179  {
1180  QO_SEG_SET_VALUED (seg) = true;
1181  }
1182  else
1183  {
1184  QO_SEG_SET_VALUED (seg) = false;
1185  }
1186 
1187  if (name->info.name.meta_class == PT_META_ATTR)
1188  {
1189  QO_SEG_CLASS_ATTR (seg) = true;
1190  }
1191  else
1192  {
1193  QO_SEG_CLASS_ATTR (seg) = false;
1194  }
1195 
1196  /* this needs to check a flag Bill is going to add--CHECK!!!!! */
1197  QO_SEG_SHARED_ATTR (seg) = false;
1198  }
1199 
1200 build_path:
1201 
1202  if (!(status & QO_BUILD_PATH))
1203  {
1204  return node;
1205  }
1206 
1207  /* recurse and build the graph for path entities */
1208  for (next_entity = entity->info.spec.path_entities; next_entity != NULL; next_entity = next_entity->next)
1209  {
1210  next_node = build_graph_for_entity (env, next_entity, (QO_BUILD_STATUS) (QO_BUILD_ENTITY | QO_BUILD_PATH));
1211 
1212  /* for each path entity, fix the join segment */
1213  QO_ASSERT (env, next_node != NULL);
1214 
1215  /* make sure path entity contains the one and only path conjunct */
1216  QO_ASSERT (env, next_entity->info.spec.path_conjuncts != NULL);
1217  QO_ASSERT (env, next_entity->info.spec.path_conjuncts->next == NULL);
1218 
1219  (void) qo_join_segment (node, next_node, next_entity->info.spec.path_conjuncts->info.expr.arg1, env);
1220  }
1221 
1222  /* create a term for the entity's path_conjunct if one exists */
1223  if (entity->info.spec.path_conjuncts != NULL)
1224  {
1225  (void) qo_add_term (entity->info.spec.path_conjuncts, entity->info.spec.meta_class, env);
1226  }
1227 
1228  return node;
1229 }
1230 
1231 /*
1232  * qo_add_node () - This routine adds a node to the optimizer environment
1233  * for the entity
1234  * return: QO_NODE *
1235  * entity(in): entity to add node for
1236  * env(in): optimizer environment
1237  */
1238 static QO_NODE *
1240 {
1241  QO_NODE *node = NULL;
1242  QO_CLASS_INFO *info;
1243  int i, n;
1244  CLASS_STATS *stats;
1245 
1246  QO_ASSERT (env, env->nnodes < env->Nnodes);
1247  QO_ASSERT (env, entity != NULL);
1248  QO_ASSERT (env, entity->node_type == PT_SPEC);
1249 
1250  node = QO_ENV_NODE (env, env->nnodes);
1251 
1252  /* fill in node */
1253  QO_NODE_ENV (node) = env;
1254  QO_NODE_ENTITY_SPEC (node) = entity;
1255  QO_NODE_NAME (node) = entity->info.spec.range_var->info.name.original;
1256  QO_NODE_IDX (node) = env->nnodes;
1257  QO_NODE_SORT_LIMIT_CANDIDATE (node) = false;
1258 
1259  env->nnodes++;
1260 
1261  /*
1262  * If derived table there will be no info. Also if derived table
1263  * that is correlated to the current scope level, establish
1264  * dependency links to all nodes that precede it in the scope. This
1265  * is overkill, but it's easier than figuring out the exact
1266  * information, and it's usually the same anyway.
1267  */
1268  if (!PT_SPEC_IS_DERIVED (entity) && !PT_SPEC_IS_CTE (entity) && (info = qo_get_class_info (env, node)) != NULL)
1269  {
1270  QO_NODE_INFO (node) = info;
1271  for (i = 0, n = info->n; i < n; i++)
1272  {
1273  stats = QO_GET_CLASS_STATS (&info->info[i]);
1274  QO_ASSERT (env, stats != NULL);
1275  if (entity->info.spec.meta_class == PT_META_CLASS)
1276  {
1277  /* is class OID reference spec for example: 'class x' SELECT class_meth(class x, x.i) FROM x, class x */
1278  QO_NODE_NCARD (node) += 1;
1279  QO_NODE_TCARD (node) += 1;
1280  }
1281  else
1282  {
1283  QO_NODE_NCARD (node) += stats->heap_num_objects;
1284  QO_NODE_TCARD (node) += stats->heap_num_pages;
1285  }
1286  } /* for (i = ... ) */
1287  }
1288  else
1289  {
1290  QO_NODE_NCARD (node) = 5; /* just guess */
1291  QO_NODE_TCARD (node) = 1; /* just guess */
1292 
1293  /* recalculate derived table size */
1294  if (PT_SPEC_IS_DERIVED (entity))
1295  {
1296  XASL_NODE *xasl;
1297 
1298  switch (entity->info.spec.derived_table->node_type)
1299  {
1300  case PT_SELECT:
1301  case PT_UNION:
1302  case PT_DIFFERENCE:
1303  case PT_INTERSECTION:
1304  xasl = (XASL_NODE *) entity->info.spec.derived_table->info.query.xasl;
1305  if (xasl)
1306  {
1307  QO_NODE_NCARD (node) = (unsigned long) xasl->cardinality;
1308  QO_NODE_TCARD (node) =
1309  (unsigned long) ((QO_NODE_NCARD (node) * (double) xasl->projected_size) / (double) IO_PAGESIZE);
1310  if (QO_NODE_TCARD (node) == 0)
1311  {
1312  QO_NODE_TCARD (node) = 1;
1313  }
1314  }
1315  break;
1316  default:
1317  break;
1318  }
1319  }
1320  }
1321 
1322  n = QO_NODE_IDX (node);
1323  QO_NODE_SARGABLE (node) = true;
1324 
1325  switch (QO_NODE_PT_JOIN_TYPE (node))
1326  {
1327  case PT_JOIN_LEFT_OUTER:
1328  QO_NODE_SARGABLE (QO_ENV_NODE (env, n - 1)) = false;
1329  break;
1330 
1331  case PT_JOIN_RIGHT_OUTER:
1332  QO_NODE_SARGABLE (node) = false;
1333  break;
1334 
1335 /* currently, not used */
1336 /* case PT_JOIN_FULL_OUTER:
1337  QO_NODE_SARGABLE(QO_ENV_NODE(env, n - 1)) = false;
1338  QO_NODE_SARGABLE(node) = false;
1339  break;
1340  */
1341  default:
1342  break;
1343  }
1344 
1345  return node;
1346 }
1347 
1348 /*
1349  * lookup_node () - looks up node in the node array, returns NULL if not found
1350  * return: Ptr to node in node table. If node is found, entity will be set
1351  * to point to the corresponding entity spec in the parse tree.
1352  * attr(in): class to look up
1353  * env(in): optimizer environment
1354  * entity(in): entity spec for the node
1355  */
1356 QO_NODE *
1357 lookup_node (PT_NODE * attr, QO_ENV * env, PT_NODE ** entity)
1358 {
1359  int i;
1360  bool found = false;
1361  PT_NODE *aux = attr;
1362 
1363  if (pt_is_function_index_expr (env->parser, attr, false))
1364  {
1365  /*
1366  * The node should be the same for each argument of expression =>
1367  * once found should be returned
1368  */
1369  QO_NODE *node = NULL;
1370  if (attr->info.expr.op == PT_FUNCTION_HOLDER)
1371  {
1372  PT_NODE *func = attr->info.expr.arg1;
1373  for (aux = func->info.function.arg_list; aux != NULL; aux = aux->next)
1374  {
1375  PT_NODE *save_aux = aux;
1376  aux = pt_function_index_skip_expr (aux);
1377  if (aux->node_type == PT_NAME)
1378  {
1379  node = lookup_node (aux, env, entity);
1380  if (node == NULL)
1381  {
1382  return NULL;
1383  }
1384  else
1385  {
1386  return node;
1387  }
1388  }
1389  aux = save_aux;
1390  }
1391  }
1392  else
1393  {
1394  aux = pt_function_index_skip_expr (attr->info.expr.arg1);
1395  if (aux)
1396  {
1397  if (aux->node_type == PT_NAME)
1398  {
1399  node = lookup_node (aux, env, entity);
1400  if (node == NULL)
1401  {
1402  return NULL;
1403  }
1404  else
1405  {
1406  return node;
1407  }
1408  }
1409  }
1410  aux = pt_function_index_skip_expr (attr->info.expr.arg2);
1411  if (aux)
1412  {
1413  if (aux->node_type == PT_NAME)
1414  {
1415  node = lookup_node (aux, env, entity);
1416  if (node == NULL)
1417  {
1418  return NULL;
1419  }
1420  else
1421  {
1422  return node;
1423  }
1424  }
1425  }
1426  aux = pt_function_index_skip_expr (attr->info.expr.arg3);
1427  if (aux)
1428  {
1429  if (aux->node_type == PT_NAME)
1430  {
1431  node = lookup_node (aux, env, entity);
1432  if (node == NULL)
1433  {
1434  return NULL;
1435  }
1436  else
1437  {
1438  return node;
1439  }
1440  }
1441  }
1442  }
1443  /* node is null at this point */
1444  return node;
1445  }
1446 
1447  QO_ASSERT (env, aux->node_type == PT_NAME);
1448 
1449  for (i = 0; (!found) && (i < env->nnodes); /* no increment step */ )
1450  {
1451  *entity = QO_NODE_ENTITY_SPEC (QO_ENV_NODE (env, i));
1452  if ((*entity)->info.spec.id == aux->info.name.spec_id)
1453  {
1454  found = true;
1455  }
1456  else
1457  {
1458  i++;
1459  }
1460  }
1461 
1462  return ((found) ? QO_ENV_NODE (env, i) : NULL);
1463 }
1464 
1465 /*
1466  * qo_insert_segment () - inserts a segment into the optimizer environment
1467  * return: QO_SEGMENT *
1468  * head(in): head of the segment
1469  * tail(in): tail of the segment
1470  * node(in): pt_node that gave rise to this segment
1471  * env(in): optimizer environment
1472  * expr_str(in): function index expression (if needed - NULL for a normal or
1473  * filter index
1474  */
1475 static QO_SEGMENT *
1476 qo_insert_segment (QO_NODE * head, QO_NODE * tail, PT_NODE * node, QO_ENV * env, const char *expr_str)
1477 {
1478  QO_SEGMENT *seg = NULL;
1479 
1480  QO_ASSERT (env, head != NULL);
1481  QO_ASSERT (env, env->nsegs < env->Nsegs);
1482 
1483  seg = QO_ENV_SEG (env, env->nsegs);
1484 
1485  /* fill in seg */
1486  QO_SEG_PT_NODE (seg) = node;
1487  QO_SEG_HEAD (seg) = head;
1488  QO_SEG_TAIL (seg) = tail;
1489  QO_SEG_IDX (seg) = env->nsegs;
1490  /* add dummy name to segment example: dummy attr from view transfrom select count(*) from v select count(*) from
1491  * (select {v}, 1 from t) v (v, 1) here, '1' is dummy attr set empty string to avoid core crash
1492  */
1493  if (node)
1494  {
1495  QO_SEG_NAME (seg) =
1496  node->info.name.original ? node->info.name.original : pt_append_string (QO_ENV_PARSER (env), NULL, "");
1497  if (PT_IS_OID_NAME (node))
1498  {
1499  /* this is an oid segment */
1500  QO_NODE_OID_SEG (head) = seg;
1501  QO_SEG_INFO (seg) = NULL;
1502  }
1503  else if (!PT_IS_CLASSOID_NAME (node))
1504  {
1505  /* Ignore CLASSOIDs. They are generated by updates on the server and can be treated as any other projected
1506  * column. We don't need to know anything else about this attr since it can not be used as an index or in
1507  * any other interesting way.
1508  */
1509  if (node->node_type == PT_NAME)
1510  {
1511  QO_SEG_INFO (seg) = qo_get_attr_info (env, seg);
1512  }
1513  else
1514  {
1515  QO_SEG_INFO (seg) = qo_get_attr_info_func_index (env, seg, expr_str);
1516  }
1517  }
1518  }
1519 
1520  bitset_add (&(QO_NODE_SEGS (head)), QO_SEG_IDX (seg));
1521 
1522  env->nsegs++;
1523 
1524  return seg;
1525 }
1526 
1527 /*
1528  * qo_join_segment () - This routine will look for the segment and set its tail
1529  * to the correct node
1530  * return: QO_SEGMENT *
1531  * head(in): head of join segment
1532  * tail(in): tail of join segment
1533  * name(in): name of join segment
1534  * env(in): optimizer environment
1535  */
1536 static QO_SEGMENT *
1537 qo_join_segment (QO_NODE * head, QO_NODE * tail, PT_NODE * name, QO_ENV * env)
1538 {
1539  QO_SEGMENT *seg = NULL;
1540 
1541  seg = lookup_seg (head, name, env);
1542  QO_ASSERT (env, seg != NULL);
1543 
1544  QO_SEG_TAIL (seg) = tail; /* may be redundant */
1545 
1546  return seg;
1547 }
1548 
1549 /*
1550  * lookup_seg () -
1551  * return: ptr to segment in segment table, or NULL if the segment is not
1552  * in the table
1553  * head(in): head of the segment
1554  * name(in): name of the segment
1555  * env(in): optimizer environment
1556  */
1557 QO_SEGMENT *
1558 lookup_seg (QO_NODE * head, PT_NODE * name, QO_ENV * env)
1559 {
1560  int i;
1561  bool found = false;
1562 
1563  if (pt_is_function_index_expr (env->parser, name, false))
1564  {
1565  int k = -1;
1566  /* we search through the segments that come from a function index. If one of these are matched by the PT_NODE,
1567  * there is no need to search other segments, since they will never match
1568  */
1569  const char *expr_str = parser_print_function_index_expr (QO_ENV_PARSER (env), name);
1570 
1571  if (expr_str != NULL)
1572  {
1573  for (i = 0; (!found) && (i < env->nsegs); i++)
1574  {
1575  if (QO_SEG_FUNC_INDEX (QO_ENV_SEG (env, i)) == false)
1576  {
1577  continue;
1578  }
1579 
1580  /* match function index expression against the expression in the given query */
1581  if (!intl_identifier_casecmp (QO_SEG_NAME (QO_ENV_SEG (env, i)), expr_str))
1582  {
1583  /* Also need to check whether the class alias names are matched. */
1584  if (head != NULL
1585  && !intl_identifier_casecmp (head->class_name, QO_SEG_HEAD (QO_ENV_SEG (env, i))->class_name))
1586  {
1587  found = true;
1588  k = i;
1589  }
1590  }
1591  }
1592  }
1593 
1594  return ((found) ? QO_ENV_SEG (env, k) : NULL);
1595  }
1596 
1597  for (i = 0; (!found) && (i < env->nsegs); /* no increment step */ )
1598  {
1599  if (QO_SEG_HEAD (QO_ENV_SEG (env, i)) == head
1600  && pt_name_equal (QO_ENV_PARSER (env), QO_SEG_PT_NODE (QO_ENV_SEG (env, i)), name))
1601  {
1602  found = true;
1603  }
1604  else
1605  {
1606  i++;
1607  }
1608  }
1609 
1610  return ((found) ? QO_ENV_SEG (env, i) : NULL);
1611 }
1612 
1613 /*
1614  * qo_add_final_segment () -
1615  * return: PT_NODE *
1616  * parser(in): parser environment
1617  * tree(in): tree to walk
1618  * arg(in):
1619  * continue_walk(in):
1620  *
1621  * Note: This walk "pre" function looks up the segment for each
1622  * node in the list. If the node is a PT_NAME node, it can use it to
1623  * find the final segment. If the node is a dot expression, the final
1624  * segment will be the segment associated with the PT_NAME node that is
1625  * arg2 of the dot expression.
1626  */
1627 static PT_NODE *
1628 qo_add_final_segment (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
1629 {
1630  QO_ENV *env = *(QO_ENV **) arg;
1631 
1632  *continue_walk = PT_CONTINUE_WALK;
1633 
1634  if (tree->node_type == PT_NAME)
1635  {
1636  (void) set_seg_node (tree, env, &env->final_segs);
1637  *continue_walk = PT_LIST_WALK;
1638  }
1639  else if ((tree->node_type == PT_DOT_))
1640  {
1641  (void) set_seg_node (tree->info.dot.arg2, env, &env->final_segs);
1642  *continue_walk = PT_LIST_WALK;
1643  }
1644 
1645  return tree; /* don't alter tree structure */
1646 }
1647 
1648 /*
1649  * qo_add_term () - Creates a new term in the env term table
1650  * return: void
1651  * conjunct(in): term to add
1652  * term_type(in): is the term a path term?
1653  * env(in): optimizer environment
1654  */
1655 static QO_TERM *
1656 qo_add_term (PT_NODE * conjunct, int term_type, QO_ENV * env)
1657 {
1658  QO_TERM *term;
1659  QO_NODE *node;
1660 
1661  QO_ASSERT (env, conjunct->next == NULL);
1662 
1663  /* The conjuct could be PT_VALUE(0); (1) if an outer join condition was derived/transformed to the always-false ON
1664  * condition when type checking, expression evaluation or query rewrite transformation. We should sustained it for
1665  * correct outer join plan. It's different from ordinary WHERE condition. (2) Or is an always-false WHERE condition
1666  */
1667  QO_ASSERT (env, conjunct->node_type == PT_EXPR || conjunct->node_type == PT_VALUE);
1668  QO_ASSERT (env, env->nterms < env->Nterms);
1669 
1670  term = QO_ENV_TERM (env, env->nterms);
1671 
1672  /* fill in term */
1673  QO_TERM_CLASS (term) = QO_TC_SARG; /* assume sarg until proven otherwise */
1674  QO_TERM_JOIN_TYPE (term) = NO_JOIN;
1675  QO_TERM_PT_EXPR (term) = conjunct;
1676  QO_TERM_LOCATION (term) =
1677  (conjunct->node_type == PT_EXPR ? conjunct->info.expr.location : conjunct->info.value.location);
1678  QO_TERM_SELECTIVITY (term) = 0.0;
1679  QO_TERM_RANK (term) = 0;
1680  QO_TERM_FLAG (term) = 0; /* init */
1681  QO_TERM_IDX (term) = env->nterms;
1682  QO_TERM_MULTI_COL_SEGS (term) = NULL; /* init */
1683  QO_TERM_MULTI_COL_CNT (term) = 0; /* init */
1684 
1685  env->nterms++;
1686 
1687  if (conjunct->node_type == PT_EXPR)
1688  {
1689  (void) qo_analyze_term (term, term_type);
1690  }
1691  else
1692  {
1693  /* conjunct->node_type == PT_VALUE */
1694  if (!pt_false_search_condition (QO_ENV_PARSER (env), conjunct))
1695  {
1696  /* is an always-true WHERE condition */
1697  QO_TERM_SELECTIVITY (term) = 1.0;
1698  }
1699 
1700  if (conjunct->info.value.location == 0)
1701  {
1702  /* is an always-false WHERE condition */
1703  QO_TERM_CLASS (term) = QO_TC_OTHER; /* is dummy */
1704  }
1705  else
1706  {
1707  /* Assume 'conjunct->info.value.location' is same to QO_NODE idx */
1708  node = QO_ENV_NODE (env, conjunct->info.value.location);
1709  switch (QO_NODE_PT_JOIN_TYPE (node))
1710  {
1711  case PT_JOIN_INNER:
1712  /* add always-false arg to each X, Y example: SELECT ... FROM X inner join Y on 0 <> 0; */
1713  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (node) - 1);
1714 
1715  term = QO_ENV_TERM (env, env->nterms);
1716 
1717  /* fill in term */
1718  QO_TERM_CLASS (term) = QO_TC_SARG;
1719  QO_TERM_JOIN_TYPE (term) = NO_JOIN;
1720  QO_TERM_PT_EXPR (term) = conjunct;
1721  QO_TERM_LOCATION (term) = conjunct->info.value.location;
1722  if (!pt_false_search_condition (QO_ENV_PARSER (env), conjunct))
1723  {
1724  /* is an always-true WHERE condition */
1725  QO_TERM_SELECTIVITY (term) = 1.0;
1726  }
1727  else
1728  {
1729  QO_TERM_SELECTIVITY (term) = 0.0;
1730  }
1731  QO_TERM_RANK (term) = 0;
1732  QO_TERM_FLAG (term) = 0; /* init */
1733  QO_TERM_IDX (term) = env->nterms;
1734 
1735  env->nterms++;
1736 
1737  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (node));
1738  break;
1739  case PT_JOIN_LEFT_OUTER:
1740  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (node));
1741  break;
1742  case PT_JOIN_RIGHT_OUTER:
1743  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (node) - 1);
1744  break;
1745  case PT_JOIN_FULL_OUTER: /* not used */
1746  /* I don't know what is to be done for full outer. */
1747  break;
1748  default:
1749  /* this should not happen */
1750  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (node));
1751  break;
1752  }
1753  } /* else */
1754  }
1755 
1756  return term;
1757 }
1758 
1759 /*
1760  * qo_add_dep_term () -
1761  * return: void
1762  * derived_node(in): The node representing the dependent derived table
1763  * depend_nodes(in):
1764  * depend_segs(in):
1765  * env(in): optimizer environment
1766  *
1767  * Note: Creates a new QO_TC_DEP_LINK term in the env term table, plus
1768  * QO_TC_DEP_JOIN terms as necessary. QO_TC_DEP_LINK terms are
1769  * used only to capture dependency information between a node
1770  * representing a dependent derived table and a node on which
1771  * that derived table depends.
1772  */
1773 static void
1774 qo_add_dep_term (QO_NODE * derived_node, BITSET * depend_nodes, BITSET * depend_segs, QO_ENV * env)
1775 {
1776  QO_TERM *term = NULL;
1777  BITSET_ITERATOR bi;
1778  int ni, di;
1779 
1780  QO_ASSERT (env, env->nterms < env->Nterms);
1781 
1782  term = QO_ENV_TERM (env, env->nterms);
1783 
1784  bitset_assign (&(QO_NODE_DEP_SET (derived_node)), depend_nodes);
1785 
1786  /* fill in term */
1787  QO_TERM_CLASS (term) = QO_TC_DEP_LINK;
1788  QO_TERM_PT_EXPR (term) = NULL;
1789  QO_TERM_LOCATION (term) = 0;
1790  QO_TERM_SELECTIVITY (term) = 1.0;
1791  QO_TERM_RANK (term) = 0;
1792  QO_TERM_FLAG (term) = 0;
1793  QO_TERM_IDX (term) = env->nterms;
1794  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
1795  /*
1796  * This is misleading if |depend_nodes| > 1, but the planner is the
1797  * only party relying on this information, and it understands the
1798  * rules of the game.
1799  */
1800  QO_TERM_HEAD (term) = QO_ENV_NODE (env, bitset_first_member (depend_nodes));
1801  QO_TERM_TAIL (term) = derived_node;
1802 
1803  bitset_assign (&(QO_TERM_NODES (term)), depend_nodes);
1804  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (derived_node));
1805  bitset_assign (&(QO_TERM_SEGS (term)), depend_segs);
1806  /*
1807  * Add this term to env->fake_terms so that we're not tempted to sarg
1808  * it if a mergeable join term between these nodes is also present.
1809  * This is part of the fix for PR 7314.
1810  */
1811  bitset_add (&(env->fake_terms), QO_TERM_IDX (term));
1812 
1813  env->nterms++;
1814 
1815  ni = bitset_iterate (depend_nodes, &bi);
1816  while ((di = bitset_next_member (&bi)) != -1)
1817  {
1818  QO_ASSERT (env, env->nterms < env->Nterms);
1819  term = QO_ENV_TERM (env, env->nterms);
1820  QO_TERM_CLASS (term) = QO_TC_DEP_JOIN;
1821  QO_TERM_PT_EXPR (term) = NULL;
1822  QO_TERM_SELECTIVITY (term) = 1.0;
1823  QO_TERM_RANK (term) = 0;
1824  QO_TERM_FLAG (term) = 0;
1825  QO_TERM_IDX (term) = env->nterms;
1826  bitset_add (&(QO_TERM_NODES (term)), ni);
1827  bitset_add (&(QO_TERM_NODES (term)), di);
1828  QO_TERM_HEAD (term) = QO_ENV_NODE (env, ni);
1829  QO_TERM_TAIL (term) = QO_ENV_NODE (env, di);
1830  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
1831  /*
1832  * Do NOT add these terms to env->fake_terms, because (unlike the
1833  * DEP_LINK terms) there is no restriction on how they can be
1834  * implemented (e.g., if there's a mergeable term available to
1835  * join the two nodes, it's ok to use it).
1836  */
1837  env->nterms++;
1838  }
1839 
1840 }
1841 
1842 /*
1843  * qo_add_dummy_join_term () - Make and add dummy join term if there's no explicit
1844  * join term related with given two nodes
1845  * return: void
1846  * env(in): optimizer environment
1847  * p_node(in):
1848  * on_node(in):
1849  */
1850 static QO_TERM *
1852 {
1853  QO_TERM *term;
1854 
1855  QO_ASSERT (env, env->nterms < env->Nterms);
1856  QO_ASSERT (env, QO_NODE_IDX (p_node) >= 0);
1857  QO_ASSERT (env, QO_NODE_IDX (p_node) + 1 == QO_NODE_IDX (on_node));
1858  QO_ASSERT (env, QO_NODE_LOCATION (on_node) > 0);
1859 
1860  term = QO_ENV_TERM (env, env->nterms);
1861 
1862  /* fill in term */
1864  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (p_node));
1865  bitset_add (&(QO_TERM_NODES (term)), QO_NODE_IDX (on_node));
1866  QO_TERM_HEAD (term) = p_node;
1867  QO_TERM_TAIL (term) = on_node;
1868  QO_TERM_PT_EXPR (term) = NULL;
1869  QO_TERM_LOCATION (term) = QO_NODE_LOCATION (on_node);
1870  QO_TERM_SELECTIVITY (term) = 1.0;
1871  QO_TERM_RANK (term) = 0;
1872 
1873  switch (QO_NODE_PT_JOIN_TYPE (on_node))
1874  {
1875  case PT_JOIN_INNER:
1876  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
1877  QO_ADD_RIGHT_DEP_SET (on_node, p_node);
1878  break;
1879  case PT_JOIN_LEFT_OUTER:
1880  QO_TERM_JOIN_TYPE (term) = JOIN_LEFT;
1881  QO_ADD_RIGHT_DEP_SET (on_node, p_node);
1882  break;
1883  case PT_JOIN_RIGHT_OUTER:
1884  QO_TERM_JOIN_TYPE (term) = JOIN_RIGHT;
1885  QO_ADD_RIGHT_DEP_SET (on_node, p_node);
1886  QO_ADD_OUTER_DEP_SET (on_node, p_node);
1887  QO_ADD_RIGHT_TO_OUTER (on_node, p_node);
1888  break;
1889  case PT_JOIN_FULL_OUTER: /* not used */
1890  QO_TERM_JOIN_TYPE (term) = JOIN_OUTER;
1891  break;
1892  default:
1893  /* this should not happen */
1894  assert (false);
1895  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
1896  break;
1897  }
1898  QO_TERM_FLAG (term) = 0;
1899  QO_TERM_IDX (term) = env->nterms;
1900 
1901  env->nterms++;
1902 
1903  QO_ASSERT (env, QO_TERM_CAN_USE_INDEX (term) == 0);
1904 
1905  return term;
1906 }
1907 
1908 /*
1909  * qo_analyze_term () - determine the selectivity and class of the given term
1910  * return: void
1911  * term(in): term to analyze
1912  * term_type(in): predicate, path or selector path term
1913  */
1914 static void
1915 qo_analyze_term (QO_TERM * term, int term_type)
1916 {
1917  QO_ENV *env = NULL;
1919  bool merge_applies;
1920  bool lhs_indexable, rhs_indexable;
1921  PT_NODE *pt_expr = NULL, *lhs_expr = NULL, *rhs_expr = NULL, *func_arg = NULL;
1922  QO_NODE *head_node = NULL, *tail_node = NULL;
1923  QO_SEGMENT *head_seg = NULL, *tail_seg = NULL;
1924  BITSET lhs_segs, rhs_segs, lhs_nodes, rhs_nodes, multi_col_segs;
1925  BITSET_ITERATOR iter;
1926  PT_OP_TYPE op_type = PT_AND;
1927  int i, n, t, segs, j;
1928 
1929  env = QO_TERM_ENV (term);
1930 
1931  QO_ASSERT (env, QO_TERM_LOCATION (term) >= 0);
1932 
1933  parser = QO_ENV_PARSER (env);
1934  pt_expr = QO_TERM_PT_EXPR (term);
1935  merge_applies = true; /* until proven otherwise */
1936  lhs_indexable = rhs_indexable = false; /* until proven as indexable */
1937  lhs_expr = rhs_expr = NULL;
1938 
1939  bitset_init (&lhs_segs, env);
1940  bitset_init (&rhs_segs, env);
1941  bitset_init (&lhs_nodes, env);
1942  bitset_init (&rhs_nodes, env);
1943  bitset_init (&multi_col_segs, env);
1944 
1945  if (pt_expr->node_type != PT_EXPR)
1946  {
1947  goto wrapup;
1948  }
1949 
1950  /* only interesting in one predicate term; if 'term' has 'or_next', it was derived from OR term */
1951  /* also cases that are too complicated and unusual to consider here: (cond and/or cond) is true/false (cond and/or
1952  * cond) =/!= (cond and/or cond).
1953  */
1954  if (pt_expr->or_next == NULL && (pt_expr->info.expr.arg1 == NULL || pt_expr->info.expr.arg1->next == NULL)
1955  && (pt_expr->info.expr.arg2 == NULL || pt_expr->info.expr.arg2->next == NULL))
1956  {
1958 
1959  op_type = pt_expr->info.expr.op;
1960  switch (op_type)
1961  {
1962 
1963  /* operators classified as lhs- and rhs-indexable */
1964  case PT_EQ:
1966  /* FALLTHRU */
1967  case PT_LT:
1968  case PT_LE:
1969  case PT_GT:
1970  case PT_GE:
1971  /* temporary guess; RHS could be a indexable segment */
1972  rhs_indexable = true;
1973  /* FALLTHRU */
1974 
1975  /* operators classified as rhs-indexable */
1976  case PT_BETWEEN:
1977  case PT_RANGE:
1978  if (op_type == PT_RANGE)
1979  {
1980  assert (pt_expr->info.expr.arg2 != NULL);
1981 
1982  if (pt_expr->info.expr.arg2)
1983  {
1984  PT_NODE *between_and;
1985 
1986  between_and = pt_expr->info.expr.arg2;
1987  if (between_and->or_next)
1988  {
1989  /* is RANGE (r1, r2, ...) */
1991  }
1992 
1993  for (; between_and; between_and = between_and->or_next)
1994  {
1995  if (between_and->info.expr.op != PT_BETWEEN_EQ_NA)
1996  {
1997  break;
1998  }
1999  }
2000 
2001  if (between_and == NULL)
2002  {
2003  /* All ranges are EQ */
2005  }
2006  }
2007  }
2008  /* FALLTHRU */
2009  case PT_IS_IN:
2010  case PT_EQ_SOME:
2011  /* temporary guess; LHS could be a indexable segment */
2012  if (op_type == PT_IS_IN || op_type == PT_EQ_SOME)
2013  {
2014  /* 'RANGE LIST' flag is needed for 'IN' OP to avoid duplication of RANGE OP when index scan */
2016  }
2017  lhs_indexable = true;
2018  /* FALLTHRU */
2019 
2020  /* operators classified as not-indexable */
2021  case PT_NOT_BETWEEN:
2022  case PT_IS_NOT_IN:
2023  case PT_GE_SOME:
2024  case PT_GT_SOME:
2025  case PT_LT_SOME:
2026  case PT_LE_SOME:
2027  case PT_EQ_ALL:
2028  case PT_GE_ALL:
2029  case PT_GT_ALL:
2030  case PT_LT_ALL:
2031  case PT_LE_ALL:
2032  case PT_NE:
2033  case PT_SETEQ:
2034  case PT_SETNEQ:
2035  case PT_SUPERSETEQ:
2036  case PT_SUPERSET:
2037  case PT_SUBSET:
2038  case PT_SUBSETEQ:
2039  case PT_NE_SOME:
2040  case PT_NE_ALL:
2041  case PT_LIKE:
2042  case PT_NOT_LIKE:
2043  case PT_RLIKE:
2044  case PT_NOT_RLIKE:
2045  case PT_RLIKE_BINARY:
2046  case PT_NOT_RLIKE_BINARY:
2047  case PT_NULLSAFE_EQ:
2048  /* RHS of the expression */
2049  rhs_expr = pt_expr->info.expr.arg2;
2050  /* get segments from RHS of the expression */
2051  qo_expr_segs (env, rhs_expr, &rhs_segs);
2052  /* FALLTHRU */
2053 
2054  case PT_IS_NULL:
2055  case PT_IS_NOT_NULL:
2056  case PT_EXISTS:
2057  case PT_IS:
2058  case PT_IS_NOT:
2059  /* LHS of the expression */
2060  lhs_expr = pt_expr->info.expr.arg1;
2061  /* get segments from LHS of the expression */
2062  qo_expr_segs (env, lhs_expr, &lhs_segs);
2063  /* now break switch statement */
2064  break;
2065 
2066  case PT_OR:
2068  /* FALLTHRU */
2069  case PT_NOT:
2070  case PT_XOR:
2071  /* get segments from the expression itself */
2072  qo_expr_segs (env, pt_expr, &lhs_segs);
2073  break;
2074 
2075  /* the other operators that can not be used as term; error case */
2076  default:
2077  /* stop processing */
2078  QO_ABORT (env);
2079 
2080  } /* switch (op_type) */
2081  }
2082  else
2083  { /* if (pt_expr->or_next == NULL) */
2084  /* term that consist of more than one predicates; do same as PT_OR */
2085  qo_expr_segs (env, pt_expr, &lhs_segs);
2087  } /* if (pt_expr->or_next == NULL) */
2088 
2089  /* get nodes from segments */
2090  qo_seg_nodes (env, &lhs_segs, &lhs_nodes);
2091  qo_seg_nodes (env, &rhs_segs, &rhs_nodes);
2092 
2093  /* do LHS and RHS of the term belong to the different node? */
2094  if (!bitset_intersects (&lhs_nodes, &rhs_nodes))
2095  {
2096  i = 0; /* idx of term->index_seg[] array; it shall be 0 or 1 */
2097 
2098  /* There terms look like they might be candidates for implementation via indexes. Make sure that they really are
2099  * candidates. IMPORTANT: this is not the final say, since we don't know at this point whether indexes actually
2100  * exist or not. We won't know that until a later phase (qo_discover_indexes()). Right now we're just determining
2101  * whether these terms qualify structurally.
2102  */
2103 
2104  /* examine if LHS is indexable or not? */
2105 
2106  /* is LHS a type of name(attribute) of local database */
2107  if (lhs_indexable)
2108  {
2109  if (is_local_name (env, lhs_expr))
2110  {
2111  if (lhs_expr->type_enum == PT_TYPE_ENUMERATION)
2112  {
2113  /* lhs is indexable only if this is an equality comparison */
2114  op_type = pt_expr->info.expr.op;
2115  switch (op_type)
2116  {
2117  case PT_EQ:
2118  case PT_IS_IN:
2119  case PT_EQ_SOME:
2120  case PT_NULLSAFE_EQ:
2121  break;
2122  case PT_RANGE:
2123  if (!QO_TERM_IS_FLAGED (term, QO_TERM_EQUAL_OP))
2124  {
2125  lhs_indexable = false;
2126  }
2127  break;
2128  default:
2129  lhs_indexable = false;
2130  break;
2131  }
2132  }
2133  else
2134  {
2135  lhs_indexable = true;
2136  }
2137  }
2138  else if (pt_is_multi_col_term (lhs_expr))
2139  {
2140  /* multi column case (attr,attr,...) is indexable for RANGE, EQ operation */
2141  func_arg = lhs_expr->info.function.arg_list;
2142  op_type = pt_expr->info.expr.op;
2143 
2144  switch (op_type)
2145  {
2146  case PT_EQ:
2147  if (!PT_IS_CONST (rhs_expr) || !QO_TERM_IS_FLAGED (term, QO_TERM_EQUAL_OP))
2148  {
2149  lhs_indexable = false;
2150  }
2151  break;
2152  case PT_RANGE:
2153  if (!QO_TERM_IS_FLAGED (term, QO_TERM_EQUAL_OP))
2154  {
2155  lhs_indexable = false;
2156  }
2157  break;
2158  default:
2159  lhs_indexable = false;
2160  break;
2161  }
2162 
2163  if (lhs_indexable)
2164  {
2165  segs = 0;
2166  bool is_find_local_name = false;
2167  for ( /* none */ ; func_arg; func_arg = func_arg->next)
2168  {
2169  if (is_local_name (env, func_arg))
2170  {
2171  if (pt_is_function_index_expr (parser, func_arg, false)
2172  && !pt_is_function_index_expression (func_arg))
2173  {
2174  /* check if expr can be function index expr && expr is function index expr */
2175  lhs_indexable = false;
2176  break;
2177  }
2178  is_find_local_name = true;
2179  }
2180  else if (pt_is_const (func_arg))
2181  {
2182  /* multi_col_term having constant value can be indexable */
2184  }
2185  else
2186  {
2187  lhs_indexable = false;
2188  break;
2189  }
2190  segs++;
2191  }
2192  if (!is_find_local_name)
2193  {
2194  lhs_indexable = false;
2195  }
2196  }
2197  if (lhs_indexable)
2198  {
2201  QO_TERM_MULTI_COL_CNT (term) = segs;
2202  QO_TERM_MULTI_COL_SEGS (term) = (int *) malloc (sizeof (int) * segs);
2203 
2204  /* set multi col segs e.g.) (b,a,c) in .. multi_col_segs[0] = b's segnum, [1] = a .. */
2205  func_arg = lhs_expr->info.function.arg_list;
2206  for (j = 0; func_arg; func_arg = func_arg->next)
2207  {
2208  bitset_init (&multi_col_segs, env);
2209  qo_expr_segs (env, func_arg, &multi_col_segs);
2210  term->multi_col_segs[j++] = bitset_first_member (&multi_col_segs);
2211  }
2212  }
2213  }
2214  else
2215  {
2216  lhs_indexable = false;
2217  }
2218  }
2219  if (lhs_indexable
2220  && (pt_is_function_index_expr (parser, lhs_expr, false)
2221  || (lhs_expr && lhs_expr->info.expr.op == PT_PRIOR
2222  && pt_is_function_index_expr (parser, lhs_expr->info.expr.arg1, false))))
2223  {
2224  /* we should be dealing with a function indexable expression, so we must check if a segment has been
2225  * associated with it
2226  */
2227  n = bitset_first_member (&lhs_segs);
2228  if ((n == -1) || (QO_SEG_FUNC_INDEX (QO_ENV_SEG (env, n)) == false))
2229  {
2230  lhs_indexable = false;
2231  }
2232  }
2233  if (lhs_indexable && rhs_expr->next == NULL)
2234  {
2235 
2236  if (op_type == PT_IS_IN || op_type == PT_EQ_SOME)
2237  {
2238  /* We have to be careful with this case because "i IN (SELECT ...)" has a special meaning: in this case
2239  * the select is treated as UNBOX_AS_TABLE instead of the usual UNBOX_AS_VALUE, and we can't use an index
2240  * even if we want to (because of an XASL deficiency).Because pt_is_pseudo_const() wants to believe that
2241  * subqueries are pseudo-constants, we have to check for that condition outside of pt_is_pseudo_const().
2242  */
2243  switch (rhs_expr->node_type)
2244  {
2245  case PT_SELECT:
2246  case PT_UNION:
2247  case PT_DIFFERENCE:
2248  case PT_INTERSECTION:
2249  lhs_indexable = false;
2250  break;
2251  case PT_NAME:
2252  if (rhs_expr->info.name.meta_class != PT_PARAMETER && pt_is_set_type (rhs_expr))
2253  {
2254  lhs_indexable = false;
2255  }
2256  break;
2257  case PT_DOT_:
2258  if (pt_is_set_type (rhs_expr))
2259  {
2260  lhs_indexable = false;
2261  }
2262  break;
2263  case PT_VALUE:
2264  if (op_type == PT_EQ_SOME && rhs_expr->info.value.db_value_is_initialized
2265  && db_value_type_is_collection (&(rhs_expr->info.value.db_value)))
2266  {
2267  /* if we have the = some{} operator check its size */
2268  DB_COLLECTION *db_collectionp = db_get_collection (&(rhs_expr->info.value.db_value));
2269 
2270  if (db_col_size (db_collectionp) == 0)
2271  {
2272  lhs_indexable = false;
2273  }
2274  }
2275  lhs_indexable = lhs_indexable && pt_is_pseudo_const (rhs_expr);
2276  break;
2277  default:
2278  lhs_indexable = lhs_indexable && pt_is_pseudo_const (rhs_expr);
2279  }
2280  }
2281  else
2282  {
2283  /* is LHS attribute and is RHS constant value ? */
2284  lhs_indexable = lhs_indexable && pt_is_pseudo_const (rhs_expr);
2285  }
2286  }
2287 
2288  /* check LHS and RHS for collations that invalidate the term's use in a key range/filter; if one of the expr
2289  * sides contains such a collation then the whole term is not indexable */
2290  if (lhs_indexable || rhs_indexable)
2291  {
2292  int has_nis_coll = 0;
2293 
2294  (void) parser_walk_tree (parser, lhs_expr, pt_has_non_idx_sarg_coll_pre, &has_nis_coll, NULL, NULL);
2295  (void) parser_walk_tree (parser, rhs_expr, pt_has_non_idx_sarg_coll_pre, &has_nis_coll, NULL, NULL);
2296 
2297  if (has_nis_coll)
2298  {
2300  lhs_indexable = false;
2301  rhs_indexable = false;
2302  }
2303  }
2304 
2305  if (lhs_indexable)
2306  {
2307  n = bitset_first_member (&lhs_segs);
2308  if (n != -1)
2309  {
2310  /* record in the term that it has indexable segment as LHS */
2311  term->index_seg[i++] = QO_ENV_SEG (env, n);
2312  }
2313  }
2314 
2315  /* examine if LHS is indexable or not? */
2316  if (rhs_indexable)
2317  {
2318  if (is_local_name (env, rhs_expr) && pt_is_pseudo_const (lhs_expr))
2319  {
2320  /* is RHS attribute and is LHS constant value ? */
2321  if (rhs_expr->type_enum == PT_TYPE_ENUMERATION)
2322  {
2323  /* lhs is indexable only if this is an equality comparison */
2324  op_type = pt_expr->info.expr.op;
2325  switch (op_type)
2326  {
2327  case PT_EQ:
2328  case PT_IS_IN:
2329  case PT_EQ_SOME:
2330  case PT_NULLSAFE_EQ:
2331  break;
2332  case PT_RANGE:
2333  if (!QO_TERM_IS_FLAGED (term, QO_TERM_EQUAL_OP))
2334  {
2335  rhs_indexable = false;
2336  }
2337  break;
2338  default:
2339  rhs_indexable = false;
2340  break;
2341  }
2342  }
2343  else
2344  {
2345  rhs_indexable = true;
2346  }
2347  }
2348  else
2349  {
2350  rhs_indexable = false;
2351  }
2352  }
2353  if (rhs_indexable
2354  && (pt_is_function_index_expr (term->env->parser, rhs_expr, false)
2355  || (rhs_expr && rhs_expr->info.expr.op == PT_PRIOR
2356  && pt_is_function_index_expr (term->env->parser, rhs_expr->info.expr.arg1, false))))
2357  {
2358  /* we should be dealing with a function indexable expression, so we must check if a segment has been
2359  * associated with it
2360  */
2361  n = bitset_first_member (&rhs_segs);
2362  if ((n == -1) || (QO_SEG_FUNC_INDEX (QO_ENV_SEG (env, n)) == false))
2363  {
2364  rhs_indexable = false;
2365  }
2366  }
2367  if (rhs_indexable)
2368  {
2369  if (!lhs_indexable)
2370  {
2371  op_type = pt_converse_op (op_type);
2372  if (op_type != 0)
2373  {
2374  /* converse 'const op attr' to 'attr op const' */
2375  PT_NODE *tmp;
2376 
2377  tmp = pt_expr->info.expr.arg2;
2378  pt_expr->info.expr.arg2 = pt_expr->info.expr.arg1;
2379  pt_expr->info.expr.arg1 = tmp;
2380  pt_expr->info.expr.op = op_type;
2381  }
2382  else
2383  {
2384  /* must be impossible error. check pt_converse_op() */
2385  QO_ABORT (env);
2386  }
2387  }
2388 
2389  n = bitset_first_member (&rhs_segs);
2390  if (n != -1)
2391  {
2392  /* record in the term that it has indexable segment as RHS */
2393  term->index_seg[i++] = QO_ENV_SEG (env, n);
2394  }
2395  } /* if (rhs_indexable) */
2396 
2397 
2398  QO_TERM_CAN_USE_INDEX (term) = i; /* cardinality of term->index_seg[] array */
2399 
2400  }
2401  else
2402  { /* if (!bitset_intersects(&lhs_nodes, &rhs_nodes)) */
2403 
2404  merge_applies = false;
2405  QO_TERM_CAN_USE_INDEX (term) = 0;
2406 
2407  } /* if (!bitset_intersects(&lhs_nodes, &rhs_nodes)) */
2408 
2409 
2410  /* fill in segment and node information of QO_TERM structure */
2411  bitset_assign (&(QO_TERM_SEGS (term)), &lhs_segs);
2412  bitset_union (&(QO_TERM_SEGS (term)), &rhs_segs);
2413  bitset_assign (&(QO_TERM_NODES (term)), &lhs_nodes);
2414  bitset_union (&(QO_TERM_NODES (term)), &rhs_nodes);
2415 
2416  /* number of nodes with which this term associated */
2417  n = bitset_cardinality (&(QO_TERM_NODES (term)));
2418  /* determine the class of the term */
2419  if (term_type != PREDICATE_TERM)
2420  {
2421  QO_ASSERT (env, n >= 2);
2422 
2423  QO_TERM_CLASS (term) = QO_TC_PATH;
2424 
2425  if (n == 2)
2426  {
2427  /* i.e., it's a path term... In this case, it's imperative that we get the head and tail nodes and segs
2428  * right. Fortunately, in this particular case we can rely on the compiler to produce the term in a
2429  * consistent way, with the head on the lhs and the tail on the rhs.
2430  */
2431  head_node = QO_ENV_NODE (env, bitset_first_member (&lhs_nodes));
2432  tail_node = QO_ENV_NODE (env, bitset_first_member (&rhs_nodes));
2433 
2434  QO_ASSERT (env, QO_NODE_IDX (head_node) < QO_NODE_IDX (tail_node));
2435  }
2436  }
2437  else if (n == 0)
2438  {
2439  bool inst_num = false;
2440 
2441  (void) parser_walk_tree (parser, pt_expr, pt_check_instnum_pre, NULL, pt_check_instnum_post, &inst_num);
2442  QO_TERM_CLASS (term) = inst_num ? QO_TC_TOTALLY_AFTER_JOIN : QO_TC_OTHER;
2443  }
2444  else if (n == 1)
2445  {
2446  QO_TERM_CLASS (term) = QO_TC_SARG;
2447 
2448  /* QO_NODE to which this sarg term belongs */
2449  head_node = QO_ENV_NODE (env, bitset_iterate (&(QO_TERM_NODES (term)), &iter));
2450  }
2451  else if (n == 2)
2452  {
2453  QO_TERM_CLASS (term) = QO_TC_JOIN;
2454 
2455  /* Although it may be tempting to say that the head node is the first member of the lhs_nodes and the tail node
2456  * is the first member of the rhs_nodes, that's not always true. For example, a term like "x.a + y.b < 100" can
2457  * get in here, and then *both* head and tail are in lhs_nodes. If you get down into the code guarded by
2458  * 'merge_applies' you can safely make more stringent assumptions, but not before then.
2459  */
2460 
2461  head_node = QO_ENV_NODE (env, bitset_iterate (&(QO_TERM_NODES (term)), &iter));
2462  tail_node = QO_ENV_NODE (env, bitset_next_member (&iter));
2463 
2464  if (QO_NODE_IDX (head_node) > QO_NODE_IDX (tail_node))
2465  {
2466  QO_NODE *swap_node = NULL;
2467 
2468  swap_node = head_node;
2469  head_node = tail_node;
2470  tail_node = swap_node;
2471  }
2472  QO_ASSERT (env, QO_NODE_IDX (head_node) < QO_NODE_IDX (tail_node));
2473  QO_ASSERT (env, QO_NODE_IDX (tail_node) > 0);
2474 
2476  {
2477  /*+ multi col term is only indexable for TC_SARG */
2478  QO_TERM_CAN_USE_INDEX (term) = 0;
2479  }
2480  }
2481  else
2482  { /* n >= 3 */
2483  QO_TERM_CLASS (term) = QO_TC_OTHER;
2484 
2486  {
2487  /*+ multi col term is only indexable for TC_SARG */
2488  QO_TERM_CAN_USE_INDEX (term) = 0;
2489  }
2490  }
2491 
2492  if (n == 2)
2493  {
2494  QO_ASSERT (env, QO_TERM_CLASS (term) == QO_TC_PATH || QO_TERM_CLASS (term) == QO_TC_JOIN);
2495 
2496  /* This is a pretty weak test; it only looks for equality comparisons. */
2497  merge_applies &= expr_is_mergable (pt_expr);
2498 
2499  /* check for dependent edge. do not join with it */
2500  if (BITSET_MEMBER (QO_NODE_DEP_SET (head_node), QO_NODE_IDX (tail_node))
2501  || BITSET_MEMBER (QO_NODE_DEP_SET (tail_node), QO_NODE_IDX (head_node)))
2502  {
2503  QO_TERM_CLASS (term) = QO_TC_OTHER;
2504 
2505  merge_applies = false;
2506  }
2507 
2508  /* And there had better be something on both sides of the comparison too. You don't want to be misled by
2509  * something like "x.a + y.b = 100" because that's definitely not mergeable right now. Perhaps if we rewrote it
2510  * like "x.a = 100 - y.b" but that seems to be stretching things a little bit.
2511  */
2512  merge_applies = merge_applies && (!bitset_is_empty (&lhs_segs) && !bitset_is_empty (&rhs_segs));
2513 
2514  if (merge_applies || QO_TERM_CLASS (term) == QO_TC_PATH)
2515  {
2516  head_seg = QO_ENV_SEG (env, bitset_iterate (&(QO_TERM_SEGS (term)), &iter));
2517  for (t = bitset_iterate (&(QO_TERM_SEGS (term)), &iter); t != -1; t = bitset_next_member (&iter))
2518  {
2519  tail_seg = QO_ENV_SEG (env, t);
2520  if (QO_NODE_IDX (QO_SEG_HEAD (tail_seg)) != QO_NODE_IDX (QO_SEG_HEAD (head_seg)))
2521  {
2522  break; /* found tail */
2523  }
2524  }
2525 
2526  /* Now make sure that the head and tail segs correspond to the proper nodes. */
2527  if (QO_SEG_HEAD (head_seg) != head_node)
2528  {
2529  QO_SEGMENT *swap_seg = NULL;
2530 
2531  swap_seg = head_seg;
2532  head_seg = tail_seg;
2533  tail_seg = swap_seg;
2534  }
2535 
2536  QO_ASSERT (env, QO_SEG_HEAD (head_seg) == head_node);
2537  QO_ASSERT (env, QO_SEG_HEAD (tail_seg) == tail_node);
2538 
2539  /* These are really only interesting for path terms, but it doesn't hurt to set them for others too. */
2540  QO_TERM_SEG (term) = head_seg;
2541  QO_TERM_OID_SEG (term) = tail_seg;
2542 
2543  /* The term might be a merge term (i.e., it uses '=' as the operator), but the expressions might not be
2544  * simple attribute references, and we mustn't try to establish equivalence classes in that case.
2545  */
2546  if (qo_is_equi_join_term (term))
2547  {
2548  qo_equivalence (head_seg, tail_seg);
2549  QO_TERM_NOMINAL_SEG (term) = head_seg;
2550  }
2551  }
2552 
2553  /* always true transitive equi-join term is not suitable as m-join edge. */
2555  {
2556  merge_applies = false;
2557  }
2558 
2559  if (merge_applies)
2560  {
2562  }
2563 
2564  /* Now make sure that the two (node) ends of the join get cached in the term structure. */
2565  QO_TERM_HEAD (term) = head_node;
2566  QO_TERM_TAIL (term) = tail_node;
2567 
2568  QO_ASSERT (env, QO_NODE_IDX (QO_TERM_HEAD (term)) < QO_NODE_IDX (QO_TERM_TAIL (term)));
2569  }
2570 
2571  if (n == 1)
2572  {
2573  QO_ASSERT (env, QO_TERM_CLASS (term) == QO_TC_SARG);
2574  }
2575 
2576  /* classify TC_JOIN term for outer join and determine its join type */
2577  if (QO_TERM_CLASS (term) == QO_TC_JOIN)
2578  {
2579  QO_ASSERT (env, QO_NODE_IDX (head_node) < QO_NODE_IDX (tail_node));
2580 
2581  /* inner join until proven otherwise */
2582  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
2583 
2584  /* check iff explicit join term */
2585  if (QO_ON_COND_TERM (term))
2586  {
2587  QO_NODE *on_node;
2588 
2589  on_node = QO_ENV_NODE (env, QO_TERM_LOCATION (term));
2590  QO_ASSERT (env, on_node != NULL);
2591  QO_ASSERT (env, QO_NODE_IDX (on_node) > 0);
2592  QO_ASSERT (env, QO_NODE_LOCATION (on_node) > 0);
2593 
2594  QO_ASSERT (env, QO_TERM_LOCATION (term) == QO_NODE_LOCATION (on_node));
2595 
2596  if (QO_NODE_IDX (tail_node) == QO_NODE_IDX (on_node))
2597  {
2598  QO_ASSERT (env, QO_NODE_LOCATION (head_node) < QO_NODE_LOCATION (tail_node));
2599  QO_ASSERT (env, QO_NODE_LOCATION (tail_node) > 0);
2600 
2601  if (QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_LEFT_OUTER)
2602  {
2603  QO_TERM_JOIN_TYPE (term) = JOIN_LEFT;
2604  QO_ADD_RIGHT_DEP_SET (on_node, head_node);
2605  QO_ADD_OUTER_DEP_SET (on_node, head_node);
2606  }
2607  else if (QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_RIGHT_OUTER)
2608  {
2609  QO_TERM_JOIN_TYPE (term) = JOIN_RIGHT;
2610  QO_ADD_RIGHT_DEP_SET (on_node, head_node);
2611  QO_ADD_OUTER_DEP_SET (on_node, head_node);
2612  QO_ADD_RIGHT_TO_OUTER (on_node, head_node);
2613  }
2614  else if (QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_FULL_OUTER)
2615  { /* not used */
2616  QO_TERM_JOIN_TYPE (term) = JOIN_OUTER;
2617  }
2618  else if (QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_INNER)
2619  {
2620  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
2621  QO_ADD_RIGHT_DEP_SET (on_node, head_node);
2622  }
2623  }
2624  else
2625  {
2626  /* is not valid explicit join term */
2627  QO_TERM_CLASS (term) = QO_TC_OTHER;
2628 
2629  QO_TERM_JOIN_TYPE (term) = NO_JOIN;
2630 
2631  /* keep out from m-join edge */
2633  }
2634  }
2635  }
2636 
2637 wrapup:
2638 
2639  /* A negative selectivity means that the cardinality of the result depends only on the cardinality of the head, not
2640  * on the product of the cardinalities of the head and the tail as in the usual case.
2641  */
2642  switch (term_type)
2643  {
2644  case PT_PATH_INNER:
2645  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
2646  if (QO_NODE_NCARD (QO_TERM_TAIL (term)) == 0)
2647  {
2648  QO_TERM_SELECTIVITY (term) = 0.0;
2649  }
2650  else
2651  {
2652  QO_TERM_SELECTIVITY (term) = 1.0 / QO_NODE_NCARD (QO_TERM_TAIL (term));
2653  }
2654  break;
2655 
2656  case PT_PATH_OUTER:
2657  {
2658  QO_TERM *t_term;
2659  QO_NODE *t_node;
2660 
2661  /* Traverse previously generated terms */
2662  for (t = 0; t < env->nterms - 1; t++)
2663  {
2664 
2665  t_term = QO_ENV_TERM (env, t);
2666 
2667  if (QO_TERM_CLASS (t_term) == QO_TC_PATH && QO_TERM_JOIN_TYPE (t_term) == JOIN_LEFT)
2668  {
2669  if (head_node == NULL)
2670  {
2671  break;
2672  }
2673 
2674  if ((QO_NODE_IDX (QO_TERM_HEAD (t_term)) == QO_NODE_IDX (head_node))
2675  || (QO_NODE_IDX (QO_TERM_TAIL (t_term)) == QO_NODE_IDX (head_node)))
2676  {
2677  /* found previously generated head_nodes's path-term */
2678 
2679  /* get tail node */
2680  t_node = QO_TERM_TAIL (t_term);
2681 
2682  /* apply ordered dependency to the tail node */
2683  bitset_union (&(QO_NODE_OUTER_DEP_SET (tail_node)), &(QO_NODE_OUTER_DEP_SET (t_node)));
2684  bitset_add (&(QO_NODE_OUTER_DEP_SET (tail_node)), QO_NODE_IDX (t_node));
2685  }
2686  }
2687  }
2688  }
2689  /* FALL THROUGH */
2690  case PT_PATH_OUTER_WEASEL:
2691  /* These can't be implemented with index scans regardless because an index scan won't properly implement the
2692  * left-outer semantics of the path...
2693  */
2694  QO_TERM_JOIN_TYPE (term) = JOIN_LEFT;
2695  QO_TERM_SELECTIVITY (term) = -1.0;
2696  QO_TERM_CAN_USE_INDEX (term) = 0;
2697 
2698  /* For term_type is PT_PATH_OUTER_WEASEL, order dependency is needed. i.e. it's a path term. */
2699  if (term_type == PT_PATH_OUTER_WEASEL && head_node != NULL && tail_node != NULL)
2700  {
2701  assert (QO_TERM_CLASS (term) == QO_TC_PATH);
2702 
2703  bitset_union (&(QO_NODE_OUTER_DEP_SET (tail_node)), &(QO_NODE_OUTER_DEP_SET (head_node)));
2704  bitset_add (&(QO_NODE_OUTER_DEP_SET (tail_node)), QO_NODE_IDX (head_node));
2705  }
2706  break;
2707 
2708  case PREDICATE_TERM:
2709  QO_TERM_SELECTIVITY (term) = qo_expr_selectivity (env, pt_expr);
2710  break;
2711 
2712  default:
2713  QO_TERM_JOIN_TYPE (term) = JOIN_INNER;
2714  QO_TERM_SELECTIVITY (term) = -1.0;
2715  break;
2716  } /* switch (term_type) */
2717 
2718  bitset_delset (&lhs_segs);
2719  bitset_delset (&rhs_segs);
2720  bitset_delset (&lhs_nodes);
2721  bitset_delset (&rhs_nodes);
2722  bitset_delset (&multi_col_segs);
2723 }
2724 
2725 /*
2726  * qo_expr_segs () - Returns a bitset encoding all of the join graph segments
2727  * used in the pt_expr
2728  * return: BITSET
2729  * env(in):
2730  * pt_expr(in): pointer to a conjunct
2731  * result(out): BITSET of join segments (OUTPUT PARAMETER)
2732  */
2733 void
2734 qo_expr_segs (QO_ENV * env, PT_NODE * pt_expr, BITSET * result)
2735 {
2736  PT_NODE *next;
2737 
2738  if (pt_expr == NULL)
2739  {
2740  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_FAILED_ASSERTION, 1, "pt_expr != NULL");
2741  return;
2742  }
2743 
2744  /* remember the next link and then break it */
2745  next = pt_expr->next;
2746  pt_expr->next = NULL;
2747 
2748  /* use env to get the bitset to the walk functions */
2749  QO_ENV_TMP_BITSET (env) = result;
2750 
2751  (void) parser_walk_tree (env->parser, pt_expr, set_seg_expr, &env, pt_continue_walk, NULL);
2752 
2753  /* recover the next link */
2754  pt_expr->next = next;
2755 
2756  /* reset the temp pointer so we don't have a dangler */
2757  QO_ENV_TMP_BITSET (env) = NULL;
2758 }
2759 
2760 /*
2761  * set_seg_expr () -
2762  * return: PT_NODE *
2763  * parser(in): parser environment
2764  * tree(in): tree to walk
2765  * arg(in):
2766  * continue_walk(in):
2767  *
2768  * Note: This walk "pre" function will set a bit in the bitset for
2769  * each segment associated with the PT_NAME node.
2770  */
2771 static PT_NODE *
2772 set_seg_expr (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
2773 {
2774  QO_ENV *env = *(QO_ENV **) arg;
2775 
2776  *continue_walk = PT_CONTINUE_WALK;
2777 
2778  /*
2779  * Make sure we check all subqueries for embedded references. This
2780  * stuff really ought to all be done in one pass.
2781  */
2782  switch (tree->node_type)
2783  {
2784  case PT_SPEC:
2785  (void) parser_walk_tree (parser, tree->info.spec.derived_table, set_seg_expr, arg, pt_continue_walk, NULL);
2786  *continue_walk = PT_LIST_WALK;
2787  break;
2788 
2789  case PT_NAME:
2790  (void) set_seg_node (tree, env, QO_ENV_TMP_BITSET (env));
2791  *continue_walk = PT_LIST_WALK;
2792  break;
2793 
2794  case PT_DOT_:
2795  (void) set_seg_node (tree->info.dot.arg2, env, QO_ENV_TMP_BITSET (env));
2796  *continue_walk = PT_LIST_WALK;
2797  break;
2798 
2799  case PT_EXPR:
2800  if (tree->info.expr.op == PT_SYS_CONNECT_BY_PATH || tree->info.expr.op == PT_CONNECT_BY_ROOT
2801  || tree->info.expr.op == PT_PRIOR)
2802  {
2803  *continue_walk = PT_STOP_WALK;
2804  }
2805  if (pt_is_function_index_expr (parser, tree, false))
2806  {
2808  (void) set_seg_node (tree, env, QO_ENV_TMP_BITSET (env));
2809  if (bitset_cardinality (QO_ENV_TMP_BITSET (env)) - count_bits > 0)
2810  {
2811  *continue_walk = PT_LIST_WALK;
2812  }
2813  }
2814  break;
2815 
2816  case PT_JSON_TABLE:
2818  *continue_walk = PT_LIST_WALK;
2819  break;
2820 
2821  default:
2822  break;
2823  }
2824 
2825  return tree; /* don't alter tree structure */
2826 }
2827 
2828 /*
2829  * set_seg_node () -
2830  * return: nothing
2831  * attr(in): attribute to set the seg for
2832  * env(in): optimizer environment
2833  * bitset(in): bitset in which to set the bit for the segment
2834  */
2835 static void
2837 {
2838  QO_NODE *node;
2839  QO_SEGMENT *seg;
2840  PT_NODE *entity;
2841 
2842  node = lookup_node (attr, env, &entity);
2843 
2844  /* node will be null if this attr resolves to an enclosing scope */
2845  if (node != NULL && (seg = lookup_seg (node, attr, env)) != NULL)
2846  {
2847  /*
2848  * lookup_seg() really shouldn't ever fail here, but it used to
2849  * for shared variables, and it doesn't really hurt anyone just
2850  * to ignore failures here.
2851  */
2852  bitset_add (bitset, QO_SEG_IDX (seg));
2853  }
2854 
2855 }
2856 
2857 /*
2858  * expr_is_mergable () - Test if the pt_expr is an equi-join conjunct
2859  * return: bool
2860  * pt_expr(in):
2861  */
2862 static bool
2864 {
2865  if (pt_expr->or_next == NULL)
2866  { /* keep out OR conjunct */
2867  if (!pt_is_query (pt_expr->info.expr.arg1) && !pt_is_query (pt_expr->info.expr.arg2))
2868  {
2869  if (pt_expr->info.expr.op == PT_EQ)
2870  {
2871  return true;
2872  }
2873  else if (pt_expr->info.expr.op == PT_RANGE)
2874  {
2875  PT_NODE *between_and;
2876 
2877  between_and = pt_expr->info.expr.arg2;
2878  if (between_and->or_next == NULL /* has only one range */
2879  && between_and->info.expr.op == PT_BETWEEN_EQ_NA)
2880  {
2881  return true;
2882  }
2883  }
2884  }
2885  }
2886 
2887  return false;
2888 }
2889 
2890 /*
2891  * qo_is_equi_join_term () - Test if the term is an equi-join conjunct whose
2892  * left and right sides are simple attribute references
2893  * return: bool
2894  * term(in):
2895  */
2896 static bool
2898 {
2899  PT_NODE *pt_expr;
2900  PT_NODE *rhs_expr;
2901 
2903  {
2905  {
2906  /* keep out OR conjunct */
2907  return false;
2908  }
2909 
2910  pt_expr = QO_TERM_PT_EXPR (term);
2911  if (pt_is_attr (pt_expr->info.expr.arg1))
2912  {
2913  rhs_expr = pt_expr->info.expr.arg2;
2914  if (pt_expr->info.expr.op == PT_RANGE)
2915  {
2916  assert (rhs_expr->info.expr.op == PT_BETWEEN_EQ_NA);
2917  assert (rhs_expr->or_next == NULL);
2918  /* has only one range */
2919  rhs_expr = rhs_expr->info.expr.arg1;
2920  }
2921 
2922  return pt_is_attr (rhs_expr);
2923  }
2924  }
2925 
2926  return false;
2927 }
2928 
2929 /*
2930  * is_dependent_table () - Returns true iff the tree represents a dependent
2931  * derived table for this query
2932  * return: bool
2933  * entity(in): entity spec for a from list entry
2934  */
2935 static bool
2937 {
2938  if (entity->info.spec.derived_table == NULL)
2939  {
2940  return false;
2941  }
2942 
2943  /* this test is too pessimistic. The argument must depend on a previous entity spec in the from list.
2944  * >>>> FIXME some day <<<<
2945  *
2946  * is this still a thing?
2947  */
2948  switch (entity->info.spec.derived_table_type)
2949  {
2950  case PT_IS_SET_EXPR:
2951  case PT_IS_CSELECT:
2952  return true;
2953 
2954  case PT_DERIVED_JSON_TABLE:
2955  return true;
2956 
2957  case PT_IS_SUBQUERY:
2958  default:
2959  // what else?
2960  return entity->info.spec.derived_table->info.query.correlation_level == 1;
2961  }
2962 }
2963 
2964 /*
2965  * get_term_subqueries () - walks the expression to see whether it contains any
2966  * correlated subqueries. If so, it records the
2967  * identity of the containing term in the subquery
2968  * structure
2969  * return:
2970  * env(in): optimizer environment
2971  * term(in):
2972  */
2973 static void
2975 {
2976  PT_NODE *pt_expr, *next;
2977  WALK_INFO info;
2978 
2979  if (QO_IS_DEP_TERM (term))
2980  {
2981  /*
2982  * This is a pseudo-term introduced to keep track of derived
2983  * table dependencies. If the dependent derived table is based
2984  * on a subquery, we need to find that subquery and record it in
2985  * the pseudo-term.
2986  */
2987  pt_expr = QO_NODE_ENTITY_SPEC (QO_TERM_TAIL (term));
2988  }
2989  else
2990  {
2991  /*
2992  * This is a normal term, and we need to find all of the
2993  * correlated subqueries contained within it.
2994  */
2995  pt_expr = QO_TERM_PT_EXPR (term);
2996  }
2997 
2998  /*
2999  * This should only happen for dependent derived tables, either those
3000  * based on a set or when checking out QO_TC_DEP_JOIN terms
3001  * introduced for ddt's that depend on more than one thing.
3002  */
3003  if (pt_expr == NULL)
3004  {
3005  return;
3006  }
3007 
3008  next = pt_expr->next;
3009  pt_expr->next = NULL;
3010 
3011  info.env = env;
3012  info.term = term;
3013 
3014  (void) parser_walk_tree (QO_ENV_PARSER (env), pt_expr, check_subquery_pre, &info, pt_continue_walk, NULL);
3015 
3016  pt_expr->next = next;
3017 
3018 }
3019 
3020 /*
3021  * get_opcode_rank () -
3022  * return:
3023  * opcode(in):
3024  */
3025 static int
3027 {
3028  switch (opcode)
3029  {
3030  /* Group 1 -- light */
3031  case PT_COERCIBILITY:
3032  /* is always folded to constant : should not reach this code */
3033  assert (false);
3034  case PT_CHARSET:
3035  case PT_COLLATION:
3036  case PT_AND:
3037  case PT_OR:
3038  case PT_XOR:
3039  case PT_NOT:
3040  case PT_ASSIGN:
3041 
3042  case PT_IS_IN:
3043  case PT_IS_NOT_IN:
3044  case PT_BETWEEN:
3045  case PT_NOT_BETWEEN:
3046 
3047  case PT_EQ:
3048  case PT_EQ_SOME:
3049  case PT_NE_SOME:
3050  case PT_GE_SOME:
3051  case PT_GT_SOME:
3052  case PT_LT_SOME:
3053  case PT_LE_SOME:
3054  case PT_EQ_ALL:
3055  case PT_NE_ALL:
3056  case PT_GE_ALL:
3057  case PT_GT_ALL:
3058  case PT_LT_ALL:
3059  case PT_LE_ALL:
3060 
3061  case PT_NE:
3062  case PT_GE:
3063  case PT_GT:
3064  case PT_LT:
3065  case PT_LE:
3066 
3067  case PT_GT_INF:
3068  case PT_LT_INF:
3069 
3070  case PT_BIT_NOT:
3071  case PT_BIT_AND:
3072  case PT_BIT_OR:
3073  case PT_BIT_XOR:
3074  case PT_BITSHIFT_LEFT:
3075  case PT_BITSHIFT_RIGHT:
3076  case PT_DIV:
3077  case PT_MOD:
3078 
3079  case PT_NULLSAFE_EQ:
3080 
3081  case PT_PLUS:
3082  case PT_MINUS:
3083  case PT_TIMES:
3084  case PT_DIVIDE:
3085  case PT_UNARY_MINUS:
3086 
3087  case PT_EXISTS:
3088 
3089  case PT_BETWEEN_AND:
3090  case PT_BETWEEN_GE_LE:
3091  case PT_BETWEEN_GE_LT:
3092  case PT_BETWEEN_GT_LE:
3093  case PT_BETWEEN_GT_LT:
3094 
3095  case PT_BETWEEN_EQ_NA:
3096  case PT_BETWEEN_INF_LE:
3097  case PT_BETWEEN_INF_LT:
3098  case PT_BETWEEN_GE_INF:
3099  case PT_BETWEEN_GT_INF:
3100 
3101  case PT_RANGE:
3102 
3103  case PT_SYS_DATE:
3104  case PT_CURRENT_DATE:
3105  case PT_SYS_TIME:
3106  case PT_CURRENT_TIME:
3107  case PT_SYS_TIMESTAMP:
3108  case PT_CURRENT_TIMESTAMP:
3109  case PT_SYS_DATETIME:
3110  case PT_CURRENT_DATETIME:
3111  case PT_UTC_TIME:
3112  case PT_UTC_DATE:
3113 
3114  case PT_CURRENT_USER:
3116  case PT_CURRENT_VALUE:
3117  case PT_NEXT_VALUE:
3118 
3119  case PT_INST_NUM:
3120  case PT_ROWNUM:
3121  case PT_ORDERBY_NUM:
3122 
3123  case PT_MODULUS:
3124  case PT_RAND:
3125  case PT_DRAND:
3126  case PT_RANDOM:
3127  case PT_DRANDOM:
3128 
3129  case PT_FLOOR:
3130  case PT_CEIL:
3131  case PT_SIGN:
3132  case PT_POWER:
3133  case PT_ROUND:
3134  case PT_LOG:
3135  case PT_EXP:
3136  case PT_SQRT:
3137  case PT_ABS:
3138  case PT_CHR:
3139 
3140  case PT_LEVEL:
3141  case PT_CONNECT_BY_ISLEAF:
3142  case PT_CONNECT_BY_ISCYCLE:
3143 
3144  case PT_IS_NULL:
3145  case PT_IS_NOT_NULL:
3146  case PT_IS:
3147  case PT_IS_NOT:
3148 
3149  case PT_ACOS:
3150  case PT_ASIN:
3151  case PT_ATAN:
3152  case PT_ATAN2:
3153  case PT_SIN:
3154  case PT_COS:
3155  case PT_TAN:
3156  case PT_COT:
3157  case PT_DEGREES:
3158  case PT_RADIANS:
3159  case PT_PI:
3160  case PT_LN:
3161  case PT_LOG2:
3162  case PT_LOG10:
3163 
3164  case PT_DATEF:
3165  case PT_TIMEF:
3166  case PT_TIME_FORMAT:
3167  case PT_TIMESTAMP:
3168  case PT_YEARF:
3169  case PT_MONTHF:
3170  case PT_DAYF:
3171  case PT_DAYOFMONTH:
3172  case PT_HOURF:
3173  case PT_MINUTEF:
3174  case PT_SECONDF:
3175  case PT_UNIX_TIMESTAMP:
3176  case PT_FROM_UNIXTIME:
3177  case PT_QUARTERF:
3178  case PT_WEEKDAY:
3179  case PT_DAYOFWEEK:
3180  case PT_DAYOFYEAR:
3181  case PT_TODAYS:
3182  case PT_FROMDAYS:
3183  case PT_TIMETOSEC:
3184  case PT_SECTOTIME:
3185  case PT_MAKEDATE:
3186  case PT_MAKETIME:
3187  case PT_ADDTIME:
3188  case PT_NEW_TIME:
3189  case PT_WEEKF:
3190 
3191  case PT_SCHEMA:
3192  case PT_DATABASE:
3193  case PT_VERSION:
3194  case PT_USER:
3195  case PT_ROW_COUNT:
3196  case PT_LAST_INSERT_ID:
3197  case PT_DEFAULTF:
3198  case PT_LIST_DBS:
3200  case PT_TYPEOF:
3201  case PT_EVALUATE_VARIABLE:
3202  case PT_DEFINE_VARIABLE:
3203  case PT_BIN:
3204  case PT_INET_ATON:
3205  case PT_INET_NTOA:
3206  case PT_FROM_TZ:
3207  case PT_DBTIMEZONE:
3208  case PT_SESSIONTIMEZONE:
3209  case PT_UTC_TIMESTAMP:
3210  case PT_SCHEMA_DEF:
3211  return RANK_EXPR_LIGHT;
3212 
3213  /* Group 2 -- medium */
3214  case PT_REPEAT:
3215  case PT_SPACE:
3216  case PT_SETEQ:
3217  case PT_SETNEQ:
3218  case PT_SUPERSETEQ:
3219  case PT_SUPERSET:
3220  case PT_SUBSET:
3221  case PT_SUBSETEQ:
3222 
3223  case PT_POSITION:
3224  case PT_FINDINSET:
3225  case PT_SUBSTRING:
3226  case PT_SUBSTRING_INDEX:
3227  case PT_OCTET_LENGTH:
3228  case PT_BIT_LENGTH:
3229 
3230  case PT_CHAR_LENGTH:
3231  case PT_LOWER:
3232  case PT_UPPER:
3233  case PT_HEX:
3234  case PT_ASCII:
3235  case PT_CONV:
3236  case PT_TRIM:
3237 
3238  case PT_LIKE_LOWER_BOUND:
3239  case PT_LIKE_UPPER_BOUND:
3240  case PT_LTRIM:
3241  case PT_RTRIM:
3242  case PT_LPAD:
3243  case PT_RPAD:
3244  case PT_REPLACE:
3245  case PT_TRANSLATE:
3246 
3247  case PT_STRCAT:
3248  case PT_TO_CHAR:
3249  case PT_TO_DATE:
3250  case PT_TO_NUMBER:
3251  case PT_TO_TIME:
3252  case PT_TO_TIMESTAMP:
3253  case PT_TO_DATETIME:
3254 
3255  case PT_TRUNC:
3256  case PT_INSTR:
3257  case PT_LEAST:
3258  case PT_GREATEST:
3259  case PT_ADD_MONTHS:
3260  case PT_LAST_DAY:
3261  case PT_MONTHS_BETWEEN:
3262 
3263  case PT_CASE:
3264  case PT_NULLIF:
3265  case PT_COALESCE:
3266  case PT_NVL:
3267  case PT_NVL2:
3268  case PT_DECODE:
3269 
3270  case PT_EXTRACT:
3271  case PT_LIKE_ESCAPE:
3272  case PT_CAST:
3273 
3274  case PT_PATH_EXPR_SET:
3275 
3276  case PT_IF:
3277  case PT_IFNULL:
3278  case PT_ISNULL:
3279 
3280  case PT_CONCAT:
3281  case PT_CONCAT_WS:
3282  case PT_FIELD:
3283  case PT_LEFT:
3284  case PT_RIGHT:
3285  case PT_LOCATE:
3286  case PT_MID:
3287  case PT_STRCMP:
3288  case PT_REVERSE:
3289  case PT_DISK_SIZE:
3290 
3291  case PT_BIT_COUNT:
3292  case PT_ADDDATE:
3293  case PT_DATE_ADD:
3294  case PT_SUBDATE:
3295  case PT_DATE_SUB:
3296  case PT_FORMAT:
3297  case PT_DATE_FORMAT:
3298  case PT_STR_TO_DATE:
3299  case PT_DATEDIFF:
3300  case PT_TIMEDIFF:
3302  case PT_TZ_OFFSET:
3303  case PT_INDEX_PREFIX:
3304  case PT_TO_DATETIME_TZ:
3305  case PT_TO_TIMESTAMP_TZ:
3306  case PT_CRC32:
3307  case PT_CONV_TZ:
3308  return RANK_EXPR_MEDIUM;
3309 
3310  /* Group 3 -- heavy */
3311  case PT_LIKE:
3312  case PT_NOT_LIKE:
3313  case PT_RLIKE:
3314  case PT_NOT_RLIKE:
3315  case PT_RLIKE_BINARY:
3316  case PT_NOT_RLIKE_BINARY:
3317 
3318  case PT_MD5:
3319  case PT_AES_ENCRYPT:
3320  case PT_AES_DECRYPT:
3321  case PT_SHA_ONE:
3322  case PT_SHA_TWO:
3323  case PT_ENCRYPT:
3324  case PT_DECRYPT:
3325  case PT_INDEX_CARDINALITY:
3326  case PT_TO_BASE64:
3327  case PT_FROM_BASE64:
3328  case PT_SYS_GUID:
3329  case PT_SLEEP:
3330 
3331  return RANK_EXPR_HEAVY;
3332  /* special case operator */
3333  case PT_FUNCTION_HOLDER:
3334  /* should be solved at PT_EXPR */
3335  assert (false);
3336  return RANK_EXPR_MEDIUM;
3337  break;
3338  default:
3339  return RANK_EXPR_MEDIUM;
3340  }
3341 }
3342 
3343 /*
3344  * get_expr_fcode_rank () -
3345  * return:
3346  * fcode(in): function code
3347  * Only the functions embedded in an expression (with PT_FUNCTION_HOLDER)
3348  * should be added here.
3349  */
3350 static int
3352 {
3353  switch (fcode)
3354  {
3355  case F_ELT:
3356  return RANK_EXPR_LIGHT;
3357  case F_JSON_ARRAY:
3358  case F_JSON_ARRAY_APPEND:
3359  case F_JSON_ARRAY_INSERT:
3360  case F_JSON_CONTAINS:
3361  case F_JSON_CONTAINS_PATH:
3362  case F_JSON_DEPTH:
3363  case F_JSON_EXTRACT:
3364  case F_JSON_GET_ALL_PATHS:
3365  case F_JSON_KEYS:
3366  case F_JSON_INSERT:
3367  case F_JSON_LENGTH:
3368  case F_JSON_MERGE:
3369  case F_JSON_MERGE_PATCH:
3370  case F_JSON_OBJECT:
3371  case F_JSON_PRETTY:
3372  case F_JSON_QUOTE:
3373  case F_JSON_REMOVE:
3374  case F_JSON_REPLACE:
3375  case F_JSON_SEARCH:
3376  case F_JSON_SET:
3377  case F_JSON_TYPE:
3378  case F_JSON_UNQUOTE:
3379  case F_JSON_VALID:
3380  case F_INSERT_SUBSTRING:
3381  case F_REGEXP_COUNT:
3382  case F_REGEXP_INSTR:
3383  case F_REGEXP_LIKE:
3384  case F_REGEXP_REPLACE:
3385  case F_REGEXP_SUBSTR:
3386  return RANK_EXPR_MEDIUM;
3387  default:
3388  /* each function must fill its rank */
3389  assert (false);
3390  return RANK_EXPR_FUNCTION;
3391  }
3392 }
3393 
3394 /*
3395  * get_operand_rank () -
3396  * return:
3397  * node(in):
3398  */
3399 static int
3401 {
3402  int rank = RANK_DEFAULT;
3403 
3404  if (node)
3405  {
3406  switch (node->node_type)
3407  {
3408  case PT_NAME:
3409  rank = RANK_NAME;
3410  break;
3411 
3412  case PT_VALUE:
3413  rank = RANK_VALUE;
3414  break;
3415 
3416  case PT_EXPR:
3417  if (node->info.expr.op == PT_FUNCTION_HOLDER)
3418  {
3419  PT_NODE *function = node->info.expr.arg1;
3420 
3421  assert (function != NULL);
3422  if (function == NULL)
3423  {
3424  rank = RANK_EXPR_MEDIUM;
3425  }
3426  else
3427  {
3428  rank = get_expr_fcode_rank (function->info.function.function_type);
3429  }
3430  }
3431  else
3432  {
3433  rank = get_opcode_rank (node->info.expr.op);
3434  }
3435  break;
3436 
3437  case PT_FUNCTION:
3438  rank = RANK_EXPR_FUNCTION;
3439  break;
3440 
3441  default:
3442  break;
3443  }
3444  }
3445 
3446  return rank;
3447 }
3448 
3449 /*
3450  * get_term_rank () - walks the expression to see whether it contains any
3451  * rankable things. If so, it records the rank of the
3452  * containing term
3453  * return:
3454  * env(in): optimizer environment
3455  * term(in): term to get
3456  */
3457 static void
3459 {
3460  PT_NODE *pt_expr;
3461 
3463 
3464  if (QO_IS_FAKE_TERM (term))
3465  {
3466  pt_expr = NULL; /* do nothing */
3467  }
3468  else
3469  {
3470  pt_expr = QO_TERM_PT_EXPR (term);
3471  }
3472 
3473  if (pt_expr == NULL)
3474  {
3475  return;
3476  }
3477 
3478  /* At here, do not traverse OR list */
3479  switch (pt_expr->node_type)
3480  {
3481  case PT_EXPR:
3482  QO_TERM_RANK (term) += get_opcode_rank (pt_expr->info.expr.op);
3483  if (pt_expr->info.expr.arg1)
3484  QO_TERM_RANK (term) += get_operand_rank (pt_expr->info.expr.arg1);
3485  if (pt_expr->info.expr.arg2)
3486  QO_TERM_RANK (term) += get_operand_rank (pt_expr->info.expr.arg2);
3487  if (pt_expr->info.expr.arg3)
3488  QO_TERM_RANK (term) += get_operand_rank (pt_expr->info.expr.arg3);
3489  break;
3490 
3491  default:
3492  break;
3493  }
3494 }
3495 
3496 /*
3497  * check_subquery_pre () - Pre routine to add to some bitset all correlated
3498  * subqueries found in an expression
3499  * return: PT_NODE *
3500  * parser(in): parser environmnet
3501  * node(in): node to check
3502  * arg(in):
3503  * continue_walk(in):
3504  */
3505 static PT_NODE *
3506 check_subquery_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
3507 {
3508  WALK_INFO *info = (WALK_INFO *) arg;
3509 
3510  /*
3511  * Be sure to reenable walking for list tails.
3512  */
3513  *continue_walk = PT_CONTINUE_WALK;
3514 
3515  if (node->node_type == PT_SELECT || node->node_type == PT_UNION || node->node_type == PT_DIFFERENCE
3516  || node->node_type == PT_INTERSECTION)
3517  {
3518  *continue_walk = PT_LIST_WALK; /* NEVER need to look inside queries */
3519 
3520  if (node->info.query.correlation_level == 1)
3521  {
3522  /*
3523  * Find out the index of this subquery, and record that index
3524  * in the enclosing term's subquery bitset. This is lame,
3525  * but I can't think of a better way to do it. When we
3526  * originally grabbed all of the subqueries we had no idea
3527  * what expression they were in, so we have to discover it
3528  * after the fact. Oh well, this doesn't happen often
3529  * anyway.
3530  */
3531  int i, N;
3532  QO_ENV *env;
3533 
3534  env = info->env;
3535  for (i = 0, N = env->nsubqueries; i < N; i++)
3536  {
3537  if (node == env->subqueries[i].node)
3538  {
3539  bitset_add (&(env->subqueries[i].terms), QO_TERM_IDX (info->term));
3540  bitset_add (&(QO_TERM_SUBQUERIES (info->term)), i);
3541  break;
3542  }
3543  }
3544  }
3545  }
3546 
3547  return node; /* leave node unchanged */
3548 
3549 }
3550 
3551 /*
3552  * is_local_name () -
3553  * return: 1 iff the expression is a name correlated to the current query
3554  * env(in): Optimizer environment
3555  * expr(in): The parse tree for the expression to examine
3556  */
3557 static bool
3559 {
3560  UINTPTR spec = 0;
3561 
3562  if (expr == NULL)
3563  {
3564  return false;
3565  }
3566  else if (expr->node_type == PT_NAME)
3567  {
3568  spec = expr->info.name.spec_id;
3569  }
3570  else if (expr->node_type == PT_DOT_)
3571  {
3572  spec = expr->info.dot.arg2->info.name.spec_id;
3573  }
3574  else if (expr->node_type == PT_EXPR && expr->info.expr.op == PT_PRIOR)
3575  {
3576  return is_local_name (env, expr->info.expr.arg1);
3577  }
3578  else if (pt_is_function_index_expr (env->parser, expr, false))
3579  {
3580  if (expr->info.expr.op == PT_FUNCTION_HOLDER)
3581  {
3582  PT_NODE *arg = NULL;
3583  PT_NODE *func = expr->info.expr.arg1;
3584  for (arg = func->info.function.arg_list; arg != NULL; arg = arg->next)
3585  {
3586  PT_NODE *save_arg = arg;
3587  arg = pt_function_index_skip_expr (arg);
3588  if (arg->node_type == PT_NAME)
3589  {
3590  if (is_local_name (env, arg) == false)
3591  {
3592  return false;
3593  }
3594  }
3595  arg = save_arg;
3596  }
3597  }
3598  else
3599  {
3600  PT_NODE *arg = NULL;
3601  if (expr->info.expr.arg1)
3602  {
3603  arg = pt_function_index_skip_expr (expr->info.expr.arg1);
3604  if (arg->node_type == PT_NAME)
3605  {
3606  if (is_local_name (env, arg) == false)
3607  {
3608  return false;
3609  }
3610  }
3611  }
3612  if (expr->info.expr.arg2)
3613  {
3614  arg = pt_function_index_skip_expr (expr->info.expr.arg2);
3615  if (arg->node_type == PT_NAME)
3616  {
3617  if (is_local_name (env, arg) == false)
3618  {
3619  return false;
3620  }
3621  }
3622  }
3623  if (expr->info.expr.arg3)
3624  {
3625  arg = pt_function_index_skip_expr (expr->info.expr.arg3);
3626  if (arg->node_type == PT_NAME)
3627  {
3628  if (is_local_name (env, arg) == false)
3629  {
3630  return false;
3631  }
3632  }
3633  }
3634  }
3635  return true;
3636  }
3637  else
3638  {
3639  return false;
3640  }
3641 
3642  return (pt_find_entity (env->parser, env->pt_tree->info.query.q.select.from, spec) != NULL) ? true : false;
3643 }
3644 
3645 /*
3646  * pt_is_pseudo_const () -
3647  * return: true if the expression can serve as a pseudo-constant
3648  * during predicate evaluation. Used primarily to help
3649  * determine whether a predicate can be implemented
3650  * with an index scan
3651  * env(in): The optimizer environment
3652  * expr(in): The parse tree for the expression to examine
3653  */
3654 bool
3656 {
3657  if (expr == NULL)
3658  {
3659  return false;
3660  }
3661 
3662  switch (expr->node_type)
3663  {
3664  case PT_VALUE:
3665  case PT_HOST_VAR:
3666  return true;
3667 
3668  case PT_SELECT:
3669  case PT_UNION:
3670  case PT_DIFFERENCE:
3671  case PT_INTERSECTION:
3672  return (expr->info.query.correlation_level != 1) ? true : false;
3673 
3674  case PT_NAME:
3675  /*
3676  * It is up to the calling context to ensure that the name is
3677  * actually a pseudo constant, either because it is a correlated
3678  * outer reference, or because it can otherwise be guaranteed to
3679  * be evaluated by the time it is referenced.
3680  */
3681  return true;
3682 
3683  case PT_DOT_:
3684  /*
3685  * It would be nice if we could use expressions that are
3686  * guaranteed to be independent of the attribute, but the current
3687  * XASL implementation can't guarantee that such expressions have
3688  * been evaluated by the time that we need them, so we have to
3689  * play it safe here and not use them.
3690  */
3691  return true;
3692 
3693  case PT_EXPR:
3694  switch (expr->info.expr.op)
3695  {
3696  case PT_FUNCTION_HOLDER:
3697  return pt_is_pseudo_const (expr->info.expr.arg1);
3698  case PT_PLUS:
3699  case PT_STRCAT:
3700  case PT_MINUS:
3701  case PT_TIMES:
3702  case PT_DIVIDE:
3703  case PT_BIT_AND:
3704  case PT_BIT_OR:
3705  case PT_BIT_XOR:
3706  case PT_BITSHIFT_LEFT:
3707  case PT_BITSHIFT_RIGHT:
3708  case PT_DIV:
3709  case PT_MOD:
3710  case PT_LEFT:
3711  case PT_RIGHT:
3712  case PT_REPEAT:
3713  case PT_STRCMP:
3714  return (pt_is_pseudo_const (expr->info.expr.arg1)
3715  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3716  case PT_UNARY_MINUS:
3717  case PT_BIT_NOT:
3718  case PT_BIT_COUNT:
3719  case PT_QPRIOR:
3720  case PT_PRIOR:
3721  return pt_is_pseudo_const (expr->info.expr.arg1);
3722  case PT_BETWEEN_AND:
3723  case PT_BETWEEN_GE_LE:
3724  case PT_BETWEEN_GE_LT:
3725  case PT_BETWEEN_GT_LE:
3726  case PT_BETWEEN_GT_LT:
3727  return (pt_is_pseudo_const (expr->info.expr.arg1)
3728  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3729  case PT_BETWEEN_EQ_NA:
3730  case PT_BETWEEN_INF_LE:
3731  case PT_BETWEEN_INF_LT:
3732  case PT_BETWEEN_GE_INF:
3733  case PT_BETWEEN_GT_INF:
3734  return pt_is_pseudo_const (expr->info.expr.arg1);
3735  case PT_MODULUS:
3736  return (pt_is_pseudo_const (expr->info.expr.arg1)
3737  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3738  case PT_SCHEMA:
3739  case PT_DATABASE:
3740  case PT_VERSION:
3741  case PT_PI:
3742  case PT_USER:
3743  case PT_LAST_INSERT_ID:
3744  case PT_ROW_COUNT:
3745  case PT_DEFAULTF:
3746  case PT_LIST_DBS:
3748  case PT_SCHEMA_DEF:
3749  return true;
3750  case PT_FLOOR:
3751  case PT_CEIL:
3752  case PT_SIGN:
3753  case PT_ABS:
3754  case PT_CHR:
3755  case PT_EXP:
3756  case PT_SQRT:
3757  case PT_ACOS:
3758  case PT_ASIN:
3759  case PT_ATAN:
3760  case PT_SIN:
3761  case PT_COS:
3762  case PT_TAN:
3763  case PT_COT:
3764  case PT_DEGREES:
3765  case PT_RADIANS:
3766  case PT_LN:
3767  case PT_LOG2:
3768  case PT_LOG10:
3769  case PT_DATEF:
3770  case PT_TIMEF:
3771  return pt_is_pseudo_const (expr->info.expr.arg1);
3772  case PT_POWER:
3773  case PT_ROUND:
3774  case PT_TRUNC:
3775  case PT_LOG:
3776  return (pt_is_pseudo_const (expr->info.expr.arg1)
3777  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3778  case PT_INSTR:
3779  case PT_CONV:
3780  return (pt_is_pseudo_const (expr->info.expr.arg1) && pt_is_pseudo_const (expr->info.expr.arg2)
3781  && pt_is_pseudo_const (expr->info.expr.arg3)) ? true : false;
3782  case PT_POSITION:
3783  case PT_FINDINSET:
3784  return (pt_is_pseudo_const (expr->info.expr.arg1)
3785  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3786  case PT_SUBSTRING:
3787  case PT_SUBSTRING_INDEX:
3788  case PT_LOCATE:
3789  return (pt_is_pseudo_const (expr->info.expr.arg1) && pt_is_pseudo_const (expr->info.expr.arg2)
3790  && (expr->info.expr.arg3 ? pt_is_pseudo_const (expr->info.expr.arg3) : true)) ? true : false;
3791  case PT_CHAR_LENGTH:
3792  case PT_OCTET_LENGTH:
3793  case PT_BIT_LENGTH:
3794  case PT_LOWER:
3795  case PT_UPPER:
3796  case PT_HEX:
3797  case PT_ASCII:
3798  case PT_REVERSE:
3799  case PT_DISK_SIZE:
3800  case PT_SPACE:
3801  case PT_MD5:
3802  case PT_SHA_ONE:
3803  case PT_TO_BASE64:
3804  case PT_FROM_BASE64:
3805  case PT_BIN:
3806  case PT_TZ_OFFSET:
3807  case PT_CRC32:
3808  case PT_CONV_TZ:
3809  return pt_is_pseudo_const (expr->info.expr.arg1);
3810  case PT_TRIM:
3811  case PT_LTRIM:
3812  case PT_RTRIM:
3813  case PT_LIKE_LOWER_BOUND:
3814  case PT_LIKE_UPPER_BOUND:
3815  case PT_FROM_UNIXTIME:
3816  case PT_AES_ENCRYPT:
3817  case PT_AES_DECRYPT:
3818  case PT_SHA_TWO:
3819  return (pt_is_pseudo_const (expr->info.expr.arg1)
3820  && (expr->info.expr.arg2 ? pt_is_pseudo_const (expr->info.expr.arg2) : true)) ? true : false;
3821 
3822  case PT_LPAD:
3823  case PT_RPAD:
3824  case PT_REPLACE:
3825  case PT_TRANSLATE:
3826  case PT_INDEX_PREFIX:
3827  return (pt_is_pseudo_const (expr->info.expr.arg1) && pt_is_pseudo_const (expr->info.expr.arg2)
3828  && (expr->info.expr.arg3 ? pt_is_pseudo_const (expr->info.expr.arg3) : true)) ? true : false;
3829  case PT_ADD_MONTHS:
3830  return (pt_is_pseudo_const (expr->info.expr.arg1)
3831  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3832  case PT_LAST_DAY:
3833  case PT_UNIX_TIMESTAMP:
3834  if (expr->info.expr.arg1)
3835  {
3836  return pt_is_pseudo_const (expr->info.expr.arg1);
3837  }
3838  else
3839  {
3840  return true;
3841  }
3842  case PT_YEARF:
3843  case PT_MONTHF:
3844  case PT_DAYF:
3845  case PT_DAYOFMONTH:
3846  case PT_HOURF:
3847  case PT_MINUTEF:
3848  case PT_SECONDF:
3849  case PT_QUARTERF:
3850  case PT_WEEKDAY:
3851  case PT_DAYOFWEEK:
3852  case PT_DAYOFYEAR:
3853  case PT_TODAYS:
3854  case PT_FROMDAYS:
3855  case PT_TIMETOSEC:
3856  case PT_SECTOTIME:
3858  return pt_is_pseudo_const (expr->info.expr.arg1);
3859  case PT_TIMESTAMP:
3860  return (pt_is_pseudo_const (expr->info.expr.arg1)
3861  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3862  case PT_MONTHS_BETWEEN:
3863  case PT_TIME_FORMAT:
3864  case PT_FORMAT:
3865  case PT_ATAN2:
3866  case PT_ADDDATE:
3867  case PT_DATE_ADD: /* 2 args because the 3rd is constant (unit) */
3868  case PT_SUBDATE:
3869  case PT_DATE_SUB:
3870  case PT_DATE_FORMAT:
3871  case PT_STR_TO_DATE:
3872  case PT_DATEDIFF:
3873  case PT_TIMEDIFF:
3874  case PT_MAKEDATE:
3875  case PT_ADDTIME:
3876  case PT_WEEKF:
3877  case PT_FROM_TZ:
3878  return (pt_is_pseudo_const (expr->info.expr.arg1)
3879  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3880  case PT_SYS_DATE:
3881  case PT_CURRENT_DATE:
3882  case PT_SYS_TIME:
3883  case PT_CURRENT_TIME:
3884  case PT_SYS_TIMESTAMP:
3885  case PT_CURRENT_TIMESTAMP:
3886  case PT_SYS_DATETIME:
3887  case PT_CURRENT_DATETIME:
3888  case PT_UTC_TIME:
3889  case PT_UTC_DATE:
3891  case PT_CURRENT_USER:
3892  case PT_EVALUATE_VARIABLE:
3893  case PT_DBTIMEZONE:
3894  case PT_UTC_TIMESTAMP:
3895  return true;
3896  case PT_TO_CHAR:
3897  case PT_TO_DATE:
3898  case PT_TO_TIME:
3899  case PT_TO_TIMESTAMP:
3900  case PT_TO_DATETIME:
3901  case PT_TO_NUMBER:
3902  case PT_TO_DATETIME_TZ:
3903  case PT_TO_TIMESTAMP_TZ:
3904  return (pt_is_pseudo_const (expr->info.expr.arg1)
3905  && (expr->info.expr.arg2 ? pt_is_pseudo_const (expr->info.expr.arg2) : true)) ? true : false;
3906  case PT_CURRENT_VALUE:
3907  case PT_NEXT_VALUE:
3908  return true;
3909  case PT_CAST:
3910  return pt_is_pseudo_const (expr->info.expr.arg1);
3911  case PT_CASE:
3912  case PT_DECODE:
3913  return (pt_is_pseudo_const (expr->info.expr.arg1)
3914  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3915  case PT_NULLIF:
3916  case PT_COALESCE:
3917  case PT_NVL:
3918  return (pt_is_pseudo_const (expr->info.expr.arg1)
3919  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3920  case PT_IF:
3921  return (pt_is_pseudo_const (expr->info.expr.arg2)
3922  && pt_is_pseudo_const (expr->info.expr.arg3)) ? true : false;
3923  case PT_IFNULL:
3924  return (pt_is_pseudo_const (expr->info.expr.arg1)
3925  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3926 
3927  case PT_ISNULL:
3928  return pt_is_pseudo_const (expr->info.expr.arg1);
3929  case PT_CONCAT:
3930  return (pt_is_pseudo_const (expr->info.expr.arg1)
3931  && (expr->info.expr.arg2 ? pt_is_pseudo_const (expr->info.expr.arg2) : true)) ? true : false;
3932  case PT_CONCAT_WS:
3933  case PT_FIELD:
3934  return (pt_is_pseudo_const (expr->info.expr.arg1)
3935  && (expr->info.expr.arg2 ? pt_is_pseudo_const (expr->info.expr.arg2) : true)
3936  && pt_is_pseudo_const (expr->info.expr.arg3)) ? true : false;
3937  case PT_MID:
3938  case PT_NVL2:
3939  case PT_MAKETIME:
3940  case PT_NEW_TIME:
3941  return (pt_is_pseudo_const (expr->info.expr.arg1) && pt_is_pseudo_const (expr->info.expr.arg2)
3942  && pt_is_pseudo_const (expr->info.expr.arg3)) ? true : false;
3943  case PT_EXTRACT:
3944  return pt_is_pseudo_const (expr->info.expr.arg1);
3945  case PT_LEAST:
3946  case PT_GREATEST:
3947  return (pt_is_pseudo_const (expr->info.expr.arg1)
3948  && pt_is_pseudo_const (expr->info.expr.arg2)) ? true : false;
3949  case PT_COERCIBILITY:
3950  /* is always folded to constant : should not reach this code */
3951  assert (false);
3952  case PT_COLLATION:
3953  case PT_CHARSET:
3954  case PT_INET_ATON:
3955  case PT_INET_NTOA:
3956  return pt_is_pseudo_const (expr->info.expr.arg1);
3957  default:
3958  return false;
3959  }
3960 
3961  case PT_FUNCTION:
3962  {
3963  /*
3964  * The is the case we encounter for predicates like
3965  *
3966  * x in (a,b,c)
3967  *
3968  * Here the the expression '(a,b,c)' comes in as a multiset
3969  * function call, with PT_NAMEs 'a', 'b', and 'c' as its arglist.
3970  */
3971  PT_NODE *p;
3972 
3974  && expr->info.function.function_type != F_SEQUENCE)
3975  {
3976  return false;
3977  }
3978  for (p = expr->info.function.arg_list; p; p = p->next)
3979  {
3980  if (!pt_is_pseudo_const (p))
3981  {
3982  return false;
3983  }
3984  }
3985  return true;
3986  }
3987 
3988  default:
3989  return false;
3990  }
3991 }
3992 
3993 /*
3994  * add_local_subquery () - This routine adds an entry to the optimizer
3995  * environment for the subquery
3996  * return: nothing
3997  * env(in): Optimizer environment
3998  * node(in): The parse tree for the subquery being added
3999  */
4000 static void
4002 {
4003  int i, n;
4004  QO_SUBQUERY *tmp;
4005 
4006  n = env->nsubqueries++;
4007 
4008  /*
4009  * Be careful here: the previously allocated QO_SUBQUERY terms
4010  * contain bitsets that may have self-relative internal pointers, and
4011  * those pointers have to be maintained in the new array. The proper
4012  * way to make sure that they are consistent is to use the bitset_assign()
4013  * macro, not just to do the bitcopy that memcpy() will do.
4014  */
4015  tmp = NULL;
4016  if ((n + 1) > 0)
4017  {
4018  tmp = (QO_SUBQUERY *) malloc (sizeof (QO_SUBQUERY) * (n + 1));
4019  if (tmp == NULL)
4020  {
4022  return;
4023  }
4024  }
4025  else
4026  {
4027  return;
4028  }
4029 
4030  memcpy (tmp, env->subqueries, n * sizeof (QO_SUBQUERY));
4031  for (i = 0; i < n; i++)
4032  {
4033  QO_SUBQUERY *subq;
4034  subq = &env->subqueries[i];
4035  BITSET_MOVE (tmp[i].segs, subq->segs);
4036  BITSET_MOVE (tmp[i].nodes, subq->nodes);
4037  BITSET_MOVE (tmp[i].terms, subq->terms);
4038  }
4039  if (env->subqueries)
4040  {
4041  free_and_init (env->subqueries);
4042  }
4043  env->subqueries = tmp;
4044 
4045  tmp = &env->subqueries[n];
4046  tmp->node = node;
4047  bitset_init (&tmp->segs, env);
4048  bitset_init (&tmp->nodes, env);
4049  bitset_init (&tmp->terms, env);
4050  qo_expr_segs (env, node, &tmp->segs);
4051  qo_seg_nodes (env, &tmp->segs, &tmp->nodes);
4052  tmp->idx = n;
4053 }
4054 
4055 
4056 /*
4057  * get_local_subqueries_pre () - Builds vector of locally correlated
4058  * (level 1) queries
4059  * return:
4060  * parser(in):
4061  * node(in):
4062  * arg(in):
4063  * continue_walk(in):
4064  */
4065 static PT_NODE *
4066 get_local_subqueries_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
4067 {
4068  QO_ENV *env;
4069  BITSET segs;
4070 
4071  *continue_walk = PT_CONTINUE_WALK;
4072 
4073  switch (node->node_type)
4074  {
4075  case PT_SELECT:
4076  case PT_UNION:
4077  case PT_DIFFERENCE:
4078  case PT_INTERSECTION:
4079  /* check for correlated subquery except for SELECT list */
4080  if (node->info.query.correlation_level == 1)
4081  {
4082  env = (QO_ENV *) arg;
4083  bitset_init (&segs, env);
4084  qo_expr_segs (env, node, &segs);
4085  if (bitset_is_empty (&segs))
4086  {
4087  /* reduce_equality_terms() can change a correlated subquery to uncorrelated one */
4088  node->info.query.correlation_level = 0;
4089  }
4090  bitset_delset (&segs);
4091  }
4092  *continue_walk = PT_LIST_WALK;
4093  break;
4094 
4095  default:
4096  break;
4097  }
4098 
4099  return node;
4100 }
4101 
4102 /*
4103  * get_local_subqueries_post () - Builds vector of locally correlated
4104  * (level 1) queries
4105  * return:
4106  * parser(in):
4107  * node(in):
4108  * arg(in):
4109  * continue_walk(in):
4110  */
4111 static PT_NODE *
4112 get_local_subqueries_post (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
4113 {
4114  QO_ENV *env = (QO_ENV *) arg;
4115 
4116  *continue_walk = PT_CONTINUE_WALK;
4117 
4118  switch (node->node_type)
4119  {
4120  case PT_SELECT:
4121  case PT_UNION:
4122  case PT_DIFFERENCE:
4123  case PT_INTERSECTION:
4124  if (node->info.query.correlation_level == 1)
4125  {
4126  add_local_subquery (env, node);
4127  }
4128  break;
4129 
4130  default:
4131  break;
4132  }
4133 
4134  return node;
4135 }
4136 
4137 /*
4138  * get_local_subqueries () -
4139  * return: non-zero if something went wrong
4140  * env(in):
4141  * node(in):
4142  *
4143  * Note:
4144  * Gather the correlated level == 1 subqueries.
4145  * EXCLUDE nested queries.
4146  * INCLUDING the node being passed in.
4147  */
4148 static void
4150 {
4152  PT_NODE *tree;
4153  PT_NODE *select_list_ptr;
4154  PT_NODE *next_ptr;
4155  int i;
4156 
4157  parser = QO_ENV_PARSER (env);
4158  tree = QO_ENV_PT_TREE (env);
4159 
4160  next_ptr = tree->next;
4161  tree->next = NULL;
4162  select_list_ptr = tree->info.query.q.select.list;
4163  tree->info.query.q.select.list = NULL;
4164 
4166 
4167  /* restore next list pointer */
4168  tree->next = next_ptr;
4169  tree->info.query.q.select.list = select_list_ptr;
4170 
4171  /*
4172  * Now that all of the subqueries have been discovered, make
4173  * *another* pass and associate each with its enclosing QO_TERM, if any.
4174  */
4175  for (i = 0; i < env->nterms; i++)
4176  {
4177  get_term_subqueries (env, QO_ENV_TERM (env, i));
4178  }
4179 
4180  QO_ASSERT (env, env->subqueries != NULL || env->nsubqueries == 0);
4181 
4182 }
4183 
4184 
4185 /*
4186  * get_rank () - Gather term's rank
4187  * return:
4188  * env(in):
4189  */
4190 static void
4192 {
4193  int i;
4194 
4195  for (i = 0; i < env->nterms; i++)
4196  {
4197  get_term_rank (env, QO_ENV_TERM (env, i));
4198  }
4199 }
4200 
4201 /*
4202  * get_referenced_attrs () - Returns the list of this entity's attributes that
4203  * are referenced in this query
4204  * return:
4205  * entity(in):
4206  */
4207 static PT_NODE *
4209 {
4210  return (PT_SPEC_IS_DERIVED (entity)
4211  || PT_SPEC_IS_CTE (entity)) ? entity->info.spec.as_attr_list : entity->info.spec.referenced_attrs;
4212 }
4213 
4214 /*
4215  * add_hint_args () - attach hint informations to QO_NODEs
4216  * return:
4217  * env(in):
4218  * arg_list(in):
4219  * hint(in):
4220  */
4221 static void
4223 {
4224  PT_NODE *arg, *entity_spec;
4225  QO_NODE *node;
4226  int i;
4227 
4228  if (arg_list)
4229  {
4230  /* iterate over all nodes */
4231  for (i = 0; i < env->nnodes; i++)
4232  {
4233  node = QO_ENV_NODE (env, i);
4234  entity_spec = QO_NODE_ENTITY_SPEC (node);
4235  /* check for spec list */
4236  for (arg = arg_list; arg; arg = arg->next)
4237  {
4238  /* found match */
4239  if (entity_spec->info.spec.id == arg->info.name.spec_id)
4240  {
4241  QO_NODE_HINT (node) = (PT_HINT_ENUM) (QO_NODE_HINT (node) | hint);
4242  break;
4243  }
4244  }
4245  }
4246  }
4247  else
4248  { /* FULLY HINTED */
4249  /* iterate over all nodes */
4250  for (i = 0; i < env->nnodes; i++)
4251  {
4252  node = QO_ENV_NODE (env, i);
4253  QO_NODE_HINT (node) = (PT_HINT_ENUM) (QO_NODE_HINT (node) | hint);
4254  }
4255  }
4256 
4257 }
4258 
4259 /*
4260  * add_hint () -
4261  * return:
4262  * env(in):
4263  * tree(in):
4264  */
4265 static void
4267 {
4268  PT_HINT_ENUM hint;
4269  int i, j, k;
4270  QO_NODE *node, *p_node;
4271  PT_NODE *arg, *p_arg, *spec, *p_spec;
4272  int last_ordered_idx = 0;
4273 
4274  hint = tree->info.query.q.select.hint;
4275 
4276  if (hint & PT_HINT_ORDERED)
4277  {
4278  if (tree->info.query.q.select.ordered)
4279  {
4280  /* find last ordered node */
4281  for (arg = tree->info.query.q.select.ordered; arg->next; arg = arg->next)
4282  {
4283  ; /* nop */
4284  }
4285  for (i = 0; i < env->nnodes; i++)
4286  {
4287  node = QO_ENV_NODE (env, i);
4288  spec = QO_NODE_ENTITY_SPEC (node);
4289  if (spec->info.spec.id == arg->info.name.spec_id)
4290  {
4291  last_ordered_idx = QO_NODE_IDX (node);
4292  break;
4293  }
4294  }
4295 
4296  /* iterate over all nodes */
4297  for (i = 0; i < env->nnodes; i++)
4298  {
4299  node = QO_ENV_NODE (env, i);
4300  spec = QO_NODE_ENTITY_SPEC (node);
4301  /* check for arg list */
4302  p_arg = NULL;
4303  for (arg = tree->info.query.q.select.ordered, j = 0; arg; arg = arg->next, j++)
4304  {
4305  if (spec->info.spec.id == arg->info.name.spec_id)
4306  {
4307  if (p_arg)
4308  { /* skip out the first ordered spec */
4309  /* find prev node */
4310  for (k = 0; k < env->nnodes; k++)
4311  {
4312  p_node = QO_ENV_NODE (env, k);
4313  p_spec = QO_NODE_ENTITY_SPEC (p_node);
4314  if (p_spec->info.spec.id == p_arg->info.name.spec_id)
4315  {
4317  bitset_add (&(QO_NODE_OUTER_DEP_SET (node)), QO_NODE_IDX (p_node));
4318  break;
4319  }
4320  }
4321  }
4322 
4323 #if 1 /* TEMPORARY CODE: DO NOT REMOVE ME !!! */
4324  QO_NODE_HINT (node) = (PT_HINT_ENUM) (QO_NODE_HINT (node) | PT_HINT_ORDERED);
4325 #endif
4326  break; /* exit loop for arg traverse */
4327  }
4328 
4329  p_arg = arg; /* save previous arg */
4330  }
4331 
4332  /* not found in arg list */
4333  if (!arg)
4334  {
4335  bitset_add (&(QO_NODE_OUTER_DEP_SET (node)), last_ordered_idx);
4336  }
4337 
4338  } /* for (i = ... ) */
4339 
4340  }
4341  else
4342  { /* FULLY HINTED */
4343  /* iterate over all nodes */
4344  p_node = NULL;
4345  for (i = 0; i < env->nnodes; i++)
4346  {
4347  node = QO_ENV_NODE (env, i);
4348  if (p_node)
4349  { /* skip out the first ordered node */
4351  bitset_add (&(QO_NODE_OUTER_DEP_SET (node)), QO_NODE_IDX (p_node));
4352  }
4353 #if 1 /* TEMPORARY CODE: DO NOT REMOVE ME !!! */
4354  QO_NODE_HINT (node) = (PT_HINT_ENUM) (QO_NODE_HINT (node) | PT_HINT_ORDERED);
4355 #endif
4356 
4357  p_node = node; /* save previous node */
4358  } /* for (i = ... ) */
4359  }
4360  }
4361 
4362  if (hint & PT_HINT_USE_NL)
4363  {
4364  add_hint_args (env, tree->info.query.q.select.use_nl, PT_HINT_USE_NL);
4365  }
4366 
4367  if (hint & PT_HINT_USE_IDX)
4368  {
4369  add_hint_args (env, tree->info.query.q.select.use_idx, PT_HINT_USE_IDX);
4370  }
4371  if (hint & PT_HINT_INDEX_SS)
4372  {
4373  add_hint_args (env, tree->info.query.q.select.index_ss, PT_HINT_INDEX_SS);
4374  }
4375  if (hint & PT_HINT_INDEX_LS)
4376  {
4377  add_hint_args (env, tree->info.query.q.select.index_ls, PT_HINT_INDEX_LS);
4378  }
4379 
4380 
4381  if (hint & PT_HINT_USE_MERGE)
4382  {
4383  add_hint_args (env, tree->info.query.q.select.use_merge, PT_HINT_USE_MERGE);
4384  }
4385 }
4386 
4387 /*
4388  * add_using_index () - attach index names specified in USING INDEX clause to QO_NODEs
4389  * return:
4390  * env(in):
4391  * using_index(in):
4392  */
4393 static void
4394 add_using_index (QO_ENV * env, PT_NODE * using_index)
4395 {
4396  int i, j, n;
4397  QO_NODE *nodep;
4398  QO_USING_INDEX *uip;
4399  PT_NODE *indexp, *indexp_nokl;
4400  bool is_none, is_ignored;
4401  PT_NODE **idx_ignore_list = NULL;
4402  int idx_ignore_list_capacity = 0;
4403  int idx_ignore_list_size = 0;
4404 
4405  if (!using_index)
4406  {
4407  /* no USING INDEX clause in the query; all QO_NODE_USING_INDEX(node) will contain NULL */
4408  goto cleanup;
4409  }
4410 
4411  /* allocate memory for index ignore list; by default, the capacity of the list is the number of index hints in the
4412  * USING INDEX clause
4413  */
4414  idx_ignore_list_capacity = 0;
4415  for (indexp = using_index; indexp; indexp = indexp->next)
4416  {
4417  idx_ignore_list_capacity++;
4418  }
4419 
4420  idx_ignore_list = (PT_NODE **) malloc (idx_ignore_list_capacity * sizeof (PT_NODE *));
4421  if (idx_ignore_list == NULL)
4422  {
4424  idx_ignore_list_capacity * sizeof (PT_NODE *));
4425  goto cleanup;
4426  }
4427 
4428  /* if an index occurs more than once and at least one occurrence has a keylimit, we should ignore the occurrences
4429  * without keylimit; we now build an ignore list containing indexes which should not be attached to the QO_NODE
4430  */
4431  idx_ignore_list_size = 0;
4432  for (indexp_nokl = using_index; indexp_nokl; indexp_nokl = indexp_nokl->next)
4433  {
4434  if (indexp_nokl->info.name.original && indexp_nokl->info.name.resolved && !indexp_nokl->info.name.indx_key_limit)
4435  {
4436  /* it's a normal index without a keylimit; search for same index with keylimit */
4437  for (indexp = using_index; indexp; indexp = indexp->next)
4438  {
4439  if (indexp->info.name.original && indexp->info.name.resolved && indexp->info.name.indx_key_limit
4440  && indexp->etc == indexp_nokl->etc
4441  && !intl_identifier_casecmp (indexp->info.name.original, indexp_nokl->info.name.original)
4442  && !intl_identifier_casecmp (indexp->info.name.resolved, indexp_nokl->info.name.resolved))
4443  {
4444  /* same index found, with keylimit; add to ignore list */
4445  idx_ignore_list[idx_ignore_list_size++] = indexp_nokl;
4446  break;
4447  }
4448  } /* for (indexp ...) */
4449  }
4450  } /* for (indexp_nokl ...) */
4451 
4452  /* for each node */
4453  for (i = 0; i < env->nnodes; i++)
4454  {
4455  nodep = QO_ENV_NODE (env, i);
4456  is_none = false;
4457 
4458  /* count number of indexes for this node */
4459  n = 0;
4460  for (indexp = using_index; indexp; indexp = indexp->next)
4461  {
4462  /* check for USING INDEX NONE or USING INDEX class.NONE cases */
4463  if (indexp->info.name.original == NULL && indexp->info.name.resolved == NULL)
4464  {
4465  n = 0;
4466  is_none = true;
4467  break; /* USING INDEX NONE case */
4468  }
4469  if (indexp->info.name.original == NULL
4470  && !intl_identifier_casecmp (QO_NODE_NAME (nodep), indexp->info.name.resolved)
4471  && indexp->etc == (void *) PT_IDX_HINT_CLASS_NONE)
4472  {
4473  n = 0; /* USING INDEX class_name.NONE,... case */
4474  is_none = true;
4475  break;
4476  }
4477 
4478  /* check if index is in ignore list (pointer comparison) */
4479  is_ignored = false;
4480  for (j = 0; j < idx_ignore_list_size; j++)
4481  {
4482  if (indexp == idx_ignore_list[j])
4483  {
4484  is_ignored = true;
4485  break;
4486  }
4487  }
4488  if (is_ignored)
4489  {
4490  continue;
4491  }
4492 
4493  /* check index type and count it accordingly */
4494  if (indexp->info.name.original == NULL && indexp->info.name.resolved[0] == '*')
4495  {
4496  n++; /* USING INDEX ALL EXCEPT case */
4497  }
4498  if (indexp->info.name.original && !intl_identifier_casecmp (QO_NODE_NAME (nodep), indexp->info.name.resolved))
4499  {
4500  n++;
4501  }
4502  }
4503  /* if n == 0, it means that either no indexes in USING INDEX clause for this node or USING INDEX NONE case */
4504 
4505  if (n == 0 && !is_none)
4506  {
4507  /* no index for this node in USING INDEX clause, however give it a chance to be assigned an index later */
4508  QO_NODE_USING_INDEX (nodep) = NULL;
4509  continue;
4510  }
4511 
4512  /* allocate QO_USING_INDEX structure */
4513  if (n == 0)
4514  {
4515  uip = (QO_USING_INDEX *) malloc (SIZEOF_USING_INDEX (1));
4516  }
4517  else
4518  {
4519  uip = (QO_USING_INDEX *) malloc (SIZEOF_USING_INDEX (n));
4520  }
4521  QO_NODE_USING_INDEX (nodep) = uip;
4522 
4523  if (uip == NULL)
4524  {
4526  goto cleanup;
4527  }
4528 
4529  QO_UI_N (uip) = n;
4530 
4531  /* USING INDEX NONE, or USING INDEX class_name.NONE,... case */
4532  if (is_none)
4533  {
4534  continue;
4535  }
4536 
4537  /* attach indexes to QO_NODE */
4538  n = 0;
4539  for (indexp = using_index; indexp; indexp = indexp->next)
4540  {
4541  /* check for USING INDEX NONE case */
4542  if (indexp->info.name.original == NULL && indexp->info.name.resolved == NULL)
4543  {
4544  break; /* USING INDEX NONE case */
4545  }
4546 
4547  /* check if index is in ignore list (pointer comparison) */
4548  is_ignored = false;
4549  for (j = 0; j < idx_ignore_list_size; j++)
4550  {
4551  if (indexp == idx_ignore_list[j])
4552  {
4553  is_ignored = true;
4554  break;
4555  }
4556  }
4557  if (is_ignored)
4558  {
4559  continue;
4560  }
4561 
4562  /* attach index if necessary */
4563  if (indexp->info.name.original == NULL && indexp->info.name.resolved[0] == '*')
4564  {
4565  /* USING INDEX ALL EXCEPT case */
4566  QO_UI_INDEX (uip, n) = indexp->info.name.resolved;
4567  QO_UI_FORCE (uip, n++) = (int) (UINT64) (indexp->etc);
4568  }
4569  if (indexp->info.name.original && !intl_identifier_casecmp (QO_NODE_NAME (nodep), indexp->info.name.resolved))
4570  {
4571  QO_UI_INDEX (uip, n) = indexp->info.name.original;
4572  QO_UI_KEYLIMIT (uip, n) = indexp->info.name.indx_key_limit;
4573  QO_UI_FORCE (uip, n++) = (int) (UINT64) (indexp->etc);
4574  }
4575  }
4576  }
4577 
4578 cleanup:
4579  /* free memory of index ignore list */
4580  if (idx_ignore_list != NULL)
4581  {
4582  free (idx_ignore_list);
4583  }
4584 }
4585 
4586 /*
4587  * qo_alloc_index () - Allocate a QO_INDEX structure with room for <n>
4588  * QO_INDEX_ENTRY elements. The fields are initialized
4589  * return: QO_CLASS_INFO *
4590  * env(in): The current optimizer environment
4591  * n(in): The node whose class info we want
4592  */
4593 static QO_INDEX *
4595 {
4596  int i;
4597  QO_INDEX *indexp;
4598  QO_INDEX_ENTRY *entryp;
4599 
4600  indexp = (QO_INDEX *) malloc (SIZEOF_INDEX (n));
4601  if (indexp == NULL)
4602  {
4604  return NULL;
4605  }
4606 
4607  indexp->n = 0;
4608  indexp->max = n;
4609 
4610  for (i = 0; i < n; i++)
4611  {
4612  entryp = QO_INDEX_INDEX (indexp, i);
4613 
4614  entryp->next = NULL;
4615  entryp->class_ = NULL;
4616  entryp->col_num = 0;
4617  entryp->key_type = NULL;
4618  entryp->nsegs = 0;
4619  entryp->seg_idxs = NULL;
4620  entryp->rangelist_seg_idx = -1;
4621  entryp->seg_equal_terms = NULL;
4622  entryp->seg_other_terms = NULL;
4623  bitset_init (&(entryp->terms), env);
4625  entryp->cover_segments = false;
4626  entryp->is_iss_candidate = false;
4627  entryp->first_sort_column = -1;
4628  entryp->orderby_skip = false;
4629  entryp->groupby_skip = false;
4630  entryp->use_descending = false;
4631  entryp->statistics_attribute_name = NULL;
4632  entryp->key_limit = NULL;
4633  entryp->constraints = NULL;
4634  entryp->ils_prefix_len = 0;
4635  entryp->rangelist_term_idx = -1;
4636  bitset_init (&(entryp->index_segs), env);
4637  bitset_init (&(entryp->multi_col_range_segs), env);
4638  }
4639 
4640  return indexp;
4641 }
4642 
4643 /*
4644  * qo_free_index () - Free the QO_INDEX structure and all elements contained
4645  * within it
4646  * return: nothing
4647  * env(in): The current optimizer environment
4648  * indexp(in): A pointer to a previously-allocated index vector
4649  */
4650 static void
4652 {
4653  int i, j;
4654  QO_INDEX_ENTRY *entryp;
4655 
4656  if (!indexp)
4657  {
4658  return;
4659  }
4660 
4661  for (i = 0; i < indexp->max; i++)
4662  {
4663  entryp = QO_INDEX_INDEX (indexp, i);
4664  bitset_delset (&(entryp->terms));
4665  bitset_delset (&(entryp->index_segs));
4666  bitset_delset (&(entryp->multi_col_range_segs));
4667  for (j = 0; j < entryp->nsegs; j++)
4668  {
4669  bitset_delset (&(entryp->seg_equal_terms[j]));
4670  bitset_delset (&(entryp->seg_other_terms[j]));
4671  }
4672  if (entryp->nsegs)
4673  {
4674  if (entryp->seg_equal_terms)
4675  {
4676  free_and_init (entryp->seg_equal_terms);
4677  }
4678  if (entryp->seg_other_terms)
4679  {
4680  free_and_init (entryp->seg_other_terms);
4681  }
4682  if (entryp->seg_idxs)
4683  {
4684  free_and_init (entryp->seg_idxs);
4685  }
4686 
4687  if (entryp->statistics_attribute_name)
4688  {
4690  }
4691  }
4692  entryp->constraints = NULL;
4693  }
4694 
4695  if (indexp)
4696  {
4697  free_and_init (indexp);
4698  }
4699 }
4700 
4701 /*
4702  * qo_get_class_info () -
4703  * return: QO_CLASS_INFO *
4704  * env(in): The current optimizer environment
4705  * node(in): The node whose class info we want
4706  */
4707 static QO_CLASS_INFO *
4709 {
4710  PT_NODE *dom_set;
4711  int n;
4712  QO_CLASS_INFO *info;
4713  QO_CLASS_INFO_ENTRY *end;
4714  int i;
4715 
4716  dom_set = QO_NODE_ENTITY_SPEC (node)->info.spec.flat_entity_list;
4717  n = count_classes (dom_set);
4718  info = (QO_CLASS_INFO *) malloc (SIZEOF_CLASS_INFO (n));
4719  if (info == NULL)
4720  {
4722  return NULL;
4723  }
4724 
4725  for (i = 0; i < n; ++i)
4726  {
4727  info->info[i].name = NULL;
4728  info->info[i].mop = NULL;
4729  info->info[i].smclass = NULL;
4730  info->info[i].stats = NULL;
4731  info->info[i].self_allocated = 0;
4732  OID_SET_NULL (&info->info[i].oid);
4733  info->info[i].index = NULL;
4734  }
4735 
4736  info->n = n;
4737  end = grok_classes (env, dom_set, &info->info[0]);
4738 
4739  QO_ASSERT (env, end == &info->info[n]);
4740 
4741  return info;
4742 
4743 }
4744 
4745 /*
4746  * qo_free_class_info () - Free the vector and all interally-allocated
4747  * structures
4748  * return: nothing
4749  * env(in): The current optimizer environment
4750  * info(in): A pointer to a previously-allocated info vector
4751  */
4752 static void
4754 {
4755  int i;
4756 
4757  if (info == NULL)
4758  {
4759  return;
4760  }
4761 
4762  /*
4763  * The CLASS_STATS structures that are pointed to by the various
4764  * members of info[] will be automatically freed by the garbage
4765  * collector. Make sure that we null out our mop pointer so that the
4766  * garbage collector doesn't mistakenly believe that the class object
4767  * is still in use.
4768  */
4769  for (i = 0; i < info->n; ++i)
4770  {
4771  qo_free_index (env, info->info[i].index);
4772  info->info[i].name = NULL;
4773  info->info[i].mop = NULL;
4774  if (info->info[i].self_allocated)
4775  {
4776  free_and_init (info->info[i].stats);
4777  }
4778  info->info[i].smclass = NULL;
4779  }
4780  if (info)
4781  {
4782  free_and_init (info);
4783  }
4784 }
4785 
4786 /*
4787  * count_classes () - Count the number of object-based classes in the domain set
4788  * return: int
4789  * p(in):
4790  */
4791 static int
4793 {
4794  int n;
4795 
4796  for (n = 0; p; p = p->next)
4797  {
4798  n++;
4799  }
4800 
4801  return n;
4802 }
4803 
4804 /*
4805  * grok_classes () -
4806  * return: QO_CLASS_INFO_ENTRY *
4807  * env(in): The current optimizer environment
4808  * p(in): The flat list of entity_specs
4809  * info(in): The next info slot to be initialized
4810  *
4811  * Note: Populate the info array by traversing the given flat list.
4812  * info is assumed to point to a vector of QO_CLASS_INFO_ENTRY
4813  * structures that is long enough to accept entries for all
4814  * remaining object-based classes. This should be the case if
4815  * the length of the array was determined using count_classes()
4816  * above.
4817  */
4818 static QO_CLASS_INFO_ENTRY *
4820 {
4821  HFID *hfid;
4822  SM_CLASS *smclass;
4823  int is_class = 0;
4824 
4825  for (; p; p = p->next)
4826  {
4827  info->mop = p->info.name.db_object;
4828  is_class = db_is_class (info->mop);
4829  if (is_class < 0)
4830  {
4831  return NULL;
4832  }
4833  info->normal_class = is_class;
4834  if (info->mop)
4835  {
4836  info->oid = *WS_OID (info->mop);
4837  info->name = sm_get_ch_name (info->mop);
4838  info->smclass = sm_get_class_with_statistics (info->mop);
4839  }
4840  else
4841  {
4842  PARSER_CONTEXT *parser = env->parser;
4843  PT_INTERNAL_ERROR (parser, "info");
4844  return info;
4845  }
4846 
4847  smclass = info->smclass;
4848  if (smclass == NULL)
4849  {
4850  PARSER_CONTEXT *parser = env->parser;
4851  PT_INTERNAL_ERROR (parser, "info");
4852  return info;
4853  }
4854 
4855  if (smclass->stats == NULL)
4856  {
4857  info->stats = (CLASS_STATS *) malloc (sizeof (CLASS_STATS));
4858  if (info->stats == NULL)
4859  {
4861  return NULL;
4862  }
4863 
4864  info->self_allocated = 1;
4865  info->stats->n_attrs = 0;
4866  info->stats->attr_stats = NULL;
4867  qo_estimate_statistics (info->mop, info->stats);
4868  }
4869  else if (smclass->stats->heap_num_pages == 0)
4870  {
4871  if (!info->normal_class || ((hfid = sm_get_ch_heap (info->mop)) && !HFID_IS_NULL (hfid)))
4872  {
4873  qo_estimate_statistics (info->mop, smclass->stats);
4874  }
4875  }
4876 
4877  info++;
4878  }
4879 
4880  return info;
4881 }
4882 
4883 /*
4884  * qo_get_attr_info_func_index () - Find the statistics information about
4885  * the function index that underlies this segment
4886  * return: QO_ATTR_INFO *
4887  * env(in): The current optimizer environment
4888  * seg(in): A (pointer to) a join graph segment
4889  * expr_str(in):
4890  */
4891 static QO_ATTR_INFO *
4892 qo_get_attr_info_func_index (QO_ENV * env, QO_SEGMENT * seg, const char *expr_str)
4893 {
4894  QO_NODE *nodep;
4895  QO_CLASS_INFO_ENTRY *class_info_entryp;
4896  SM_CLASS_CONSTRAINT *consp;
4897  QO_ATTR_INFO *attr_infop = NULL;
4898  QO_ATTR_CUM_STATS *cum_statsp;
4899  BTREE_STATS *bstatsp = NULL;
4900  ATTR_STATS *attr_statsp = NULL;
4901  int n, i, j;
4902  int attr_id;
4903  int n_attrs;
4904  CLASS_STATS *stats;
4905 
4906  nodep = QO_SEG_HEAD (seg);
4907 
4908  if (QO_NODE_INFO (nodep) == NULL || !(QO_NODE_INFO (nodep)->info[0].normal_class))
4909  {
4910  /* if there's no class information or the class is not normal class */
4911  return NULL;
4912  }
4913 
4914  /* number of class information entries */
4915  n = QO_NODE_INFO_N (nodep);
4916  QO_ASSERT (env, n > 0);
4917 
4918  /* pointer to QO_CLASS_INFO_ENTRY[] array of the node */
4919  class_info_entryp = &QO_NODE_INFO (nodep)->info[0];
4920 
4921  /* allocate QO_ATTR_INFO within the current optimizer environment */
4922  attr_infop = (QO_ATTR_INFO *) malloc (sizeof (QO_ATTR_INFO));
4923  if (attr_infop == NULL)
4924  {
4926  return NULL;
4927  }
4928 
4929  cum_statsp = &attr_infop->cum_stats;
4930  cum_statsp->type = pt_type_enum_to_db (QO_SEG_PT_NODE (seg)->type_enum);
4931  cum_statsp->valid_limits = false;
4932  cum_statsp->is_indexed = false;
4933  cum_statsp->leafs = cum_statsp->pages = cum_statsp->height = 0;
4934  cum_statsp->keys = 0;
4935  cum_statsp->key_type = NULL;
4936  cum_statsp->pkeys_size = 0;
4937  cum_statsp->pkeys = NULL;
4938 
4939  /* set the statistics from the class information(QO_CLASS_INFO_ENTRY) */
4940  for (i = 0; i < n; class_info_entryp++, i++)
4941  {
4942  stats = QO_GET_CLASS_STATS (class_info_entryp);
4943  QO_ASSERT (env, stats != NULL);
4944  if (stats->attr_stats == NULL)
4945  {
4946  /* the attribute statistics of the class were not set */
4947  continue;
4948  /* We'll consider the segment to be indexed only if all of the attributes it represents are indexed. The
4949  * current optimization strategy makes it inconvenient to try to construct "mixed" (segment and index) scans
4950  * of a node that represents more than one node.
4951  */
4952  }
4953 
4954  for (consp = class_info_entryp->smclass->constraints; consp; consp = consp->next)
4955  {
4956  /* search the attribute from the class information */
4957  attr_statsp = stats->attr_stats;
4958  n_attrs = stats->n_attrs;
4959 
4960  if (consp->index_status != SM_NORMAL_INDEX)
4961  {
4962  /* Skip not normal indexes. */
4963  continue;
4964  }
4965 
4966  if (consp->func_index_info && consp->func_index_info->col_id == 0
4967  && !intl_identifier_casecmp (expr_str, consp->func_index_info->expr_str))
4968  {
4969  attr_id = consp->attributes[0]->id;
4970 
4971  for (j = 0; j < n_attrs; j++, attr_statsp++)
4972  {
4973  if (attr_statsp->id == attr_id)
4974  {
4975  break;
4976  }
4977  }
4978  if (j == n_attrs)
4979  {
4980  /* attribute not found, what happens to the class attribute? */
4981  continue;
4982  }
4983 
4984  bstatsp = attr_statsp->bt_stats;
4985  for (j = 0; j < attr_statsp->n_btstats; j++, bstatsp++)
4986  {
4987  if (BTID_IS_EQUAL (&bstatsp->btid, &consp->index_btid) && bstatsp->has_function == 1)
4988  {
4989  break;
4990  }
4991  }
4992 
4993  if (cum_statsp->valid_limits == false)
4994  {
4995  /* first time */
4996  cum_statsp->valid_limits = true;
4997  }
4998 
4999  /* This should always happen. We must find a matching index. */
5000  assert (j < attr_statsp->n_btstats);
5001 
5002  cum_statsp->is_indexed = true;
5003 
5004  cum_statsp->leafs += bstatsp->leafs;
5005  cum_statsp->pages += bstatsp->pages;
5006  cum_statsp->height = MAX (cum_statsp->height, bstatsp->height);
5007 
5008  if (cum_statsp->pkeys_size == 0 || /* the first found */
5009  cum_statsp->keys < bstatsp->keys)
5010  {
5011  cum_statsp->keys = bstatsp->keys;
5012  cum_statsp->key_type = bstatsp->key_type;
5013  cum_statsp->pkeys_size = bstatsp->pkeys_size;
5014  /* alloc pkeys[] within the current optimizer environment */
5015  if (cum_statsp->pkeys)
5016  {
5017  free_and_init (cum_statsp->pkeys);
5018  }
5019  cum_statsp->pkeys = (int *) malloc (SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5020  if (cum_statsp->pkeys == NULL)
5021  {
5023  SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5024  qo_free_attr_info (env, attr_infop);
5025  return NULL;
5026  }
5027 
5028  assert (cum_statsp->pkeys_size <= BTREE_STATS_PKEYS_NUM);
5029  for (i = 0; i < cum_statsp->pkeys_size; i++)
5030  {
5031  cum_statsp->pkeys[i] = bstatsp->pkeys[i];
5032  }
5033  }
5034  }
5035  }
5036  }
5037 
5038  return attr_infop;
5039 }
5040 
5041 /*
5042  * qo_get_attr_info () - Find the ATTR_STATS information about each actual
5043  * attribute that underlies this segment
5044  * return: QO_ATTR_INFO *
5045  * env(in): The current optimizer environment
5046  * seg(in): A (pointer to) a join graph segment
5047  */
5048 static QO_ATTR_INFO *
5050 {
5051  QO_NODE *nodep;
5052  QO_CLASS_INFO_ENTRY *class_info_entryp;
5053  QO_ATTR_INFO *attr_infop;
5054  int attr_id;
5055  QO_ATTR_CUM_STATS *cum_statsp;
5056  ATTR_STATS *attr_statsp;
5057  BTREE_STATS *bt_statsp;
5058  int n_attrs;
5059  const char *name;
5060  int n, i, j;
5061  int n_func_indexes;
5062  int n_unavail_indexes;
5063  SM_CLASS_CONSTRAINT *consp;
5064  CLASS_STATS *stats;
5065  bool is_reserved_name = false;
5066 
5067  if ((QO_SEG_PT_NODE (seg))->info.name.meta_class == PT_RESERVED)
5068  {
5069  is_reserved_name = true;
5070  }
5071 
5072  /* actual attribute name of the given segment */
5073  name = QO_SEG_NAME (seg);
5074  /* QO_NODE of the given segment */
5075  nodep = QO_SEG_HEAD (seg);
5076 
5077  if (QO_NODE_INFO (nodep) == NULL || !(QO_NODE_INFO (nodep)->info[0].normal_class))
5078  {
5079  /* if there's no class information or the class is not normal class */
5080  return NULL;
5081  }
5082 
5083  /* number of class information entries */
5084  n = QO_NODE_INFO_N (nodep);
5085  QO_ASSERT (env, n > 0);
5086 
5087  /* pointer to QO_CLASS_INFO_ENTRY[] array of the node */
5088  class_info_entryp = &QO_NODE_INFO (nodep)->info[0];
5089 
5090  /* allocate QO_ATTR_INFO within the current optimizer environment */
5091  attr_infop = (QO_ATTR_INFO *) malloc (sizeof (QO_ATTR_INFO));
5092  if (attr_infop == NULL)
5093  {
5095  return NULL;
5096  }
5097 
5098  /* initialize QO_ATTR_CUM_STATS structure of QO_ATTR_INFO */
5099  cum_statsp = &attr_infop->cum_stats;
5100  if (is_reserved_name)
5101  {
5102  cum_statsp->type = pt_Reserved_name_table[(QO_SEG_PT_NODE (seg))->info.name.reserved_id].type;
5103  cum_statsp->valid_limits = false;
5104  cum_statsp->is_indexed = true;
5105  cum_statsp->leafs = cum_statsp->pages = cum_statsp->height = 0;
5106  cum_statsp->keys = 0;
5107  cum_statsp->key_type = NULL;
5108  cum_statsp->pkeys_size = 0;
5109  cum_statsp->pkeys = NULL;
5110 
5111  return attr_infop;
5112  }
5113 
5114  /* not a reserved name */
5115  cum_statsp->type = sm_att_type_id (class_info_entryp->mop, name);
5116  cum_statsp->valid_limits = false;
5117  cum_statsp->is_indexed = true;
5118  cum_statsp->leafs = cum_statsp->pages = cum_statsp->height = 0;
5119  cum_statsp->keys = 0;
5120  cum_statsp->key_type = NULL;
5121  cum_statsp->pkeys_size = 0;
5122  cum_statsp->pkeys = NULL;
5123 
5124  /* set the statistics from the class information(QO_CLASS_INFO_ENTRY) */
5125  for (i = 0; i < n; class_info_entryp++, i++)
5126  {
5127  attr_id = sm_att_id (class_info_entryp->mop, name);
5128 
5129  /* pointer to ATTR_STATS of CLASS_STATS of QO_CLASS_INFO_ENTRY */
5130  stats = QO_GET_CLASS_STATS (class_info_entryp);
5131  QO_ASSERT (env, stats != NULL);
5132  if (stats->attr_stats == NULL)
5133  {
5134  /* the attribute statistics of the class were not set */
5135  cum_statsp->is_indexed = false;
5136  continue;
5137  /* We'll consider the segment to be indexed only if all of the attributes it represents are indexed. The
5138  * current optimization strategy makes it inconvenient to try to construct "mixed" (segment and index) scans
5139  * of a node that represents more than one node.
5140  */
5141  }
5142 
5143  /* The stats vector isn't kept in id order because of the effects of schema updates (attribute deletion, most
5144  * notably). We need to search it to find the stats record we're interested in. Worse, there doesn't even need to
5145  * be an entry for this particular attribute in the vector. If we're dealing with a class that was created after
5146  * the last statistics update, it won't have any information associated with it, or if we're dealing with certain
5147  * kinds of attributes they simply won't be recorded. In these cases we just make the best guess we can.
5148  */
5149 
5150  /* search the attribute from the class information */
5151  attr_statsp = stats->attr_stats;
5152  n_attrs = stats->n_attrs;
5153  for (j = 0; j < n_attrs; j++, attr_statsp++)
5154  {
5155  if (attr_statsp->id == attr_id)
5156  {
5157  break;
5158  }
5159  }
5160  if (j == n_attrs)
5161  {
5162  /* attribute not found, what happens to the class attribute? */
5163  cum_statsp->is_indexed = false;
5164  continue;
5165  }
5166 
5167  if (cum_statsp->valid_limits == false)
5168  {
5169  /* first time */
5170  cum_statsp->type = attr_statsp->type;
5171  cum_statsp->valid_limits = true;
5172  }
5173 
5174  n_func_indexes = 0;
5175  n_unavail_indexes = 0;
5176  for (j = 0; j < attr_statsp->n_btstats; j++)
5177  {
5178  if (attr_statsp->bt_stats[j].has_function == 1)
5179  {
5180  n_func_indexes++;
5181  }
5182 
5183  if (!sm_is_index_visible (class_info_entryp->smclass->constraints, attr_statsp->bt_stats->btid))
5184  {
5185  n_unavail_indexes++;
5186  }
5187  }
5188 
5189  if ((attr_statsp->n_btstats - (n_func_indexes + n_unavail_indexes) <= 0) || (!attr_statsp->bt_stats))
5190  {
5191  /* the attribute does not have any usable index */
5192  cum_statsp->is_indexed = false;
5193  continue;
5194  /* We'll consider the segment to be indexed only if all of the attributes it represents are indexed. The
5195  * current optimization strategy makes it inconvenient to try to construct "mixed" (segment and index) scans
5196  * of a node that represents more than one node.
5197  */
5198  }
5199 
5200  /* Because we cannot know which index will be selected for this attribute when there're more than one indexes on
5201  * this attribute, use the statistics of the MIN keys index.
5202  */
5203  bt_statsp = &attr_statsp->bt_stats[0];
5204  for (j = 1; j < attr_statsp->n_btstats; j++)
5205  {
5206  if (bt_statsp->keys > attr_statsp->bt_stats[j].keys)
5207  {
5208  bt_statsp = &attr_statsp->bt_stats[j];
5209  }
5210  }
5211 
5212  if (QO_NODE_ENTITY_SPEC (nodep)->info.spec.only_all == PT_ALL)
5213  {
5214  /* class hierarchy spec for example: select ... from all p */
5215 
5216  /* check index uniqueness */
5217  for (consp = sm_class_constraints (class_info_entryp->mop); consp; consp = consp->next)
5218  {
5219  if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (consp->type) && BTID_IS_EQUAL (&bt_statsp->btid, &consp->index_btid))
5220  {
5221  break;
5222  }
5223  }
5224 
5225  if (consp && consp->index_status == SM_NORMAL_INDEX) /* is unique index */
5226  {
5227  /* is class hierarchy index: set unique index statistics */
5228  cum_statsp->leafs = bt_statsp->leafs;
5229  cum_statsp->pages = bt_statsp->pages;
5230  cum_statsp->height = bt_statsp->height;
5231  cum_statsp->keys = bt_statsp->keys;
5232  cum_statsp->key_type = bt_statsp->key_type;
5233  cum_statsp->pkeys_size = bt_statsp->pkeys_size;
5234  /* alloc pkeys[] within the current optimizer environment */
5235  if (cum_statsp->pkeys != NULL)
5236  {
5237  free_and_init (cum_statsp->pkeys); /* free alloced */
5238  }
5239  cum_statsp->pkeys = (int *) malloc (SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5240  if (cum_statsp->pkeys == NULL)
5241  {
5243  SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5244  qo_free_attr_info (env, attr_infop);
5245  return NULL;
5246  }
5247 
5248  assert (cum_statsp->pkeys_size <= BTREE_STATS_PKEYS_NUM);
5249  for (j = 0; j < cum_statsp->pkeys_size; j++)
5250  {
5251  cum_statsp->pkeys[j] = bt_statsp->pkeys[j];
5252  }
5253 
5254  /* immediately return the allocated QO_ATTR_INFO */
5255  return attr_infop;
5256  }
5257  }
5258 
5259  /* keep cumulative totals of index statistics */
5260  cum_statsp->leafs += bt_statsp->leafs;
5261  cum_statsp->pages += bt_statsp->pages;
5262  /* Assume that the key distributions overlap here, so that the number of distinct keys in all of the attributes
5263  * equal to the maximum number of distinct keys in any one of the attributes. This is probably not far from the
5264  * truth; it is almost certainly a better guess than assuming that all key ranges are distinct.
5265  */
5266  cum_statsp->height = MAX (cum_statsp->height, bt_statsp->height);
5267  if (cum_statsp->pkeys_size == 0 || /* the first found */
5268  cum_statsp->keys < bt_statsp->keys)
5269  {
5270  cum_statsp->keys = bt_statsp->keys;
5271  cum_statsp->key_type = bt_statsp->key_type;
5272  cum_statsp->pkeys_size = bt_statsp->pkeys_size;
5273  /* alloc pkeys[] within the current optimizer environment */
5274  if (cum_statsp->pkeys)
5275  {
5276  free_and_init (cum_statsp->pkeys);
5277  }
5278  cum_statsp->pkeys = (int *) malloc (SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5279  if (cum_statsp->pkeys == NULL)
5280  {
5282  SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5283  qo_free_attr_info (env, attr_infop);
5284  return NULL;
5285  }
5286 
5287  assert (cum_statsp->pkeys_size <= BTREE_STATS_PKEYS_NUM);
5288  for (j = 0; j < cum_statsp->pkeys_size; j++)
5289  {
5290  cum_statsp->pkeys[j] = bt_statsp->pkeys[j];
5291  }
5292  }
5293 
5294  } /* for (i = 0; i < n; ...) */
5295 
5296  /* return the allocated QO_ATTR_INFO */
5297  return attr_infop;
5298 }
5299 
5300 /*
5301  * qo_free_attr_info () - Free the vector and any internally allocated
5302  * structures
5303  * return: nothing
5304  * env(in): The current optimizer environment
5305  * info(in): A pointer to a previously allocated info vector
5306  */
5307 static void
5309 {
5310  QO_ATTR_CUM_STATS *cum_statsp;
5311 
5312  if (info)
5313  {
5314  cum_statsp = &info->cum_stats;
5315  if (cum_statsp->pkeys)
5316  {
5317  free_and_init (cum_statsp->pkeys);
5318  }
5319  free_and_init (info);
5320  }
5321 }
5322 
5323 /*
5324  * qo_get_index_info () - Get index statistical information
5325  * return:
5326  * env(in): The current optimizer environment
5327  * node(in): A join graph node
5328  */
5329 static void
5331 {
5332  QO_NODE_INDEX *node_indexp;
5333  QO_NODE_INDEX_ENTRY *ni_entryp;
5334  QO_INDEX_ENTRY *index_entryp;
5335  QO_ATTR_CUM_STATS *cum_statsp;
5336  QO_SEGMENT *segp;
5337  QO_NODE *seg_node;
5338  QO_CLASS_INFO_ENTRY *class_info_entryp = NULL;
5339  const char *name;
5340  int attr_id, n_attrs;
5341  ATTR_STATS *attr_statsp;
5342  BTREE_STATS *bt_statsp;
5343  int i, j, k;
5344  CLASS_STATS *stats;
5345 
5346  /* pointer to QO_NODE_INDEX structure of QO_NODE */
5347  node_indexp = QO_NODE_INDEXES (node);
5348 
5349  /* for each index list(linked list of QO_INDEX_ENTRY) rooted at the node (all elements of QO_NODE_INDEX_ENTRY[]
5350  * array) */
5351  for (i = 0, ni_entryp = QO_NI_ENTRY (node_indexp, 0); i < QO_NI_N (node_indexp); i++, ni_entryp++)
5352  {
5353  cum_statsp = &(ni_entryp)->cum_stats;
5354  cum_statsp->is_indexed = true;
5355 
5356  /* The linked list of QO_INDEX_ENTRY was built by 'qo_find_node_index()' function. It is the list of compatible
5357  * indexes under class hierarchy.
5358  */
5359  /* for each index entry(QO_INDEX_ENTRY) on the list, acquire the statistics and cumulate them */
5360  for (j = 0, index_entryp = (ni_entryp)->head; index_entryp != NULL; j++, index_entryp = index_entryp->next)
5361  {
5362  /* The index information is associated with the first attribute of index keys in the case of multi-column
5363  * index and 'seg_idx[]' array of QO_INDEX_ENTRY structure was built by 'qo_find_index_seg_and_term()'
5364  * function to keep the order of index key attributes. So, 'seg_idx[0]' is the right segment denoting the
5365  * attribute that contains the index statistics that we want to get. If seg_idx[0] is null (-1), then the
5366  * name of the first attribute is taken from index_entryp->statistics_attribute_name
5367  */
5368  segp = NULL;
5369  for (k = 0; k < index_entryp->nsegs; k++)
5370  {
5371  if (index_entryp->seg_idxs[k] != -1)
5372  {
5373  segp = QO_ENV_SEG (env, (index_entryp->seg_idxs[k]));
5374 
5375  if (segp != NULL)
5376  {
5377  break;
5378  }
5379  }
5380  }
5381 
5382  if (segp == NULL)
5383  {
5384  index_entryp->key_type = NULL;
5385  continue;
5386  }
5387 
5388  /* QO_NODE of the given segment */
5389  seg_node = QO_SEG_HEAD (segp);
5390 
5391  if (k == 0)
5392  {
5393  /* actual attribute name of the given segment */
5394  name = QO_SEG_NAME (segp);
5395  }
5396  else
5397  {
5398  /* actual attribute name of the given segment */
5399  name = index_entryp->statistics_attribute_name;
5400  }
5401 
5402  /* pointer to QO_CLASS_INFO_ENTRY[] array of the node */
5403  class_info_entryp = &QO_NODE_INFO (seg_node)->info[j];
5404 
5405  /* pointer to ATTR_STATS of CLASS_STATS of QO_CLASS_INFO_ENTRY */
5406  stats = QO_GET_CLASS_STATS (class_info_entryp);
5407  QO_ASSERT (env, stats != NULL);
5408 
5409  /* search the attribute from the class information */
5410  attr_statsp = stats->attr_stats;
5411  n_attrs = stats->n_attrs;
5412 
5413  if (!index_entryp->is_func_index)
5414  {
5415  attr_id = sm_att_id (class_info_entryp->mop, name);
5416  }
5417  else
5418  {
5419  /* function index with the function expression as the first attribute */
5420  attr_id = index_entryp->constraints->attributes[0]->id;
5421  }
5422 
5423  for (k = 0; k < n_attrs; k++, attr_statsp++)
5424  {
5425  if (attr_statsp->id == attr_id)
5426  {
5427  break;
5428  }
5429  }
5430 
5431  index_entryp->key_type = NULL;
5432  if (k >= n_attrs) /* not found */
5433  {
5434  attr_statsp = NULL;
5435  continue;
5436  }
5437 
5438  if (cum_statsp->valid_limits == false)
5439  {
5440  /* first time */
5441  cum_statsp->type = attr_statsp->type;
5442  cum_statsp->valid_limits = true;
5443  }
5444 
5445  /* find the index that we are interesting within BTREE_STATS[] array */
5446  bt_statsp = attr_statsp->bt_stats;
5447  for (k = 0; k < attr_statsp->n_btstats; k++, bt_statsp++)
5448  {
5449  if (BTID_IS_EQUAL (&bt_statsp->btid, &(index_entryp->constraints->index_btid)))
5450  {
5451  if (!index_entryp->is_func_index || bt_statsp->has_function == 1)
5452  {
5453  index_entryp->key_type = bt_statsp->key_type;
5454  break;
5455  }
5456  }
5457  } /* for (k = 0, ...) */
5458 
5459  if (k == attr_statsp->n_btstats)
5460  {
5461  /* cannot find index in this attribute. what happens? */
5462  continue;
5463  }
5464 
5465  if (QO_NODE_ENTITY_SPEC (node)->info.spec.only_all == PT_ALL)
5466  {
5467  /* class hierarchy spec for example: select ... from all p */
5468 
5469  /* check index uniqueness */
5470  if (SM_IS_CONSTRAINT_UNIQUE_FAMILY (index_entryp->constraints->type))
5471  {
5472  /* is class hierarchy index: set unique index statistics */
5473  cum_statsp->leafs = bt_statsp->leafs;
5474  cum_statsp->pages = bt_statsp->pages;
5475  cum_statsp->height = bt_statsp->height;
5476  cum_statsp->keys = bt_statsp->keys;
5477  cum_statsp->key_type = bt_statsp->key_type;
5478  cum_statsp->pkeys_size = bt_statsp->pkeys_size;
5479  /* alloc pkeys[] within the current optimizer environment */
5480  if (cum_statsp->pkeys)
5481  {
5482  free_and_init (cum_statsp->pkeys);
5483  }
5484  cum_statsp->pkeys = (int *) malloc (SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5485  if (cum_statsp->pkeys == NULL)
5486  {
5488  SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5489  return; /* give up */
5490  }
5491 
5492  assert (cum_statsp->pkeys_size <= BTREE_STATS_PKEYS_NUM);
5493  for (k = 0; k < cum_statsp->pkeys_size; k++)
5494  {
5495  cum_statsp->pkeys[k] = bt_statsp->pkeys[k];
5496  }
5497 
5498  /* immediately finish getting index statistics */
5499  break; /* for (j = 0, ... ) */
5500  }
5501  }
5502 
5503  /* keep cumulative totals of index statistics */
5504  cum_statsp->leafs += bt_statsp->leafs;
5505  cum_statsp->pages += bt_statsp->pages;
5506  /* Assume that the key distributions overlap here, so that the number of distinct keys in all of the
5507  * attributes equal to the maximum number of distinct keys in any one of the attributes. This is probably not
5508  * far from the truth; it is almost certainly a better guess than assuming that all key ranges are distinct.
5509  */
5510  cum_statsp->height = MAX (cum_statsp->height, bt_statsp->height);
5511  if (cum_statsp->pkeys_size == 0 || /* the first found */
5512  cum_statsp->keys < bt_statsp->keys)
5513  {
5514  cum_statsp->keys = bt_statsp->keys;
5515  cum_statsp->key_type = bt_statsp->key_type;
5516  cum_statsp->pkeys_size = bt_statsp->pkeys_size;
5517  /* alloc pkeys[] within the current optimizer environment */
5518  if (cum_statsp->pkeys)
5519  {
5520  free_and_init (cum_statsp->pkeys);
5521  }
5522  cum_statsp->pkeys = (int *) malloc (SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5523  if (cum_statsp->pkeys == NULL)
5524  {
5526  SIZEOF_ATTR_CUM_STATS_PKEYS (cum_statsp->pkeys_size));
5527  return; /* give up */
5528  }
5529 
5530  assert (cum_statsp->pkeys_size <= BTREE_STATS_PKEYS_NUM);
5531  for (k = 0; k < cum_statsp->pkeys_size; k++)
5532  {
5533  cum_statsp->pkeys[k] = bt_statsp->pkeys[k];
5534  }
5535  }
5536  } /* for (j = 0, ... ) */
5537  } /* for (i = 0, ...) */
5538 }
5539 
5540 /*
5541  * qo_free_node_index_info () - Free the vector and any internally allocated
5542  * structures
5543  * return: nothing
5544  * env(in): The current optimizer environment
5545  * node_indexp(in): A pointer to QO_NODE_INDEX structure of QO_NODE
5546  */
5547 static void
5549 {
5550  QO_NODE_INDEX_ENTRY *ni_entryp;
5551  QO_ATTR_CUM_STATS *cum_statsp;
5552  int i;
5553 
5554  if (node_indexp)
5555  {
5556  /* for each index list(linked list of QO_INDEX_ENTRY) rooted at the node (all elements of QO_NODE_INDEX_ENTRY[]
5557  * array) */
5558  for (i = 0, ni_entryp = QO_NI_ENTRY (node_indexp, 0); i < QO_NI_N (node_indexp); i++, ni_entryp++)
5559  {
5560  cum_statsp = &(ni_entryp)->cum_stats;
5561  if (cum_statsp->pkeys)
5562  {
5563  free_and_init (cum_statsp->pkeys);
5564  }
5565  }
5566 
5567  free_and_init (node_indexp);
5568  }
5569 }
5570 
5571 /*
5572  * qo_data_compare () -
5573  * return: 1, 0, -1
5574  * data1(in):
5575  * data2(in):
5576  * type(in):
5577  *
5578  * Note: This is a simplified function that works with DB_DATA
5579  * instead of DB_VALUE, which is the same function of 'qst_data_compare()'.
5580  */
5581 static int
5582 qo_data_compare (DB_DATA * data1, DB_DATA * data2, DB_TYPE type)
5583 {
5584  int result;
5585 
5586  switch (type)
5587  {
5588  case DB_TYPE_INTEGER:
5589  result = (data1->i < data2->i) ? -1 : ((data1->i > data2->i) ? 1 : 0);
5590  break;
5591  case DB_TYPE_SHORT:
5592  result = ((data1->sh < data2->sh) ? -1 : ((data1->sh > data2->sh) ? 1 : 0));
5593  break;
5594  case DB_TYPE_BIGINT:
5595  result = ((data1->bigint < data2->bigint) ? -1 : ((data1->bigint > data2->bigint) ? 1 : 0));
5596  break;
5597  case DB_TYPE_FLOAT:
5598  result = (data1->f < data2->f) ? -1 : ((data1->f > data2->f) ? 1 : 0);
5599  break;
5600  case DB_TYPE_DOUBLE:
5601  result = (data1->d < data2->d) ? -1 : ((data1->d > data2->d) ? 1 : 0);
5602  break;
5603  case DB_TYPE_DATE:
5604  result = ((data1->date < data2->date) ? -1 : ((data1->date > data2->date) ? 1 : 0));
5605  break;
5606  case DB_TYPE_TIME:
5607  result = ((data1->time < data2->time) ? -1 : ((data1->time > data2->time) ? 1 : 0));
5608  break;
5609 
5610  case DB_TYPE_TIMESTAMPLTZ:
5611  case DB_TYPE_TIMESTAMP:
5612  result = ((data1->utime < data2->utime) ? -1 : ((data1->utime > data2->utime) ? 1 : 0));
5613  break;
5614  case DB_TYPE_TIMESTAMPTZ:
5615  result = ((data1->timestamptz.timestamp < data2->timestamptz.timestamp)
5616  ? -1 : ((data1->timestamptz.timestamp > data2->timestamptz.timestamp) ? 1 : 0));
5617  break;
5618  case DB_TYPE_DATETIMELTZ:
5619  case DB_TYPE_DATETIME:
5620  if (data1->datetime.date < data2->datetime.date)
5621  {
5622  result = -1;
5623  }
5624  else if (data1->datetime.date > data2->datetime.date)
5625  {
5626  result = 1;
5627  }
5628  else if (data1->datetime.time < data2->datetime.time)
5629  {
5630  result = -1;
5631  }
5632  else if (data1->datetime.time > data2->datetime.time)
5633  {
5634  result = 1;
5635  }
5636  else
5637  {
5638  result = 0;
5639  }
5640  break;
5641  case DB_TYPE_DATETIMETZ:
5642  if (data1->datetimetz.datetime.date < data2->datetimetz.datetime.date)
5643  {
5644  result = -1;
5645  }
5646  else if (data1->datetimetz.datetime.date > data2->datetimetz.datetime.date)
5647  {
5648  result = 1;
5649  }
5650  else if (data1->datetimetz.datetime.time < data2->datetimetz.datetime.time)
5651  {
5652  result = -1;
5653  }
5654  else if (data1->datetimetz.datetime.time > data2->datetimetz.datetime.time)
5655  {
5656  result = 1;
5657  }
5658  else
5659  {
5660  result = 0;
5661  }
5662  break;
5663  case DB_TYPE_MONETARY:
5664  result = ((data1->money.amount < data2->money.amount)
5665  ? -1 : ((data1->money.amount > data2->money.amount) ? 1 : 0));
5666  break;
5667  default:
5668  /* not numeric type */
5669  result = 0;
5670  break;
5671  }
5672 
5673  return result;
5674 }
5675 
5676 /*
5677  * qo_estimate_statistics () - Make a wild-ass guess at the appropriate
5678  * statistics for this class. The statistics
5679  * manager doesn't know anything about this class,
5680  * so we're on our own.
5681  * return: nothing
5682  * class_mop(in): The mop of the class whose statistics need to be
5683  fabricated
5684  * statblock(in): The CLASS_STATS structure to be populated
5685  */
5686 static void
5687 qo_estimate_statistics (MOP class_mop, CLASS_STATS * statblock)
5688 {
5689  /*
5690  * It would be nice if we could the get the actual number of pages
5691  * allocated for the class; at least then we could make some sort of
5692  * realistic guess at the upper bound of the number of objects (we
5693  * can already figure out the "average" size of an object).
5694  *
5695  * Really, the statistics manager ought to be doing this on its own.
5696  */
5697 
5698  statblock->heap_num_pages = NOMINAL_HEAP_SIZE (class_mop);
5699  statblock->heap_num_objects = (statblock->heap_num_pages * DB_PAGESIZE) / NOMINAL_OBJECT_SIZE (class_mop);
5700 
5701 }
5702 
5703 /*
5704  * qo_env_new () -
5705  * return:
5706  * parser(in):
5707  * query(in):
5708  */
5709 static QO_ENV *
5711 {
5712  QO_ENV *env;
5713  PT_NODE *spec;
5714 
5715  env = (QO_ENV *) malloc (sizeof (QO_ENV));
5716  if (env == NULL)
5717  {
5719  return NULL;
5720  }
5721 
5722  env->parser = parser;
5723  env->pt_tree = query;
5724  env->nsegs = 0;
5725  env->nnodes = 0;
5726  env->nedges = 0;
5727  env->neqclasses = 0;
5728  env->nterms = 0;
5729  env->nsubqueries = 0;
5730  env->npartitions = 0;
5731  env->final_plan = NULL;
5732  env->segs = NULL;
5733  env->nodes = NULL;
5734  env->eqclasses = NULL;
5735  env->terms = NULL;
5736  env->subqueries = NULL;
5737  env->partitions = NULL;
5738  bitset_init (&(env->final_segs), env);
5739  env->tmp_bitset = NULL;
5740  env->bail_out = 0;
5741  env->planner = NULL;
5743  bitset_init (&(env->fake_terms), env);
5744  bitset_init (&QO_ENV_SORT_LIMIT_NODES (env), env);
5746 
5747  assert (query->node_type == PT_SELECT);
5750  || ((spec = query->info.query.q.select.from) != NULL && spec->info.spec.derived_table_type == PT_IS_SHOWSTMT))
5751  {
5752  env->plan_dump_enabled = false;
5753  }
5754  else
5755  {
5756  env->plan_dump_enabled = true;
5757  }
5758  env->multi_range_opt_candidate = false;
5759 
5760  return env;
5761 }
5762 
5763 #if 0
5764 /*
5765  * qo_malloc () - Try to allocate the requested number of bytes. If that
5766  * fails, throw to some enclosing unwind-protect handler
5767  * return: void *
5768  * env(in): The optimizer environment from which the request is issued
5769  * size(in): The number of bytes requested
5770  * file(in): The file from which qo_malloc() was called
5771  * line(in): The line number of from which qo_malloc() was called
5772  */
5773 void *
5774 qo_malloc (QO_ENV * env, unsigned size, const char *file, int line)
5775 {
5776  void *p;
5777 
5778  p = malloc (size);
5779  if (p == NULL)
5780  {
5781  longjmp (env->catch, 1);
5782  }
5783  return p;
5784 
5785 }
5786 #endif
5787 
5788 /*
5789  * qo_abort () -
5790  * return:
5791  * env(in):
5792  * file(in):
5793  * line(in):
5794  */
5795 void
5796 qo_abort (QO_ENV * env, const char *file, int line)
5797 {
5798  er_set (ER_WARNING_SEVERITY, file, line, ER_FAILED_ASSERTION, 1, "false");
5799  longjmp (env->catch_, 2);
5800 }
5801 
5802 /*
5803  * qo_env_free () -
5804  * return:
5805  * env(in):
5806  */
5807 void
5809 {
5810  if (env)
5811  {
5812  int i;
5813 
5814  /*
5815  * Be sure to use Nnodes, Nterms, and Nsegs as the loop limits in
5816  * the code below, because those are the sizes of the allocated
5817  * arrays; nnodes, nterms, and nsegs are the extents of those
5818  * arrays that were actually used, but the entries past those
5819  * extents need to be cleaned up too.
5820  */
5821 
5822  if (env->segs)
5823  {
5824  for (i = 0; i < env->Nsegs; ++i)
5825  {
5826  qo_seg_free (QO_ENV_SEG (env, i));
5827  }
5828  free_and_init (env->segs);
5829  }
5830 
5831  if (env->nodes)
5832  {
5833  for (i = 0; i < env->Nnodes; ++i)
5834  {
5835  qo_node_free (QO_ENV_NODE (env, i));
5836  }
5837  free_and_init (env->nodes);
5838  }
5839 
5840  if (env->eqclasses)
5841  {
5842  for (i = 0; i < env->neqclasses; ++i)
5843  {
5844  qo_eqclass_free (QO_ENV_EQCLASS (env, i));
5845  }
5846  free_and_init (env->eqclasses);
5847  }
5848 
5849  if (env->terms)
5850  {
5851  for (i = 0; i < env->Nterms; ++i)
5852  {
5853  qo_term_free (QO_ENV_TERM (env, i));
5854  }
5855  free_and_init (env->terms);
5856  }
5857 
5858  if (env->partitions)
5859  {
5860  for (i = 0; i < env->npartitions; ++i)
5861  {
5863  }
5864  free_and_init (env->partitions);
5865  }
5866 
5867  if (env->subqueries)
5868  {
5869  for (i = 0; i < env->nsubqueries; ++i)
5870  {
5871  qo_subquery_free (&env->subqueries[i]);
5872  }
5873  free_and_init (env->subqueries);
5874  }
5875 
5876  bitset_delset (&(env->final_segs));
5877  bitset_delset (&(env->fake_terms));
5880 
5881  if (env->planner)
5882  {
5883  qo_planner_free (env->planner);
5884  }
5885 
5886  free_and_init (env);
5887  }
5888 }
5889 
5890 /*
5891  * qo_exchange () -
5892  * return:
5893  * t0(in):
5894  * t1(in):
5895  */
5896 static void
5898 {
5899 
5900  /*
5901  * 'env' attribute is the same in both, don't bother with it.
5902  */
5904  BISET_EXCHANGE (t0->nodes, t1->nodes);
5905  BISET_EXCHANGE (t0->segments, t1->segments);
5907  INT_EXCHANGE (t0->rank, t1->rank);
5908  PT_NODE_EXCHANGE (t0->pt_expr, t1->pt_expr);
5909  INT_EXCHANGE (t0->location, t1->location);
5913  SEGMENTPTR_EXCHANGE (t0->index_seg[0], t1->index_seg[0]);
5914  SEGMENTPTR_EXCHANGE (t0->index_seg[1], t1->index_seg[1]);
5915  SEGMENTPTR_EXCHANGE (t0->seg, t1->seg);
5916  SEGMENTPTR_EXCHANGE (t0->oid_seg, t1->oid_seg);
5917  NODEPTR_EXCHANGE (t0->head, t1->head);
5918  NODEPTR_EXCHANGE (t0->tail, t1->tail);
5919  EQCLASSPTR_EXCHANGE (t0->eqclass, t1->eqclass);
5921  FLAG_EXCHANGE (t0->flag, t1->flag);
5924  /*
5925  * DON'T exchange the 'idx' values!
5926  */
5927 }
5928 
5929 /*
5930  * qo_discover_edges () -
5931  * return:
5932  * env(in):
5933  */
5934 static void
5936 {
5937  int i, j, n;
5938  QO_TERM *term, *edge, *edge2;
5939  QO_NODE *node;
5940  PT_NODE *pt_expr;
5941  int t;
5942  BITSET_ITERATOR iter;
5943  BITSET direct_nodes;
5944  int t1, t2;
5945  QO_TERM *term1, *term2;
5946 
5947  bitset_init (&direct_nodes, env);
5948 
5949  i = 0;
5950  n = env->nterms;
5951 
5952  while (i < n)
5953  {
5954  term = QO_ENV_TERM (env, i);
5955  if (QO_IS_EDGE_TERM (term))
5956  {
5957  env->nedges++;
5958  i++;
5959  }
5960  else
5961  {
5962  if (i < --n)
5963  {
5964  /*
5965  * Exchange the terms at the two boundaries. This moves
5966  * a known non-edge up to just below the section of other
5967  * non-edge terms, and moves a term of unknown "edgeness"
5968  * down to just above the section of known edges. Leave
5969  * the bottom boundary alone, but move the upper boundary
5970  * down one notch.
5971  */
5972  qo_exchange (QO_ENV_TERM (env, i), QO_ENV_TERM (env, n));
5973  }
5974  }
5975  }
5976 
5977  /* sort join-term on selectivity as descending order */
5978  for (t1 = 0; t1 < i - 1; t1++)
5979  {
5980  term1 = QO_ENV_TERM (env, t1);
5981  for (t2 = t1 + 1; t2 < i; t2++)
5982  {
5983  term2 = QO_ENV_TERM (env, t2);
5984  if (QO_TERM_SELECTIVITY (term1) < QO_TERM_SELECTIVITY (term2))
5985  {
5986  qo_exchange (term1, term2);
5987  }
5988  }
5989  }
5990  /* sort sarg-term on selectivity as descending order */
5991  for (t1 = i; t1 < env->nterms - 1; t1++)
5992  {
5993  term1 = QO_ENV_TERM (env, t1);
5994  for (t2 = t1 + 1; t2 < env->nterms; t2++)
5995  {
5996  term2 = QO_ENV_TERM (env, t2);
5997  if (QO_TERM_SELECTIVITY (term1) < QO_TERM_SELECTIVITY (term2))
5998  {
5999  qo_exchange (term1, term2);
6000  }
6001  }
6002  }
6003 
6004  for (n = env->nterms; i < n; i++)
6005  {
6006  term = QO_ENV_TERM (env, i);
6007  if (QO_TERM_CLASS (term) == QO_TC_SARG)
6008  {
6009  QO_ASSERT (env, bitset_cardinality (&(QO_TERM_NODES (term))) == 1);
6011  }
6012  }
6013 
6014  /*
6015  * Check some invariants. If something has gone wrong during the
6016  * discovery phase to violate these invariants, it will mean certain
6017  * death for later phases, so we need to discover it now while it's
6018  * convenient.
6019  */
6020  for (i = 0, n = env->nedges; i < n; i++)
6021  {
6022  edge = QO_ENV_TERM (env, i);
6023  QO_ASSERT (env, QO_TERM_HEAD (edge) != NULL);
6024  QO_ASSERT (env, QO_TERM_TAIL (edge) != NULL);
6025 
6026  if (QO_TERM_JOIN_TYPE (edge) != JOIN_INNER && QO_TERM_CLASS (edge) != QO_TC_JOIN)
6027  {
6028  for (j = 0; j < n; j++)
6029  {
6030  edge2 = QO_ENV_TERM (env, j);
6031  if (i != j && bitset_is_equivalent (&(QO_TERM_NODES (edge)), &(QO_TERM_NODES (edge2))))
6032  {
6033  QO_TERM_JOIN_TYPE (edge2) = QO_TERM_JOIN_TYPE (edge);
6034  }
6035  }
6036  }
6037 
6038  pt_expr = QO_TERM_PT_EXPR (edge);
6039 
6040  /* check for always true transitive join term */
6041  if (pt_expr && PT_EXPR_INFO_IS_FLAGED (pt_expr, PT_EXPR_INFO_TRANSITIVE))
6042  {
6043  BITSET_CLEAR (direct_nodes);
6044 
6045  for (j = 0; j < n; j++)
6046  {
6047  edge2 = QO_ENV_TERM (env, j);
6048  if (bitset_intersects (&(QO_TERM_NODES (edge2)), &(QO_TERM_NODES (edge))))
6049  {
6050  bitset_union (&direct_nodes, &(QO_TERM_NODES (edge2)));
6051  }
6052  } /* for (j = 0; ...) */
6053 
6054  /* check for direct connected nodes */
6055  for (t = bitset_iterate (&direct_nodes, &iter); t != -1; t = bitset_next_member (&iter))
6056  {
6057  node = QO_ENV_NODE (env, t);
6058  if (!QO_NODE_SARGABLE (node))
6059  {
6060  break; /* give up */
6061  }
6062  }
6063 
6064  /* found dummy join edge. it is used for planning only */
6065  if (t == -1)
6066  {
6068 
6069  /* keep out from m-join edge */
6071  }
6072  }
6073  }
6074 
6075  bitset_delset (&direct_nodes);
6076 }
6077 
6078 /*
6079  * qo_classify_outerjoin_terms () -
6080  * return:
6081  * env(in):
6082  *
6083  * Note:
6084  * Term Classify Matrix
6085  * --+-----+---------------------+----------+---------------+------------------
6086  * NO|Major|Minor |nidx_self |dep_set | Classify
6087  * --+-----+---------------------+----------+---------------+------------------
6088  * O1|ON |TC_sarg(on_conn) |!Right |!Outer(ex R_on)|TC_sarg(ow TC_dj)
6089  * O2|ON |TC_join |term_tail=|=on_node |TC_join(ow O3)
6090  * O3|ON |TC_other(n>0,on_conn)|- |!Outer(ex R_on)|TC_dj
6091  * O4|ON |TC_other(n==0) |- |- |TC_dj
6092  * W1|WHERE|TC_sarg |!Left |!Right |TC_sarg(ow TC_aj)
6093  * W2|WHERE|TC_join |!Outer |!Right |TC_join(ow TC_aj)
6094  * W3|WHERE|TC_other(n>0) |!Outer |!Right |TC_other(ow TC_aj)
6095  * W4|WHERE|TC_other(n==0) |- |- |TC_aj
6096  * --+-----+---------------------+----------+---------------+------------------
6097  */
6098 static void
6100 {
6101  bool is_null_padded, is_outerjoin_for_or_pred;
6102  int n, i, t;
6103  BITSET_ITERATOR iter;
6104  QO_NODE *node, *on_node;
6105  QO_TERM *term;
6106  int nidx_self; /* node index of term */
6107  BITSET dep_set, prev_dep_set;
6108 
6109  for (i = 0; i < env->nterms; i++)
6110  {
6111  term = QO_ENV_TERM (env, i);
6112  QO_ASSERT (env, QO_TERM_LOCATION (term) >= 0);
6113 
6114  if (QO_OUTER_JOIN_TERM (term))
6115  {
6116  break;
6117  }
6118  }
6119 
6120  if (i >= env->nterms)
6121  {
6122  return; /* not found outer join term; do nothing */
6123  }
6124 
6125  bitset_init (&dep_set, env);
6126  bitset_init (&prev_dep_set, env);
6127 
6128  for (i = 0; i < env->nterms; i++)
6129  {
6130  term = QO_ENV_TERM (env, i);
6131  QO_ASSERT (env, QO_TERM_LOCATION (term) >= 0);
6132 
6133  on_node = QO_ENV_NODE (env, QO_TERM_LOCATION (term));
6134  QO_ASSERT (env, on_node != NULL);
6135 
6136  if (QO_ON_COND_TERM (term))
6137  {
6138  QO_ASSERT (env, QO_NODE_IDX (on_node) > 0);
6139  QO_ASSERT (env, QO_NODE_LOCATION (on_node) > 0);
6140  QO_ASSERT (env, QO_NODE_PT_JOIN_TYPE (on_node) != PT_JOIN_NONE);
6141 
6142  /* is explicit join ON cond */
6143  QO_ASSERT (env, QO_TERM_LOCATION (term) == QO_NODE_LOCATION (on_node));
6144 
6145  if (QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_INNER)
6146  {
6147  continue; /* is inner join; no need to classify */
6148  }
6149 
6150  /* is explicit outer-joined ON cond */
6151  QO_ASSERT (env, QO_NODE_IS_OUTER_JOIN (on_node));
6152  }
6153  else
6154  {
6155  QO_ASSERT (env, QO_NODE_IDX (on_node) == 0);
6156  QO_ASSERT (env, QO_NODE_LOCATION (on_node) == 0);
6157  QO_ASSERT (env, QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_NONE);
6158  }
6159 
6160  nidx_self = -1; /* init */
6161  is_outerjoin_for_or_pred = false;
6162  for (t = bitset_iterate (&(QO_TERM_NODES (term)), &iter); t != -1; t = bitset_next_member (&iter))
6163  {
6164  node = QO_ENV_NODE (env, t);
6165  nidx_self = MAX (nidx_self, QO_NODE_IDX (node));
6167  {
6168  is_outerjoin_for_or_pred = true; /* for OR predicate */
6169  }
6170  }
6171  QO_ASSERT (env, nidx_self < env->nnodes);
6172 
6173  /* nidx_self is -1 iff term nodes is empty */
6174 
6175  /* STEP 1: check nidx_self */
6176  if (QO_TERM_CLASS (term) == QO_TC_SARG)
6177  {
6178  QO_ASSERT (env, nidx_self >= 0);
6179 
6180  node = QO_ENV_NODE (env, nidx_self);
6181 
6182  if (QO_ON_COND_TERM (term))
6183  {
6186  {
6188  }
6189  }
6190  else
6191  {
6194  {
6196  }
6197  }
6198  }
6199  else if (QO_TERM_CLASS (term) == QO_TC_JOIN)
6200  {
6201  QO_ASSERT (env, nidx_self >= 0);
6202 
6203  node = QO_ENV_NODE (env, nidx_self);
6204 
6205  if (QO_ON_COND_TERM (term))
6206  {
6207  /* is already checked at qo_analyze_term () */
6208  QO_ASSERT (env, QO_NODE_IDX (QO_TERM_TAIL (term)) == QO_NODE_IDX (on_node));
6209  QO_ASSERT (env, QO_NODE_IDX (QO_TERM_HEAD (term)) < QO_NODE_IDX (QO_TERM_TAIL (term)));
6210  }
6211  else
6212  {
6213  if (QO_NODE_IS_OUTER_JOIN (node) || is_outerjoin_for_or_pred)
6214  {
6216 
6217  QO_TERM_JOIN_TYPE (term) = NO_JOIN;
6218 
6219  /* keep out from m-join edge */
6221  }
6222  }
6223  }
6224  else if (QO_TERM_CLASS (term) == QO_TC_OTHER)
6225  {
6226  if (nidx_self >= 0)
6227  {
6228  node = QO_ENV_NODE (env, nidx_self);
6229  if (QO_NODE_IS_OUTER_JOIN (node) || is_outerjoin_for_or_pred)
6230  {
6231  if (QO_ON_COND_TERM (term))
6232  {
6234  }
6235  else
6236  {
6238  }
6239  }
6240  }
6241  else
6242  {
6243  if (QO_ON_COND_TERM (term))
6244  {
6246  }
6247  else
6248  {
6250  }
6251  }
6252  }
6253 
6254  if (!
6255  (QO_TERM_CLASS (term) == QO_TC_SARG || QO_TERM_CLASS (term) == QO_TC_JOIN
6256  || QO_TERM_CLASS (term) == QO_TC_OTHER))
6257  {
6258  continue; /* no need to classify */
6259  }
6260 
6261  /* traverse outer-dep nodeset */
6262 
6263  QO_ASSERT (env, nidx_self >= 0);
6264 
6265  is_null_padded = false; /* init */
6266 
6267  BITSET_CLEAR (dep_set);
6268 
6269  bitset_add (&dep_set, nidx_self);
6270 
6271  do
6272  {
6273  bitset_assign (&prev_dep_set, &dep_set);
6274 
6275  for (n = 0; n < env->nnodes; n++)
6276  {
6277  node = QO_ENV_NODE (env, n);
6278 
6279  if (bitset_intersects (&dep_set, &(QO_NODE_OUTER_DEP_SET (node))))
6280  {
6281  bitset_add (&dep_set, QO_NODE_IDX (node));
6282  }
6283  }
6284  }
6285  while (!bitset_is_equivalent (&prev_dep_set, &dep_set));
6286 
6287  /* STEP 2: check iff term nodes are connected with ON cond */
6288  if (QO_ON_COND_TERM (term))
6289  {
6290  if (!BITSET_MEMBER (dep_set, QO_NODE_IDX (on_node)))
6291  {
6292  is_null_padded = true;
6293  }
6294  }
6295 
6296  /* STEP 3: check outer-dep nodeset join type */
6297  bitset_remove (&dep_set, nidx_self); /* remove me */
6298  if (QO_ON_COND_TERM (term))
6299  {
6300  QO_ASSERT (env, QO_TERM_LOCATION (term) == QO_NODE_LOCATION (on_node));
6301 
6302  if (QO_NODE_PT_JOIN_TYPE (on_node) == PT_JOIN_RIGHT_OUTER)
6303  {
6304  bitset_remove (&dep_set, QO_NODE_IDX (on_node)); /* remove ON */
6305  }
6306  }
6307 
6308  for (t = bitset_iterate (&dep_set, &iter); t != -1 && !is_null_padded; t = bitset_next_member (&iter))
6309  {
6310  node = QO_ENV_NODE (env, t);
6311 
6312  if (QO_ON_COND_TERM (term))
6313  {
6314  if (QO_NODE_LOCATION (node) > QO_NODE_LOCATION (on_node))
6315  {
6316  continue; /* out of ON cond scope */
6317  }
6318 
6320  {
6321  is_null_padded = true;
6322  }
6323  }
6324 
6326  {
6327  is_null_padded = true;
6328  }
6329  }
6330 
6331  if (!is_null_padded)
6332  {
6333  continue; /* go ahead */
6334  }
6335 
6336  /* at here, found non-sargable node in outer-dep nodeset */
6337 
6338  if (QO_ON_COND_TERM (term))
6339  {
6341  }
6342  else
6343  {
6345  }
6346 
6347  if (QO_TERM_CLASS (term) != QO_TC_JOIN)
6348  {
6349  QO_TERM_JOIN_TYPE (term) = NO_JOIN;
6350 
6351  /* keep out from m-join edge */
6353  }
6354 
6355  } /* for (i = 0; ...) */
6356 
6357  bitset_delset (&prev_dep_set);
6358  bitset_delset (&dep_set);
6359 }
6360 
6361 /*
6362  * qo_find_index_terms () - Find the terms which contain the passed segments
6363  * and terms which contain just the passed segments
6364  * return:
6365  * env(in): The environment used
6366  * segsp(in): Passed BITSET of interested segments
6367  * index_entry(in):
6368  */
6369 static void
6370 qo_find_index_terms (QO_ENV * env, BITSET * segsp, QO_INDEX_ENTRY * index_entry)
6371 {
6372  int t;
6373  QO_TERM *qo_termp;
6374 
6375  assert (index_entry != NULL);
6376 
6377  BITSET_CLEAR (index_entry->terms);
6378 
6379  /* traverse all terms */
6380  for (t = 0; t < env->nterms; t++)
6381  {
6382  /* get the pointer to QO_TERM structure */
6383  qo_termp = QO_ENV_TERM (env, t);
6384 
6385  /* Fake terms (e.g., dependency links) won't have pt_expr's associated with them. They can't be implemented as
6386  * indexed sargs, either, so don't worry about them here.
6387  */
6388  if (!QO_TERM_PT_EXPR (qo_termp))
6389  {
6390  continue;
6391  }
6392  /* 'qo_analyze_term()' function verifies that all indexable terms are expression so that they have 'pt_expr'
6393  * field of type PT_EXPR. */
6394 
6395  /* if the segments that give rise to the term are in the given segment set */
6396  if (bitset_intersects (&(QO_TERM_SEGS (qo_termp)), segsp))
6397  {
6398  /* collect this term */
6399  bitset_add (&(index_entry->terms), t);
6400  }
6401  } /* for (t = 0; t < env->nterms; t++) */
6402 
6403  /* add index segs */
6404  bitset_union (&(index_entry->index_segs), segsp);
6405 }
6406 
6407 /*
6408  * qo_find_index_seg_terms () - Find the terms which contain the passed segment.
6409  * Only indexable and SARG terms are included
6410  * return:
6411  * env(in): The environment used
6412  * index_entry(in/out): Index entry
6413  * idx(in): Passed idx of an interested segment
6414  */
6415 static void
6416 qo_find_index_seg_terms (QO_ENV * env, QO_INDEX_ENTRY * index_entry, int idx, BITSET * index_segsp)
6417 {
6418  int t;
6419  QO_TERM *qo_termp;
6420  BITSET_ITERATOR iter;
6421 
6422  /* traverse all terms */
6423  for (t = 0; t < env->nterms; t++)
6424  {
6425  /* get the pointer to QO_TERM structure */
6426  qo_termp = QO_ENV_TERM (env, t);
6427 
6428  /* ignore this term if it is not marked as indexable by 'qo_analyze_term()' */
6429  if (!qo_termp->can_use_index)
6430  {
6431  continue;
6432  }
6433 
6434  /* Fake terms (e.g., dependency links) won't have pt_expr's associated with them. They can't be implemented as
6435  * indexed sargs, either, so don't worry about them here.
6436  */
6437  if (!QO_TERM_PT_EXPR (qo_termp))
6438  {
6439  continue;
6440  }
6441  /* 'qo_analyze_term()' function verifies that all indexable terms are expression so that they have 'pt_expr'
6442  * field of type PT_EXPR.
6443  */
6444 
6445  /* if the term is sarg and the given segment is involed in the expression that gives rise to the term */
6446  if (QO_TERM_CLASS (qo_termp) == QO_TC_SARG && BITSET_MEMBER (QO_TERM_SEGS (qo_termp), index_entry->seg_idxs[idx]))
6447  {
6448  /* check for range list term; RANGE (r1, r2, ...) */
6449  if (QO_TERM_IS_FLAGED (qo_termp, QO_TERM_RANGELIST))
6450  {
6451  if (index_entry->rangelist_seg_idx != -1 && QO_TERM_IDX (qo_termp) != index_entry->rangelist_term_idx)
6452  {
6453  /* (a,b) range (={..},..) if a is rangelist_seg_idx then b can scan using index */
6454  continue; /* already found. give up */
6455  }
6456 
6457  /* is the first time */
6458  index_entry->rangelist_seg_idx = idx;
6459  index_entry->rangelist_term_idx = QO_TERM_IDX (qo_termp);
6460  }
6461 
6462  /* collect this term */
6463  if (QO_TERM_IS_FLAGED (qo_termp, QO_TERM_EQUAL_OP))
6464  {
6465  bitset_add (&(index_entry->seg_equal_terms[idx]), t);
6466  }
6467  else
6468  {
6469  bitset_add (&(index_entry->seg_other_terms[idx]), t);
6470  }
6471  }
6472 
6473  } /* for (t = 0; ... */
6474 
6475 }
6476 
6477 /*
6478  * is_equivalent_indexes () - Compare the two index entries
6479  * return: True/False
6480  * index1(in): First index entry
6481  * index2(in): Second index entry
6482  *
6483  * Note: Return true if they are equivalent
6484  * and false otherwise. In order to be equivalent, the index entries
6485  * must contain the same segments specified in the same order
6486  */
6487 static int
6489 {
6490  int i, equivalent;
6491 
6492  /*
6493  * If the number of segments is different, then the indexes can't
6494  * be equivalent (cheap test).
6495  */
6496  if (index1->nsegs != index2->nsegs)
6497  {
6498  return false;
6499  }
6500 
6501  /*
6502  * Now compare the two indexes element by element
6503  */
6504  equivalent = true;
6505  for (i = 0; i < index1->nsegs; i++)
6506  {
6507  if ((index1->seg_idxs[i]) != (index2->seg_idxs[i]))
6508  {
6509  equivalent = false;
6510  break;
6511  }
6512  }
6513 
6514  return equivalent;
6515 }
6516 
6517 /*
6518  * qo_find_matching_index () -
6519  * return: int (index of matching index entry, or -1)
6520  * index_entry(in): Index entry to match
6521  * class_indexes(in): Array of index entries to search
6522  *
6523  * Note:
6524  * Given a index entry, search the index array looking for a match.
6525  * The array index of the matching entry is returned (if found).
6526  * A -1 is returned if a matching entry is not found.
6527  *
6528  * Indexes which are already a part of a heirarchical compatible index
6529  * list are not considered (these are identifialbe since their next
6530  * pointer is non-NULL).
6531  */
6532 static int
6533 qo_find_matching_index (QO_INDEX_ENTRY * index_entry, QO_INDEX * class_indexes)
6534 {
6535  int i;
6536 
6537  for (i = 0; i < class_indexes->n; i++)
6538  {
6539  /*
6540  * A matching index is found if the index node is not already a member
6541  * of a heirarchical compatible index list (i.e. next pointer is NULL)
6542  * and if it matches the passes <index_entry>.
6543  */
6544  if (QO_INDEX_INDEX (class_indexes, i)->next == NULL
6545  && is_equivalent_indexes (index_entry, QO_INDEX_INDEX (class_indexes, i)))
6546  {
6547  break;
6548  }
6549  }
6550 
6551  /*
6552  * If a match is found, return its index, otherwise return -1
6553  */
6554  if (i < class_indexes->n)
6555  {
6556  return i;
6557  }
6558  else
6559  {
6560  return -1;
6561  }
6562 }
6563 
6564 /*
6565  * is_index_compatible () -
6566  * return: int (True/False)
6567  * class_info(in): Class info structure
6568  * n(in): Index into class info structure. This determines the level
6569  * in the class hierarchy that we're currently concerned with
6570  * index_entry(in): Index entry to match against
6571  *
6572  * Note:
6573  * This is a recursive function which is used to verify that a
6574  * given index entry is compatible across the class hierarchy.
6575  * An index entry is compatible if there exists an index definition
6576  * on the same sequence of attributes at each level in the class
6577  * hierarchy. If the index entry is compatible, the entry will be
6578  * marked as such throughout the hierarchy.
6579  */
6580 static QO_INDEX_ENTRY *
6581 is_index_compatible (QO_CLASS_INFO * class_info, int n, QO_INDEX_ENTRY * index_entry)
6582 {
6583  QO_CLASS_INFO_ENTRY *class_entry;
6584  QO_INDEX *class_indexes;
6586  int i;
6587 
6588  if (n >= class_info->n)
6589  {
6590  return NULL;
6591  }
6592 
6593  class_entry = &(class_info->info[n]);
6594  class_indexes = class_entry->index;
6595 
6596  i = qo_find_matching_index (index_entry, class_indexes);
6597  if (i < 0)
6598  {
6599  return NULL;
6600  }
6601 
6602  index = QO_INDEX_INDEX (class_indexes, i);
6603  if (n == (class_info->n - 1))
6604  {
6605  index->next = NULL;
6606  return index;
6607  }
6608  else
6609  {
6610  index->next = is_index_compatible (class_info, n + 1, index);
6611  if (index->next == NULL)
6612  {
6613  return NULL;
6614  }
6615  else
6616  {
6617  return index;
6618  }
6619  }
6620 
6621 /* return NULL;*/
6622 }
6623 
6624 /*
6625  * qo_find_index_segs () -
6626  * return:
6627  * env(in):
6628  * consp(in):
6629  * nodep(in):
6630  * seg_idx(in):
6631  * seg_idx_num(in):
6632  * nseg_idxp(in):
6633  * segs(in):
6634  */
6635 static bool
6636 qo_find_index_segs (QO_ENV * env, SM_CLASS_CONSTRAINT * consp, QO_NODE * nodep, int *seg_idx, int seg_idx_num,
6637  int *nseg_idxp, BITSET * segs)
6638 {
6639  QO_SEGMENT *segp;
6640  SM_ATTRIBUTE *attrp;
6641  BITSET working;
6642  BITSET_ITERATOR iter;
6643  int i, iseg;
6644  bool matched;
6645  int count_matched_index_attributes = 0;
6646 
6647  /* working set; indexed segments */
6648  bitset_init (&working, env);
6649  bitset_assign (&working, &(QO_NODE_SEGS (nodep)));
6650 
6651  /* for each attribute of this constraint */
6652  for (i = 0; *nseg_idxp < seg_idx_num; i++)
6653  {
6654 
6655  if (consp->func_index_info && i == consp->func_index_info->col_id)
6656  {
6657  matched = false;
6658  for (iseg = bitset_iterate (&working, &iter); iseg != -1; iseg = bitset_next_member (&iter))
6659  {
6660  segp = QO_ENV_SEG (env, iseg);
6661  if (QO_SEG_FUNC_INDEX (segp) == true
6663  {
6664  bitset_add (segs, iseg); /* add the segment to the index segment set */
6665  bitset_remove (&working, iseg); /* remove the segment from the working set */
6666  seg_idx[*nseg_idxp] = iseg; /* remember the order of the index segments */
6667  (*nseg_idxp)++; /* number of index segments, 'seg_idx[]' */
6668  /* If we're handling with a multi-column index, then only equality expressions are allowed except for
6669  * the last matching segment.
6670  */
6671  bitset_delset (&working);
6672  matched = true;
6673  count_matched_index_attributes++;
6674  break;
6675  }
6676  }
6677  if (!matched)
6678  {
6679  seg_idx[*nseg_idxp] = -1; /* not found matched segment */
6680  (*nseg_idxp)++; /* number of index segments, 'seg_idx[]' */
6681  } /* if (!matched) */
6682  }
6683 
6684  if (*nseg_idxp == seg_idx_num)
6685  {
6686  break;
6687  }
6688  attrp = consp->attributes[i];
6689 
6690  matched = false;
6691  /* for each indexed segments of this node, compare the name of the segment with the one of the attribute */
6692  for (iseg = bitset_iterate (&working, &iter); iseg != -1; iseg = bitset_next_member (&iter))
6693  {
6694 
6695  segp = QO_ENV_SEG (env, iseg);
6696 
6697  if (!intl_identifier_casecmp (QO_SEG_NAME (segp), attrp->header.name))
6698  {
6699 
6700  bitset_add (segs, iseg); /* add the segment to the index segment set */
6701  bitset_remove (&working, iseg); /* remove the segment from the working set */
6702  seg_idx[*nseg_idxp] = iseg; /* remember the order of the index segments */
6703  (*nseg_idxp)++; /* number of index segments, 'seg_idx[]' */
6704  /* If we're handling with a multi-column index, then only equality expressions are allowed except for the
6705  * last matching segment.
6706  */
6707  matched = true;
6708  count_matched_index_attributes++;
6709  break;
6710  } /* if (!intl_identifier_casecmp...) */
6711 
6712  } /* for (iseg = bitset_iterate(&working, &iter); ...) */
6713 
6714  if (!matched)
6715  {
6716  seg_idx[*nseg_idxp] = -1; /* not found matched segment */
6717  (*nseg_idxp)++; /* number of index segments, 'seg_idx[]' */
6718  } /* if (!matched) */
6719 
6720  } /* for (i = 0; consp->attributes[i]; i++) */
6721 
6722  bitset_delset (&working);
6723 
6724  return count_matched_index_attributes > 0;
6725  /* this index is feasible to use if at least one attribute of index is specified(matched) */
6726 }
6727 
6728 /*
6729  * qo_is_coverage_index () - check if the index cover all query segments
6730  * return: bool
6731  * env(in): The environment
6732  * nodep(in): The node
6733  * index_entry(in): The index entry
6734  */
6735 static bool
6736 qo_is_coverage_index (QO_ENV * env, QO_NODE * nodep, QO_INDEX_ENTRY * index_entry)
6737 {
6738  int i, j, seg_idx;
6739  QO_SEGMENT *seg;
6740  bool found;
6741  QO_CLASS_INFO *class_infop = NULL;
6742  QO_NODE *seg_nodep = NULL;
6743  QO_TERM *qo_termp;
6744  PT_NODE *pt_node;
6745 
6746  if (env == NULL || nodep == NULL || index_entry == NULL)
6747  {
6748  return false;
6749  }
6750 
6751  /*
6752  * If NO_COVERING_IDX hint is given, we do not generate a plan for
6753  * covering index scan.
6754  */
6755  QO_ASSERT (env, QO_ENV_PT_TREE (env)->node_type == PT_SELECT);
6756  if (QO_ENV_PT_TREE (env)->node_type == PT_SELECT
6757  && (QO_ENV_PT_TREE (env)->info.query.q.select.hint & PT_HINT_NO_COVERING_IDX))
6758  {
6759  return false;
6760  }
6761 
6762  for (i = 0; i < index_entry->nsegs; i++)
6763  {
6764  seg_idx = (index_entry->seg_idxs[i]);
6765  if (seg_idx == -1)
6766  {
6767  continue;
6768  }
6769 
6770  /* We do not use covering index if there is a path expression */
6771  seg = QO_ENV_SEG (env, seg_idx);
6772  pt_node = QO_SEG_PT_NODE (seg);
6773  if (pt_node->node_type == PT_DOT_ || (pt_node->node_type == PT_NAME && pt_node->info.name.resolved == NULL))
6774  {
6775  return false;
6776  }
6777  }
6778 
6779  for (i = 0; i < env->nsegs; i++)
6780  {
6781  seg = QO_ENV_SEG (env, i);
6782 
6783  if (seg == NULL)
6784  {
6785  continue;
6786  }
6787 
6788  if (QO_SEG_IS_OID_SEG (seg))
6789  {
6790  found = false;
6791  for (j = 0; j < env->nterms; j++)
6792  {
6793  qo_termp = QO_ENV_TERM (env, j);
6794  if (BITSET_MEMBER (QO_TERM_SEGS (qo_termp), i))
6795  {
6796  found = true;
6797  break;
6798  }
6799  }
6800 
6801  if (found == false)
6802  {
6803  continue;
6804  }
6805  }
6806 
6807  /* the segment should belong to the given node */
6808  seg_nodep = QO_SEG_HEAD (seg);
6809  if (seg_nodep == NULL || seg_nodep != nodep)
6810  {
6811  continue;
6812  }
6813 
6814  class_infop = QO_NODE_INFO (seg_nodep);
6815  if (class_infop == NULL || !(class_infop->info[0].normal_class))
6816  {
6817  return false;
6818  }
6819  QO_ASSERT (env, class_infop->n > 0);
6820 
6821  found = false;
6822  for (j = 0; j < class_infop->n; j++)
6823  {
6824  if (class_infop->info[j].mop == index_entry->class_->mop)
6825  {
6826  found = true;
6827  break;
6828  }
6829  }
6830  if (!found)
6831  {
6832  continue;
6833  }
6834 
6835  found = false;
6836  for (j = 0; j < index_entry->col_num; j++)
6837  {
6838  if (index_entry->seg_idxs[j] == QO_SEG_IDX (seg))
6839  {
6840  /* if the segment created in respect to the function index info is covered, we do not use index covering */
6841  if (QO_SEG_FUNC_INDEX (seg))
6842  {
6843  return false;
6844  }
6845  found = true;
6846  break;
6847  }
6848  }
6849  if (!found)
6850  {
6851  return false;
6852  }
6853  }
6854 
6855  return true;
6856 }
6857 
6858 /*
6859  * qo_get_ils_prefix_length () - get prefix length of loose scan
6860  * returns: prefix length or -1 if loose scan not possible
6861  * env(in): environment
6862  * nodep(in): graph node
6863  * index_entry(in): index structure
6864  */
6865 static int
6867 {
6868  PT_NODE *tree;
6869  int prefix_len = 0, i;
6870 
6871  /* check for nulls */
6872  if (env == NULL || nodep == NULL || index_entry == NULL)
6873  {
6874  return 0;
6875  }
6876 
6877  /* loose scan has no point on single column index */
6878  if (!QO_ENTRY_MULTI_COL (index_entry))
6879  {
6880  return 0;
6881  }
6882  assert (index_entry->nsegs > 1);
6883 
6884  tree = env->pt_tree;
6885  QO_ASSERT (env, tree != NULL);
6886 
6887  if (tree->node_type != PT_SELECT)
6888  {
6889  return 0; /* not applicable */
6890  }
6891 
6892  /* check hint */
6893  if (tree->info.query.q.select.hint & PT_HINT_NO_INDEX_LS)
6894  {
6895  return 0; /* disable loose index scan */
6896  }
6897  else if ((tree->info.query.q.select.hint & PT_HINT_INDEX_LS) && (QO_NODE_HINT (nodep) & PT_HINT_INDEX_LS))
6898  { /* enable loose index scan */
6900  || !(QO_NODE_HINT (nodep) & PT_HINT_INDEX_SS))
6901  { /* skip scan is disabled */
6902  ; /* go ahead */
6903  }
6904  else
6905  { /* skip scan is enabled */
6906  return 0;
6907  }
6908  }
6909  else
6910  {
6911  return 0; /* no hint */
6912  }
6913 
6915  {
6916  return 0; /* not applicable */
6917  }
6918 
6919  if (index_entry->cover_segments
6921  {
6922  /* this is a select, index is covering all segments and it's either a DISTINCT query or GROUP BY query with
6923  * DISTINCT functions
6924  */
6925 
6926  /* see if only a prefix of the index is used */
6927  for (i = index_entry->nsegs - 1; i >= 0; i--)
6928  {
6929  if (index_entry->seg_idxs[i] != -1)
6930  {
6931  prefix_len = i + 1;
6932  break;
6933  }
6934  }
6935  }
6936  else
6937  {
6938  /* not applicable */
6939  return 0;
6940  }
6941 
6942  /* no need to continue if no prefix detected */
6943  if (prefix_len == -1 || prefix_len == index_entry->col_num)
6944  {
6945  return 0;
6946  }
6947 
6948  if (!pt_is_single_tuple (env->parser, env->pt_tree))
6949  {
6950  /* if not a single tuple query, then we either have a GROUP BY clause or we don't have any kind of aggregation;
6951  * in these cases, pure NULL keys qualify iff no terms are used
6952  */
6953  if (bitset_cardinality (&index_entry->terms) <= 0)
6954  {
6955  /* no terms specified, so NULL keys can't be skipped; disable ILS */
6956  return 0;
6957  }
6958  }
6959 
6960  /* all done */
6961  return prefix_len;
6962 }
6963 
6964 /*
6965  * qo_is_iss_index () - check if we can use the Index Skip Scan optimization
6966  * return: bool
6967  * env(in): The environment
6968  * nodep(in): The node
6969  * index_entry(in): The index entry
6970  *
6971  * Notes: The Index Skip Scan optimization applies when there is no term
6972  * involving the first index column, but there are other terms that
6973  * refer to the second, third etc columns, and the first column has
6974  * few distinct values: in this case, multiple index scans (one for
6975  * each value of the first column) can be faster than an index scan.
6976  */
6977 static bool
6978 qo_is_iss_index (QO_ENV * env, QO_NODE * nodep, QO_INDEX_ENTRY * index_entry)
6979 {
6980  int i;
6981  PT_NODE *tree;
6982  bool first_col_present = false, second_col_present = false;
6983 
6984  if (env == NULL || nodep == NULL || index_entry == NULL)
6985  {
6986  return false;
6987  }
6988 
6989  /* Index skip scan (ISS) candidates: - have no range or key filter terms for the first column of the index; - DO have
6990  * range or key filter terms for at least the second column of the index (maybe even for further columns, but we are
6991  * only interested in the second column right now); - obviously are multi-column indexes - not a filter index - not
6992  * with HQ
6993  */
6994 
6995  /* ISS has no meaning on single column indexes */
6996  if (!QO_ENTRY_MULTI_COL (index_entry))
6997  {
6998  return false;
6999  }
7000  assert (index_entry->nsegs > 1);
7001 
7002  tree = env->pt_tree;
7003  QO_ASSERT (env, tree != NULL);
7004 
7005  if (tree->node_type != PT_SELECT)
7006  {
7007  return false;
7008  }
7009 
7010  /* CONNECT BY messes with the terms, so just refuse any index skip scan in this case */
7011  if (tree->info.query.q.select.connect_by)
7012  {
7013  return false;
7014  }
7015 
7016  /* check hint */
7018  || !(QO_NODE_HINT (nodep) & PT_HINT_INDEX_SS))
7019  {
7020  return false;
7021  }
7022 
7023  assert (index_entry->constraints != NULL);
7024 
7025  /* do not allow filter ISS with filter index */
7026  if (index_entry->constraints->filter_predicate != NULL)
7027  {
7028  return false;
7029  }
7030 
7031  /* do not allow filter ISS with function index */
7032  for (i = 0; i < index_entry->nsegs; i++)
7033  {
7034  if ((index_entry->seg_idxs[i] != -1) && (QO_SEG_FUNC_INDEX (QO_ENV_SEG (env, index_entry->seg_idxs[i]))))
7035  {
7036  return false;
7037  }
7038  }
7039 
7040  /* First segment index should be missing */
7041  first_col_present = false;
7042  if (index_entry->seg_idxs[0] != -1)
7043  {
7044  /* it's not enough to have a reference to a segment in seg_idxs[], we must make sure there is an indexable term
7045  * that uses it: this means either an equal term, or an "other" term that is real (i.e. it is not a full range
7046  * scan term "invented" by pt_check_orderby to help with generating index covering.
7047  */
7048 
7049  if (bitset_cardinality (&(index_entry->seg_equal_terms[0])) > 0
7050  || bitset_cardinality (&(index_entry->seg_other_terms[0])) > 0)
7051  {
7052  first_col_present = true;
7053  }
7054  }
7055 
7056  if (first_col_present)
7057  {
7058  return false;
7059  }
7060 
7061  second_col_present = false;
7062  if (index_entry->seg_idxs[1] != -1)
7063  {
7064  /* it's not enough to have a reference to a segment in seg_idxs[], we must make sure there is an indexable term
7065  * that uses it: this means either an equal term, or an "other" term that is real (i.e. it is not a full range
7066  * scan term "invented" by pt_check_orderby to help with generating index covering.
7067  */
7068 
7069  if (bitset_cardinality (&(index_entry->seg_equal_terms[1])) > 0
7070  || bitset_cardinality (&(index_entry->seg_other_terms[1])) > 0)
7071  {
7072  second_col_present = true;
7073  }
7074  }
7075 
7076  if (!second_col_present)
7077  {
7078  return false;
7079  }
7080 
7081  /* The first col is missing, and the second col is present and has terms that can be used in a range search. Go ahead
7082  * and approve the index as a candidate for index skip scanning. We still have a long way ahead of us (use statistics
7083  * to decide whether index skip scan is the best approach) but we've made the first step.
7084  */
7085  return true;
7086 }
7087 
7088 static bool
7090 {
7091  if (!SM_IS_CONSTRAINT_INDEX_FAMILY (constraint->type))
7092  {
7093  // not an index
7094  return false;
7095  }
7096 
7097  if (constraint->index_status != SM_NORMAL_INDEX)
7098  {
7099  // building or invisible
7100  return false;
7101  }
7102 
7103  if (constraint->filter_predicate != NULL && QO_NODE_USING_INDEX (nodep) == NULL)
7104  {
7105  return false;
7106  }
7107 
7108  return true;
7109 }
7110 
7111 /*
7112  * qo_find_node_indexes () -
7113  * return:
7114  * env(in): The environment to be updated
7115  * nodep(in): The node to be updated
7116  *
7117  * Note: Scan the class constraints associated with the node. If
7118  * a match is found between a class constraint and the
7119  * segments, then add an QO_INDEX to the node. A match
7120  * occurs when the class constraint attribute are a subset
7121  * of the segments. We currently consider SM_CONSTRAINT_INDEX
7122  * and SM_CONSTRAINT_UNIQUE constraint types.
7123  */
7124 static void
7126 {
7127  int i, j, n, col_num;
7128  QO_CLASS_INFO *class_infop;
7129  QO_CLASS_INFO_ENTRY *class_entryp;
7130  QO_USING_INDEX *uip;
7131  QO_INDEX *indexp;
7132  QO_INDEX_ENTRY *index_entryp;
7133  QO_NODE_INDEX *node_indexp;
7134  QO_NODE_INDEX_ENTRY *ni_entryp;
7135  SM_CLASS_CONSTRAINT *constraints, *consp;
7136  int *seg_idx, seg_idx_arr[NELEMENTS], nseg_idx;
7137  bool found, is_hint_use, is_hint_ignore, is_hint_force, is_hint_all_except;
7138  BITSET index_segs, index_terms;
7139  bool special_index_scan = false;
7140 
7141  /* information of classes underlying this node */
7142  class_infop = QO_NODE_INFO (nodep);
7143 
7144  if (class_infop->n <= 0)
7145  {
7146  return; /* no classes, nothing to do process */
7147  }
7148 
7150  {
7151  if (QO_NODE_USING_INDEX (nodep) == NULL)
7152  {
7153  assert (0);
7154  return;
7155  }
7156  special_index_scan = true;
7157  }
7158 
7159  /* for each class in the hierarchy, search the class constraint cache looking for applicable indexes(UNIQUE and INDEX
7160  * constraint)
7161  */
7162  for (i = 0; i < class_infop->n; i++)
7163  {
7164 
7165  /* class information entry */
7166  class_entryp = &(class_infop->info[i]);
7167 
7168  if (qo_is_non_mvcc_class_with_index (class_entryp))
7169  {
7170  /* Do not use index of db_serial/db_has_apply_info for scanning. Current index scanning is optimized for
7171  * MVCC, while db_serial and db_ha_apply_info have MVCC disabled.
7172  */
7173  constraints = NULL;
7174  }
7175  else
7176  {
7177  /* get constraints of the class */
7178  constraints = sm_class_constraints (class_entryp->mop);
7179  }
7180 
7181  /* count the number of INDEX and UNIQUE constraints contained in this class */
7182  n = 0;
7183  for (consp = constraints; consp; consp = consp->next)
7184  {
7185  if (qo_is_usable_index (consp, nodep))
7186  {
7187  n++;
7188  }
7189  }
7190 
7191  /* allocate room for the constraint indexes */
7192  /* we don't have apriori knowledge about which constraints will be applied, so allocate room for all of them */
7193  /* qo_alloc_index(env, n) will allocate QO_INDEX structure and QO_INDEX_ENTRY structure array */
7194  indexp = class_entryp->index = qo_alloc_index (env, n);
7195  if (indexp == NULL)
7196  {
7197  return;
7198  }
7199 
7200  indexp->n = 0;
7201 
7202  /* for each constraint of the class */
7203  for (consp = constraints; consp; consp = consp->next)
7204  {
7205  if (!qo_is_usable_index (consp, nodep))
7206  {
7207  continue; // skip it
7208  }
7209 
7210  uip = QO_NODE_USING_INDEX (nodep);
7211  j = -1;
7212  if (uip)
7213  {
7214  if (QO_UI_N (uip) == 0)
7215  {
7216  /* USING INDEX NONE case, skip */
7217  continue;
7218  }
7219 
7220  /* search USING INDEX list */
7221  found = false;
7222  is_hint_use = is_hint_force = is_hint_ignore = false;
7223  is_hint_all_except = false;
7224 
7225  /* gather information */
7226  for (j = 0; j < QO_UI_N (uip); j++)
7227  {
7228  switch (QO_UI_FORCE (uip, j))
7229  {
7230  case PT_IDX_HINT_USE:
7231  is_hint_use = true;
7232  break;
7233  case PT_IDX_HINT_FORCE:
7234  is_hint_force = true;
7235  break;
7236  case PT_IDX_HINT_IGNORE:
7237  is_hint_ignore = true;
7238  break;
7240  is_hint_all_except = true;
7241  break;
7242  }
7243  }
7244 
7245  /* search for index in using_index clause */
7246  for (j = 0; j < QO_UI_N (uip); j++)
7247  {
7248  if (!intl_identifier_casecmp (consp->name, QO_UI_INDEX (uip, j)))
7249  {
7250  found = true;
7251  break;
7252  }
7253  }
7254 
7255  if (QO_UI_FORCE (uip, 0) == PT_IDX_HINT_ALL_EXCEPT)
7256  {
7257  /* USING INDEX ALL EXCEPT case */
7258  if (found)
7259  {
7260  /* this constraint(index) is specified in USING INDEX ALL EXCEPT clause; do not use it */
7261  continue;
7262  }
7263  if (consp->filter_predicate != NULL)
7264  {
7265  /* don't use filter indexes unless specified */
7266  continue;
7267  }
7268  j = -1;
7269  }
7270  else if (is_hint_force || is_hint_use)
7271  {
7272  /* if any indexes are forced or used, use them */
7273  if (!found || QO_UI_FORCE (uip, j) == PT_IDX_HINT_IGNORE)
7274  {
7275  continue;
7276  }
7277  }
7278  else
7279  {
7280  /* no indexes are used or forced, only ignored */
7281  if (found)
7282  {
7283  /* found as ignored; don't use */
7284  continue;
7285  }
7286  if (consp->filter_predicate != NULL)
7287  {
7288  /* don't use filter indexes unless specified */
7289  continue;
7290  }
7291  j = -1;
7292  }
7293  }
7294 
7295  bitset_init (&index_segs, env);
7296  bitset_init (&index_terms, env);
7297  nseg_idx = 0;
7298 
7299  /* count the number of columns on this constraint */
7300  for (col_num = 0; consp->attributes[col_num]; col_num++)
7301  {
7302  ;
7303  }
7304  if (consp->func_index_info)
7305  {
7306  col_num = consp->func_index_info->attr_index_start + 1;
7307  }
7308 
7309  if (col_num <= NELEMENTS)
7310  {
7311  seg_idx = seg_idx_arr;
7312  }
7313  else
7314  {
7315  /* allocate seg_idx */
7316  seg_idx = (int *) malloc (sizeof (int) * col_num);
7317  if (seg_idx == NULL)
7318  {
7319  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (int) * col_num);
7320  /* cannot allocate seg_idx, use seg_idx_arr instead. */
7321  seg_idx = seg_idx_arr;
7322  col_num = NELEMENTS;
7323  }
7324  }
7325 
7326  /* find indexed segments into 'seg_idx[]' */
7327  found = qo_find_index_segs (env, consp, nodep, seg_idx, col_num, &nseg_idx, &index_segs);
7328  /* 'seg_idx[nseg_idx]' array contains index no.(idx) of the segments which are found and applicable to this
7329  * index(constraint) as search key in the order of the index key attribute. For example, if the index
7330  * consists of attributes 'b' and 'a', and the given segments of the node are 'a(1)', 'b(2)' and 'c(3)', then
7331  * the result of 'seg_idx[]' will be '{ 2, 1, -1 }'. The value -1 in 'seg_idx[] array means that no segment
7332  * is specified.
7333  */
7334  /* If key information is required, no index segments will be found, but index scan has to be forced. */
7335  if (found == true || special_index_scan == true)
7336  {
7337  /* if applicable index was found, add it to the node */
7338 
7339  /* fill in QO_INDEX_ENTRY structure */
7340  index_entryp = QO_INDEX_INDEX (indexp, indexp->n);
7341  index_entryp->nsegs = nseg_idx;
7342  index_entryp->seg_idxs = NULL;
7343  index_entryp->rangelist_seg_idx = -1;
7344  index_entryp->seg_equal_terms = NULL;
7345  index_entryp->seg_other_terms = NULL;
7346  if (index_entryp->nsegs > 0)
7347  {
7348  size_t size;
7349 
7350  size = sizeof (int) * index_entryp->nsegs;
7351  index_entryp->seg_idxs = (int *) malloc (size);
7352  if (index_entryp->seg_idxs == NULL)
7353  {
7354  if (seg_idx != seg_idx_arr)
7355  {
7356  free_and_init (seg_idx);
7357  }
7359  return;
7360  }
7361 
7362  size = sizeof (BITSET) * index_entryp->nsegs;
7363  index_entryp->seg_equal_terms = (BITSET *) malloc (size);
7364  if (index_entryp->seg_equal_terms == NULL)
7365  {
7366  free_and_init (index_entryp->seg_idxs);
7367  if (seg_idx != seg_idx_arr)
7368  {
7369  free_and_init (seg_idx);
7370  }
7372  return;
7373  }
7374  index_entryp->seg_other_terms = (BITSET *) malloc (size);
7375  if (index_entryp->seg_other_terms == NULL)
7376  {
7377  free_and_init (index_entryp->seg_equal_terms);
7378  free_and_init (index_entryp->seg_idxs);
7379  if (seg_idx != seg_idx_arr)
7380  {
7381  free_and_init (seg_idx);
7382  }
7384  return;
7385  }
7386  }
7387  index_entryp->class_ = class_entryp;
7388  /* j == -1 iff no USING INDEX or USING INDEX ALL EXCEPT */
7389  index_entryp->force = (j == -1) ? 0 : QO_UI_FORCE (uip, j);
7390  index_entryp->col_num = col_num;
7391  index_entryp->key_type = NULL;
7392  index_entryp->constraints = consp;
7393 
7394  /* set key limits */
7395  index_entryp->key_limit = (j == -1) ? NULL : QO_UI_KEYLIMIT (uip, j);
7396 
7397  /* assign seg_idx[] and seg_terms[] */
7398  for (j = 0; j < index_entryp->nsegs; j++)
7399  {
7400  bitset_init (&(index_entryp->seg_equal_terms[j]), env);
7401  bitset_init (&(index_entryp->seg_other_terms[j]), env);
7402  index_entryp->seg_idxs[j] = seg_idx[j];
7403  if (index_entryp->seg_idxs[j] != -1)
7404  {
7405  qo_find_index_seg_terms (env, index_entryp, j, &index_segs);
7406  }
7407  }
7408  qo_find_index_terms (env, &index_segs, index_entryp);
7409 
7410  index_entryp->cover_segments = qo_is_coverage_index (env, nodep, index_entryp);
7411 
7412  index_entryp->is_iss_candidate = qo_is_iss_index (env, nodep, index_entryp);
7413 
7414  /* disable loose scan if skip scan is possible */
7415  if (index_entryp->is_iss_candidate == true)
7416  {
7417  index_entryp->ils_prefix_len = 0;
7418  }
7419  else
7420  {
7421  index_entryp->ils_prefix_len = qo_get_ils_prefix_length (env, nodep, index_entryp);
7422  }
7423 
7424  index_entryp->statistics_attribute_name = NULL;
7425  index_entryp->is_func_index = false;
7426 
7427  if (index_entryp->col_num > 0)
7428  {
7429  const char *temp_name = NULL;
7430 
7431  if (consp->func_index_info && consp->func_index_info->col_id == 0)
7432  {
7433  index_entryp->is_func_index = true;
7434  }
7435  if (!index_entryp->is_func_index && consp->attributes && consp->attributes[0])
7436  {
7437  temp_name = consp->attributes[0]->header.name;
7438  if (temp_name)
7439  {
7440  size_t len = strlen (temp_name) + 1;
7441  index_entryp->statistics_attribute_name = (char *) malloc (sizeof (char) * len);
7442  if (index_entryp->statistics_attribute_name == NULL)
7443  {
7444  if (seg_idx != seg_idx_arr)
7445  {
7446  free_and_init (seg_idx);
7447  }
7449  sizeof (char) * len);
7450  return;
7451  }
7452  strcpy (index_entryp->statistics_attribute_name, temp_name);
7453  }
7454  }
7455  }
7456 
7457  (indexp->n)++;
7458 
7459  }
7460 
7461  bitset_delset (&(index_segs));
7462  bitset_delset (&(index_terms));
7463  if (seg_idx != seg_idx_arr)
7464  {
7465  free_and_init (seg_idx);
7466  }
7467 
7468  } /* for (consp = constraintp; consp; consp = consp->next) */
7469 
7470  } /* for (i = 0; i < class_infop->n; i++) */
7471  /* class_infop->n >= 1 */
7472 
7473  /* find and mark indexes which are compatible across class hierarchy */
7474 
7475  indexp = class_infop->info[0].index;
7476 
7477  /* allocate room for the compatible heirarchical indexex */
7478  /* We'll go ahead and allocate room for each index in the top level class. This is the worst case situation and it
7479  * simplifies the code a bit.
7480  */
7481  /* Malloc and Init a QO_INDEX struct with n entries. */
7482  node_indexp = QO_NODE_INDEXES (nodep) = (QO_NODE_INDEX *) malloc (SIZEOF_NODE_INDEX (indexp->n));
7483 
7484  if (node_indexp == NULL)
7485  {
7487  return;
7488  }
7489 
7490  memset (node_indexp, 0, SIZEOF_NODE_INDEX (indexp->n));
7491 
7492  QO_NI_N (node_indexp) = 0;
7493 
7494  /* if we don`t have any indexes to process, we're through if there is only one, then make sure that the head pointer
7495  * points to it if there are more than one, we also need to construct a linked list of compatible indexes by
7496  * recursively searching down the hierarchy
7497  */
7498  for (i = 0; i < indexp->n; i++)
7499  {
7500  index_entryp = QO_INDEX_INDEX (indexp, i);
7501  /* get compatible(equivalent) index of the next class 'index_entryp->next' points to it */
7502  index_entryp->next = is_index_compatible (class_infop, 1, index_entryp);
7503 
7504  if ((index_entryp->next != NULL) || (class_infop->n == 1))
7505  {
7506  /* fill in QO_NODE_INDEX_ENTRY structure */
7507  ni_entryp = QO_NI_ENTRY (node_indexp, QO_NI_N (node_indexp));
7508  /* number of classes on the list */
7509  (ni_entryp)->n = class_infop->n;
7510  /* link QO_INDEX_ENTRY struture to QO_NODE_INDEX_ENTRY strucure */
7511  (ni_entryp)->head = index_entryp;
7512  QO_NI_N (node_indexp)++;
7513  }
7514  } /* for (i = 0; i < indexp->n; i++) */
7515 
7516 }
7517 
7518 /*
7519  * qo_discover_indexes () -
7520  * return: nothing
7521  * env(in): The environment to be updated
7522  *
7523  * Note: Study each term to finish determination of whether it can use
7524  * an index. qo_analyze_term() already determined whether each
7525  * term qualifies structurally, and qo_get_class_info() has
7526  * determined all of the indexes that are available, so all we
7527  * have to do here is combine those two pieces of information.
7528  */
7529 static void
7531 {
7532  int i, j, k, b, n, s;
7533  bool found;
7534  BITSET_ITERATOR bi;
7535  QO_NODE_INDEX *node_indexp;
7536  QO_NODE_INDEX_ENTRY *ni_entryp;
7537  QO_INDEX_ENTRY *index_entryp;
7538  QO_TERM *termp;
7539  QO_NODE *nodep;
7540  QO_SEGMENT *segp;
7541 
7542  /* iterate over all nodes and find indexes for each node */
7543  for (i = 0; i < env->nnodes; i++)
7544  {
7545  nodep = QO_ENV_NODE (env, i);
7546  if (nodep->info)
7547  {
7548  /* find indexed segments that belong to this node and get indexes that apply to indexed segments. Note that a
7549  * scan for record information or page informations should follow, there is no need to check for index (a
7550  * sequential scan is needed).
7551  */
7554  {
7555  qo_find_node_indexes (env, nodep);
7556  if (0 < QO_NODE_INFO_N (nodep) && QO_NODE_INDEXES (nodep) != NULL)
7557  {
7558  /* collect statistics if discovers an usable index */
7559  qo_get_index_info (env, nodep);
7560  continue;
7561  }
7562  /* fall through */
7563  }
7564  /* fall through */
7565  }
7566 
7567  /* this node will not use an index */
7568  QO_NODE_INDEXES (nodep) = NULL;
7569  }
7570 
7571  /* for each terms, look indexed segements and filter out the segments which don't actually contain any indexes */
7572  for (i = 0; i < env->nterms; i++)
7573  {
7574 
7575  termp = QO_ENV_TERM (env, i);
7576 
7577  /* before, 'index_seg[]' has all possible indexed segments, that is assigned at 'qo_analyze_term()' */
7578  /* for all 'term.index_seg[]', examine if it really has index or not */
7579  k = 0;
7580  for (j = 0; j < termp->can_use_index; j++)
7581  {
7582 
7583  segp = termp->index_seg[j];
7584 
7585  found = false; /* init */
7586  /* for each nodes, do traverse */
7587  for (b = bitset_iterate (&(QO_TERM_NODES (termp)), &bi); b != -1 && !found; b = bitset_next_member (&bi))
7588  {
7589 
7590  nodep = QO_ENV_NODE (env, b);
7591 
7592  /* pointer to QO_NODE_INDEX structure of QO_NODE */
7593  node_indexp = QO_NODE_INDEXES (nodep);
7594  if (node_indexp == NULL)
7595  {
7596  /* node has not any index skip and go ahead */
7597  continue;
7598  }
7599 
7600  /* for each index list rooted at the node */
7601  for (n = 0, ni_entryp = QO_NI_ENTRY (node_indexp, 0); n < QO_NI_N (node_indexp) && !found;
7602  n++, ni_entryp++)
7603  {
7604 
7605  index_entryp = (ni_entryp)->head;
7606 
7607  /* for each segments constrained by the index */
7608  for (s = 0; s < index_entryp->nsegs && !found; s++)
7609  {
7610  if (QO_SEG_IDX (segp) == (index_entryp->seg_idxs[s]))
7611  {
7612  /* found specified seg stop traverse */
7613  found = true;
7614 
7615  /* record term at segment structure */
7616  bitset_add (&(QO_SEG_INDEX_TERMS (segp)), QO_TERM_IDX (termp));
7617  /* indexed segment in 'index_seg[]' array */
7618  termp->index_seg[k++] = termp->index_seg[j];
7619  }
7620  } /* for (s = 0 ... ) */
7621 
7622  } /* for (n = 0 ... ) */
7623 
7624  } /* for (b = ... ) */
7625 
7626  } /* for (j = 0 ... ) */
7627 
7628  termp->can_use_index = k; /* dimension of 'index_seg[]' */
7629  /* clear unused, discarded 'index_seg[]' entries */
7630  while (k < j)
7631  {
7632  termp->index_seg[k++] = NULL;
7633  }
7634 
7635  } /* for (i = 0; i < env->nterms; i++) */
7636 
7637 }
7638 
7639 /*
7640  * qo_discover_partitions () -
7641  * return:
7642  * env(in):
7643  */
7644 static void
7646 {
7647  int N = env->nnodes; /* The number of nodes in the join graph */
7648  int E = env->nedges; /* The number of edges (in the strict sense) */
7649  int P = 0; /* The number of partitions */
7650  int e, n, p;
7651 
7652  int *buddy; /* buddy[i] is the index of another node in the same partition as i */
7653  int *partition; /* partition[i] is the index of the partition to which node i belongs */
7654  BITSET_ITERATOR bi;
7655  int hi, ti, r;
7656  QO_TERM *term;
7657  QO_PARTITION *part;
7658  int M_offset, join_info_size;
7659  int rel_idx;
7660 
7661  buddy = NULL;
7662  if (N > 0)
7663  {
7664  buddy = (int *) malloc (sizeof (int) * (2 * N));
7665  if (buddy == NULL)
7666  {
7667  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (int) * (2 * N));
7668  return;
7669  }
7670  }
7671  else
7672  {
7673  return;
7674  }
7675 
7676  partition = buddy + N;
7677 
7678  /*
7679  * This code assumes that there will be no ALLOCATE failures; if
7680  * there are, the buddy array will be lost.
7681  */
7682 
7683  for (n = 0; n < N; ++n)
7684  {
7685  buddy[n] = -1;
7686  partition[n] = -1;
7687  }
7688 
7689  for (e = 0; e < E; ++e)
7690  {
7691  term = QO_ENV_TERM (env, e);
7692 
7693  /*
7694  * Identify one of the nodes in this term, and run to the top of
7695  * the tree in which it resides.
7696  */
7697  hi = bitset_iterate (&(QO_TERM_NODES (term)), &bi);
7698  while (hi != -1 && buddy[hi] != -1)
7699  {
7700  hi = buddy[hi];
7701  }
7702 
7703  /*
7704  * Now buddy up all of the other nodes encompassed by this term.
7705  */
7706  while ((ti = bitset_next_member (&bi)) != -1)
7707  {
7708  /*
7709  * Run to the top of the tree in which node[ti] resides.
7710  */
7711  while (buddy[ti] != -1)
7712  {
7713  ti = buddy[ti];
7714  }
7715  /*
7716  * Join the two trees together.
7717  */
7718  if (hi != ti)
7719  {
7720  buddy[hi] = ti;
7721  }
7722  }
7723  }
7724 
7725  /*
7726  * Now assign the actual partitions.
7727  */
7728  for (n = 0; n < N; ++n)
7729  {
7730  if (partition[n] == -1)
7731  {
7732  r = n;
7733  /*
7734  * Find the root of the tree to which node[n] belongs.
7735  */
7736  while (buddy[r] != -1)
7737  {
7738  r = buddy[r];
7739  }
7740  /*
7741  * If a partition hasn't already been assigned for this tree,
7742  * assign one now.
7743  */
7744  if (partition[r] == -1)
7745  {
7746  QO_PARTITION *part = QO_ENV_PARTITION (env, P);
7747  QO_NODE *node = QO_ENV_NODE (env, r);
7748  qo_partition_init (env, part, P);
7749  bitset_add (&(QO_PARTITION_NODES (part)), r);
7751  QO_NODE_PARTITION (node) = part;
7752  partition[r] = P;
7753  P++;
7754  }
7755  /*
7756  * Now add node[n] to that partition.
7757  */
7758  if (n != r)
7759  {
7760  QO_PARTITION *part = QO_ENV_PARTITION (env, partition[r]);
7761  QO_NODE *node = QO_ENV_NODE (env, n);
7762  partition[n] = partition[r];
7763  bitset_add (&(QO_PARTITION_NODES (part)), n);
7765  QO_NODE_PARTITION (node) = part;
7766  }
7767  }
7768  }
7769 
7770  /*
7771  * Now go build the edge sets that correspond to each partition,
7772  * i.e., the set of edges that connect the nodes in each partition.
7773  */
7774  M_offset = 0; /* init */
7775  for (p = 0; p < P; ++p)
7776  {
7777  part = QO_ENV_PARTITION (env, p);
7778 
7779  for (e = 0; e < E; ++e)
7780  {
7781  QO_TERM *edge = QO_ENV_TERM (env, e);
7782 
7783  if (bitset_subset (&(QO_PARTITION_NODES (part)), &(QO_TERM_NODES (edge)))
7784  && !bitset_is_empty (&(QO_TERM_NODES (edge))))
7785  {
7786  bitset_add (&(QO_PARTITION_EDGES (part)), e);
7787  }
7788  }
7789  /* alloc size check 2: for signed max int. 2**30 is positive, 2**31 is negative LOG2_SIZEOF_POINTER:
7790  * log2(sizeof(QO_INFO *))
7791  */
7793  {
7794  if (buddy)
7795  {
7796  free_and_init (buddy);
7797  }
7798  QO_ABORT (env);
7799  }
7800 
7801  /* set the starting point the join_info vector that correspond to each partition. */
7802  if (p > 0)
7803  {
7804  QO_PARTITION_M_OFFSET (part) = M_offset;
7805  }
7806  join_info_size = QO_JOIN_INFO_SIZE (part);
7807  if (INT_MAX - M_offset * sizeof (QO_INFO *) < join_info_size * sizeof (QO_INFO *))
7808  {
7809  if (buddy)
7810  {
7811  free_and_init (buddy);
7812  }
7813  QO_ABORT (env);
7814  }
7815  M_offset += join_info_size;
7816 
7817  /* set the relative id of nodes in the partition */
7818  rel_idx = 0; /* init */
7819  for (hi = bitset_iterate (&(QO_PARTITION_NODES (part)), &bi); hi != -1; hi = bitset_next_member (&bi))
7820  {
7821  QO_NODE_REL_IDX (QO_ENV_NODE (env, hi)) = rel_idx;
7822  rel_idx++;
7823  }
7824  }
7825 
7826  env->npartitions = P;
7827 
7828  if (buddy)
7829  {
7830  free_and_init (buddy);
7831  }
7832 }
7833 
7834 /*
7835  * qo_assign_eq_classes () -
7836  * return:
7837  * env(in):
7838  */
7839 static void
7841 {
7842  int i;
7843  QO_EQCLASS **eq_map;
7844  BITSET segs;
7845 
7846  bitset_init (&segs, env);
7847 
7848  eq_map = NULL;
7849  if (env->nsegs > 0)
7850  {
7851  eq_map = (QO_EQCLASS **) malloc (sizeof (QO_EQCLASS *) * env->nsegs);
7852  if (eq_map == NULL)
7853  {
7855  return;
7856  }
7857  }
7858 
7859  for (i = 0; i < env->nsegs; ++i)
7860  {
7861  eq_map[i] = NULL;
7862  }
7863 
7864  for (i = 0; i < env->nedges; i++)
7865  {
7866  QO_TERM *term;
7867 
7868  term = QO_ENV_TERM (env, i);
7869  if (QO_TERM_NOMINAL_SEG (term))
7870  {
7871  bitset_union (&segs, &(QO_TERM_SEGS (term)));
7872  }
7873  }
7874 
7875  /*
7876  * Now examine each segment and see if it should be assigned to an
7877  * equivalence class.
7878  */
7879  for (i = 0; i < env->nsegs; ++i)
7880  {
7881  if (!BITSET_MEMBER (segs, i))
7882  {
7883  continue;
7884  }
7885 
7886  if (eq_map[i] == NULL)
7887  {
7888  QO_SEGMENT *root, *seg;
7889  seg = QO_ENV_SEG (env, i);
7890 
7891  /*
7892  * Find the root of the tree in which this segment resides.
7893  */
7894  for (root = seg; QO_SEG_EQ_ROOT (root); root = QO_SEG_EQ_ROOT (root))
7895  {
7896  ;
7897  }
7898  /*
7899  * Assign a new EqClass to that root if one hasn't already
7900  * been assigned.
7901  */
7902  if (eq_map[QO_SEG_IDX (root)] == NULL)
7903  {
7904  qo_eqclass_add ((eq_map[QO_SEG_IDX (root)] = qo_eqclass_new (env)), root);
7905  }
7906  /*
7907  * Now add the original segment to the same equivalence
7908  * class.
7909  */
7910  if (root != seg)
7911  {
7912  qo_eqclass_add (eq_map[QO_SEG_IDX (root)], seg);
7913  }
7914  eq_map[i] = eq_map[QO_SEG_IDX (root)];
7915  }
7916  }
7917 
7918  bitset_delset (&segs);
7919  if (eq_map)
7920  {
7921  free_and_init (eq_map);
7922  }
7923 
7924  /*
7925  * Now squirrel away the eqclass info for each term so that we don't
7926  * have to keep recomputing it when searching the plan space. Note
7927  * that this not really meaningful unless all of the segments in the
7928  * term are in the same equivalence class as the first one. However,
7929  * since we're only supposed to use this information when examining
7930  * join or path terms, and since that condition holds for those
7931  * terms, this should be ok.
7932  */
7933  for (i = 0; i < env->nedges; i++)
7934  {
7935  QO_TERM *term = QO_ENV_TERM (env, i);
7936  QO_SEGMENT *seg = QO_TERM_NOMINAL_SEG (term);
7937 
7938  if (seg)
7939  {
7940  QO_TERM_EQCLASS (term) = QO_SEG_EQCLASS (seg);
7941  }
7942  else if (QO_TERM_IS_FLAGED (term, QO_TERM_MERGEABLE_EDGE))
7943  {
7944  QO_TERM_EQCLASS (term) = qo_eqclass_new (env);
7946  }
7947  else
7948  {
7949  QO_TERM_EQCLASS (term) = QO_UNORDERED;
7950  }
7951  }
7952 }
7953 
7954 /*
7955  * qo_env_dump () -
7956  * return:
7957  * env(in):
7958  * f(in):
7959  */
7960 static void
7961 qo_env_dump (QO_ENV * env, FILE * f)
7962 {
7963  int i;
7964 
7966  {
7967  fprintf (f, "Non recursive part of CTE:\n");
7968  }
7970  {
7971  fprintf (f, "Recursive part of CTE:\n");
7972  }
7973 
7974  if (f == NULL)
7975  {
7976  f = stdout;
7977  }
7978 
7979  if (env->nsegs)
7980  {
7981  fprintf (f, "Join graph segments (f indicates final):\n");
7982  for (i = 0; i < env->nsegs; ++i)
7983  {
7984  QO_SEGMENT *seg = QO_ENV_SEG (env, i);
7985  int extra_info = 0;
7986 
7987  fprintf (f, "seg[%d]: ", i);
7988  qo_seg_fprint (seg, f);
7989 
7990  PUT_FLAG (BITSET_MEMBER (env->final_segs, i), "f");
7991  /*
7992  * Put extra flags here.
7993  */
7994  fputs (extra_info ? ")\n" : "\n", f);
7995  }
7996  }
7997 
7998  if (env->nnodes)
7999  {
8000  fprintf (f, "Join graph nodes:\n");
8001  for (i = 0; i < env->nnodes; ++i)
8002  {
8003  QO_NODE *node = QO_ENV_NODE (env, i);
8004  fprintf (f, "node[%d]: ", i);
8005  qo_node_dump (node, f);
8006  fputs ("\n", f);
8007  }
8008  }
8009 
8010  if (env->neqclasses)
8011  {
8012  fprintf (f, "Join graph equivalence classes:\n");
8013  for (i = 0; i < env->neqclasses; ++i)
8014  {
8015  fprintf (f, "eqclass[%d]: ", i);
8016  qo_eqclass_dump (QO_ENV_EQCLASS (env, i), f);
8017  fputs ("\n", f);
8018  }
8019  }
8020 
8021  /*
8022  * Notice that we blow off printing the edge structures themselves,
8023  * and just print the term that gives rise to the edge. Also notice
8024  * the way edges and terms are separated: we don't reset the counter
8025  * for non-edge terms.
8026  */
8027  if (env->nedges)
8028  {
8029  fputs ("Join graph edges:\n", f);
8030  for (i = 0; i < env->nedges; ++i)
8031  {
8032  fprintf (f, "term[%d]: ", i);
8033  qo_term_dump (QO_ENV_TERM (env, i), f);
8034  fputs ("\n", f);
8035  }
8036  }
8037 
8038  if (env->nterms - env->nedges)
8039  {
8040  fputs ("Join graph terms:\n", f);
8041  for (i = env->nedges; i < env->nterms; ++i)
8042  {
8043  fprintf (f, "term[%d]: ", i);
8044  qo_term_dump (QO_ENV_TERM (env, i), f);
8045  fputs ("\n", f);
8046  }
8047  }
8048 
8049  if (env->nsubqueries)
8050  {
8051  fputs ("Join graph subqueries:\n", f);
8052  for (i = 0; i < env->nsubqueries; ++i)
8053  {
8054  fprintf (f, "subquery[%d]: ", i);
8055  qo_subquery_dump (env, &env->subqueries[i], f);
8056  fputs ("\n", f);
8057  }
8058  }
8059 
8060  if (env->npartitions > 1)
8061  {
8062  fputs ("Join graph partitions:\n", f);
8063  for (i = 0; i < env->npartitions; ++i)
8064  {
8065  fprintf (f, "partition[%d]: ", i);
8066  qo_partition_dump (QO_ENV_PARTITION (env, i), f);
8067  fputs ("\n", f);
8068  }
8069  }
8070 
8071  fflush (f);
8072 }
8073 
8074 /*
8075  * qo_node_clear () -
8076  * return:
8077  * env(in):
8078  * idx(in):
8079  */
8080 static void
8081 qo_node_clear (QO_ENV * env, int idx)
8082 {
8083  QO_NODE *node = QO_ENV_NODE (env, idx);
8084 
8085  QO_NODE_ENV (node) = env;
8086  QO_NODE_ENTITY_SPEC (node) = NULL;
8087  QO_NODE_PARTITION (node) = NULL;
8088  QO_NODE_OID_SEG (node) = NULL;
8089  QO_NODE_SELECTIVITY (node) = 1.0;
8090  QO_NODE_IDX (node) = idx;
8091  QO_NODE_INFO (node) = NULL;
8092  QO_NODE_NCARD (node) = 0;
8093  QO_NODE_TCARD (node) = 0;
8094  QO_NODE_NAME (node) = NULL;
8095  QO_NODE_INDEXES (node) = NULL;
8096  QO_NODE_USING_INDEX (node) = NULL;
8097 
8098  bitset_init (&(QO_NODE_EQCLASSES (node)), env);
8099  bitset_init (&(QO_NODE_SARGS (node)), env);
8100  bitset_init (&(QO_NODE_DEP_SET (node)), env);
8101  bitset_init (&(QO_NODE_SUBQUERIES (node)), env);
8102  bitset_init (&(QO_NODE_SEGS (node)), env);
8103  bitset_init (&(QO_NODE_OUTER_DEP_SET (node)), env);
8104  bitset_init (&(QO_NODE_RIGHT_DEP_SET (node)), env);
8105 
8106  QO_NODE_HINT (node) = PT_HINT_NONE;
8107 }
8108 
8109 /*
8110  * qo_node_free () -
8111  * return:
8112  * node(in):
8113  */
8114 static void
8116 {
8117  bitset_delset (&(QO_NODE_EQCLASSES (node)));
8118  bitset_delset (&(QO_NODE_SARGS (node)));
8119  bitset_delset (&(QO_NODE_DEP_SET (node)));
8120  bitset_delset (&(QO_NODE_SEGS (node)));
8121  bitset_delset (&(QO_NODE_SUBQUERIES (node)));
8124  qo_free_class_info (QO_NODE_ENV (node), QO_NODE_INFO (node));
8125  if (QO_NODE_INDEXES (node))
8126  {
8128  }
8129  if (QO_NODE_USING_INDEX (node))
8130  {
8132  }
8133 }
8134 
8135 /*
8136  * qo_node_add_sarg () -
8137  * return:
8138  * node(in):
8139  * sarg(in):
8140  */
8141 static void
8143 {
8144  double sel_limit;
8145 
8146  bitset_add (&(QO_NODE_SARGS (node)), QO_TERM_IDX (sarg));
8147  QO_NODE_SELECTIVITY (node) *= QO_TERM_SELECTIVITY (sarg);
8148  sel_limit = (QO_NODE_NCARD (node) == 0) ? 0 : (1.0 / (double) QO_NODE_NCARD (node));
8149  if (QO_NODE_SELECTIVITY (node) < sel_limit)
8150  {
8151  QO_NODE_SELECTIVITY (node) = sel_limit;
8152  }
8153 }
8154 
8155 /*
8156  * qo_node_fprint () -
8157  * return:
8158  * node(in):
8159  * f(in):
8160  */
8161 void
8162 qo_node_fprint (QO_NODE * node, FILE * f)
8163 {
8164  if (QO_NODE_NAME (node))
8165  {
8166  fprintf (f, "%s", QO_NODE_NAME (node));
8167  }
8168  fprintf (f, " node[%d]", QO_NODE_IDX (node));
8169 }
8170 
8171 /*
8172  * qo_node_dump () -
8173  * return:
8174  * node(in):
8175  * f(in):
8176  */
8177 static void
8178 qo_node_dump (QO_NODE * node, FILE * f)
8179 {
8180  int i, n = 1;
8181  const char *name;
8182  PT_NODE *entity;
8183 
8184  entity = QO_NODE_ENTITY_SPEC (node);
8185 
8186  if (QO_NODE_INFO (node))
8187  {
8188  n = QO_NODE_INFO_N (node);
8189  if (n > 1)
8190  {
8191  fprintf (f, "("); /* left paren */
8192  }
8193  for (i = 0; i < n; i++)
8194  {
8195  name = QO_NODE_INFO (node)->info[i].name;
8196  /* check for class OID reference spec for example: 'class x' SELECT class_meth(class x, x.i) FROM x, class x */
8197  if (i == 0)
8198  { /* the first entity */
8199  fprintf (f, (entity->info.spec.meta_class == PT_META_CLASS ? "class %s" : "%s"),
8200  (name ? name : "(anon)"));
8201  }
8202  else
8203  {
8204  fprintf (f, (entity->info.spec.meta_class == PT_META_CLASS ? ", class %s" : ", %s"),
8205  (name ? name : "(anon)"));
8206  }
8207  }
8208  fprintf (f, "%s ", (n > 1 ? ")" : "")); /* right paren */
8209  }
8210  name = QO_NODE_NAME (node);
8211  if (n == 1)
8212  {
8213  fprintf (f, "%s", (name ? name : "(unknown)"));
8214  }
8215  else
8216  {
8217  fprintf (f, "as %s", (name ? name : "(unknown)"));
8218  }
8219 
8220  if (entity->info.spec.range_var->alias_print)
8221  {
8222  fprintf (f, "(%s)", entity->info.spec.range_var->alias_print);
8223  }
8224 
8225  fprintf (f, "(%lu/%lu)", QO_NODE_NCARD (node), QO_NODE_TCARD (node));
8226  if (!bitset_is_empty (&(QO_NODE_SARGS (node))))
8227  {
8228  fputs (" (sargs ", f);
8229  bitset_print (&(QO_NODE_SARGS (node)), f);
8230  fputs (")", f);
8231  }
8232  if (!bitset_is_empty (&(QO_NODE_OUTER_DEP_SET (node))))
8233  {
8234  fputs (" (outer-dep-set ", f);
8235  bitset_print (&(QO_NODE_OUTER_DEP_SET (node)), f);
8236  fputs (")", f);
8237  }
8238  if (!bitset_is_empty (&(QO_NODE_DEP_SET (node))))
8239  {
8240  fputs (" (dep-set ", f);
8241  bitset_print (&(QO_NODE_DEP_SET (node)), f);
8242  fputs (")", f);
8243  }
8244  if (!bitset_is_empty (&(QO_NODE_RIGHT_DEP_SET (node))))
8245  {
8246  fputs (" (right-dep-set ", f);
8247  bitset_print (&(QO_NODE_RIGHT_DEP_SET (node)), f);
8248  fputs (")", f);
8249  }
8250 
8251  fprintf (f, " (loc %d)", entity->info.spec.location);
8252 }
8253 
8254 /*
8255  * qo_seg_clear () -
8256  * return:
8257  * env(in):
8258  * idx(in):
8259  */
8260 static void
8261 qo_seg_clear (QO_ENV * env, int idx)
8262 {
8263  QO_SEGMENT *seg = QO_ENV_SEG (env, idx);
8264 
8265  QO_SEG_ENV (seg) = env;
8266  QO_SEG_HEAD (seg) = NULL;
8267  QO_SEG_TAIL (seg) = NULL;
8268  QO_SEG_EQ_ROOT (seg) = NULL;
8269  QO_SEG_EQCLASS (seg) = NULL;
8270  QO_SEG_NAME (seg) = NULL;
8271  QO_SEG_INFO (seg) = NULL;
8272  QO_SEG_SET_VALUED (seg) = false;
8273  QO_SEG_CLASS_ATTR (seg) = false;
8274  QO_SEG_SHARED_ATTR (seg) = false;
8275  QO_SEG_IDX (seg) = idx;
8276  QO_SEG_FUNC_INDEX (seg) = false;
8277  bitset_init (&(QO_SEG_INDEX_TERMS (seg)), env);
8278 }
8279 
8280 /*
8281  * qo_seg_free () -
8282  * return:
8283  * seg(in):
8284  */
8285 static void
8287 {
8288  if (QO_SEG_INFO (seg) != NULL)
8289  {
8290  qo_free_attr_info (QO_SEG_ENV (seg), QO_SEG_INFO (seg));
8291  if (QO_SEG_FUNC_INDEX (seg) == true)
8292  {
8293  if (QO_SEG_NAME (seg))
8294  {
8295  free_and_init (QO_SEG_NAME (seg));
8296  }
8297  }
8298  }
8299  bitset_delset (&(QO_SEG_INDEX_TERMS (seg)));
8300 }
8301 
8302 /*
8303  * qo_seg_width () -
8304  * return: size_t
8305  * seg(in): A pointer to a QO_SEGMENT
8306  *
8307  * Note: Return the estimated width (in size_t units) of the indicated
8308  * attribute. This estimate will be required to estimate the
8309  * size of intermediate results should they need to be
8310  * materialized for e.g. sorting.
8311  */
8312 int
8314 {
8315  /*
8316  * This needs to consult the schema manager (or somebody) to
8317  * determine the type of the underlying attribute. For set-valued
8318  * attributes, this is truly an estimate, since the size of the
8319  * attribute in any result tuple will be the product of the
8320  * cardinality of that particular set and the size of the underlying
8321  * element type.
8322  */
8323  int size;
8324  DB_DOMAIN *domain;
8325 
8327  if (domain)
8328  {
8329  domain = tp_domain_cache (domain);
8330  }
8331  else
8332  {
8333  /* guessing */
8334  return sizeof (int);
8335  }
8336 
8337  size = tp_domain_disk_size (domain);
8338  switch (TP_DOMAIN_TYPE (domain))
8339  {
8340  case DB_TYPE_VARBIT:
8341  case DB_TYPE_VARCHAR:
8342  case DB_TYPE_VARNCHAR:
8343  /* do guessing for variable character type */
8344  size = size * (2 / 3);
8345  break;
8346  default:
8347  break;
8348  }
8349 
8350  return MAX ((int) sizeof (int), size);
8351  /* for backward compatibility, at least sizeof(long) */
8352 }
8353 
8354 /*
8355  * qo_seg_fprint () -
8356  * return:
8357  * seg(in):
8358  * f(in):
8359  */
8360 void
8361 qo_seg_fprint (QO_SEGMENT * seg, FILE * f)
8362 {
8363  fprintf (f, "%s[%d]", QO_SEG_NAME (seg), QO_NODE_IDX (QO_SEG_HEAD (seg)));
8364 }
8365 
8366 /*
8367  * qo_eqclass_new () -
8368  * return:
8369  * env(in):
8370  */
8371 static QO_EQCLASS *
8373 {
8374  QO_EQCLASS *eqclass;
8375 
8376  QO_ASSERT (env, env->neqclasses < env->Neqclasses);
8377  eqclass = QO_ENV_EQCLASS (env, env->neqclasses);
8378 
8379  QO_EQCLASS_ENV (eqclass) = env;
8380  QO_EQCLASS_IDX (eqclass) = env->neqclasses;
8381  QO_EQCLASS_TERM (eqclass) = NULL;
8382 
8383  bitset_init (&(QO_EQCLASS_SEGS (eqclass)), env);
8384 
8385  env->neqclasses++;
8386 
8387  return eqclass;
8388 }
8389 
8390 /*
8391  * qo_eqclass_free () -
8392  * return:
8393  * eqclass(in):
8394  */
8395 static void
8397 {
8398  bitset_delset (&(QO_EQCLASS_SEGS (eqclass)));
8399 }
8400 
8401 /*
8402  * qo_eqclass_add () -
8403  * return:
8404  * eqclass(in):
8405  * seg(in):
8406  */
8407 static void
8409 {
8410  bitset_add (&(QO_EQCLASS_SEGS (eqclass)), QO_SEG_IDX (seg));
8411  bitset_add (&(QO_NODE_EQCLASSES (QO_SEG_HEAD (seg))), QO_EQCLASS_IDX (eqclass));
8412  QO_SEG_EQCLASS (seg) = eqclass;
8413 }
8414 
8415 /*
8416  * qo_eqclass_dump () -
8417  * return:
8418  * eqclass(in):
8419  * f(in):
8420  */
8421 static void
8422 qo_eqclass_dump (QO_EQCLASS * eqclass, FILE * f)
8423 {
8424  const char *prefix = "";
8425  int member;
8426  QO_ENV *env = QO_EQCLASS_ENV (eqclass);
8427  BITSET_ITERATOR bi;
8428 
8429  if (QO_EQCLASS_TERM (eqclass))
8430  {
8431  qo_term_fprint (QO_EQCLASS_TERM (eqclass), f);
8432  }
8433  else
8434  {
8435  for (member = bitset_iterate (&(QO_EQCLASS_SEGS (eqclass)), &bi); member != -1; member = bitset_next_member (&bi))
8436  {
8437  fputs (prefix, f);
8438  qo_seg_fprint (QO_ENV_SEG (env, member), f);
8439  prefix = " ";
8440  }
8441  }
8442 }
8443 
8444 /*
8445  * qo_term_clear () -
8446  * return:
8447  * env(in):
8448  * idx(in):
8449  */
8450 static void
8451 qo_term_clear (QO_ENV * env, int idx)
8452 {
8453  QO_TERM *term = QO_ENV_TERM (env, idx);
8454 
8455  QO_TERM_ENV (term) = env;
8456  QO_TERM_CLASS (term) = QO_TC_OTHER;
8457  QO_TERM_SELECTIVITY (term) = 1.0;
8458  QO_TERM_RANK (term) = 0;
8459  QO_TERM_PT_EXPR (term) = NULL;
8460  QO_TERM_LOCATION (term) = 0;
8461  QO_TERM_SEG (term) = NULL;
8462  QO_TERM_OID_SEG (term) = NULL;
8463  QO_TERM_HEAD (term) = NULL;
8464  QO_TERM_TAIL (term) = NULL;
8465  QO_TERM_EQCLASS (term) = QO_UNORDERED;
8466  QO_TERM_NOMINAL_SEG (term) = NULL;
8467  QO_TERM_IDX (term) = idx;
8468 
8469  QO_TERM_CAN_USE_INDEX (term) = 0;
8470  QO_TERM_INDEX_SEG (term, 0) = NULL;
8471  QO_TERM_INDEX_SEG (term, 1) = NULL;
8472  QO_TERM_JOIN_TYPE (term) = NO_JOIN;
8473  QO_TERM_MULTI_COL_SEGS (term) = NULL;
8474  QO_TERM_MULTI_COL_CNT (term) = 0;
8475 
8476  bitset_init (&(QO_TERM_NODES (term)), env);
8477  bitset_init (&(QO_TERM_SEGS (term)), env);
8478  bitset_init (&(QO_TERM_SUBQUERIES (term)), env);
8479 
8480  QO_TERM_FLAG (term) = 0;
8481 }
8482 
8483 /*
8484  * qo_discover_sort_limit_nodes () - discover the subset of nodes on which
8485  * a SORT_LIMIT plan can be applied.
8486  * return : void
8487  * env (in) : env
8488  *
8489  * Note: This function discovers a subset of nodes on which a SORT_LIMIT plan
8490  * can be applied without altering the result of the query.
8491  */
8492 static void
8494 {
8495  PT_NODE *query, *orderby, *sort_col, *select_list, *col, *save_next;
8496  int i, pos_spec, limit_max_count;
8497  QO_NODE *node;
8498  BITSET order_nodes, dep_nodes, expr_segs, tmp_bitset;
8499  BITSET_ITERATOR bi;
8500 
8501  bitset_init (&order_nodes, env);
8502  bitset_init (&QO_ENV_SORT_LIMIT_NODES (env), env);
8503 
8504  query = QO_ENV_PT_TREE (env);
8505  if (!PT_IS_SELECT (query))
8506  {
8507  goto abandon_stop_limit;
8508  }
8509  if (query->info.query.all_distinct != PT_ALL || query->info.query.q.select.group_by != NULL
8510  || query->info.query.q.select.connect_by != NULL)
8511  {
8512  goto abandon_stop_limit;
8513  }
8515  {
8516  goto abandon_stop_limit;
8517  }
8518 
8520  {
8521  /* unusable limit */
8522  goto abandon_stop_limit;
8523  }
8524 
8525  if (env->npartitions > 1)
8526  {
8527  /* not applicable when dealing with more than one partition */
8528  goto abandon_stop_limit;
8529  }
8530 
8532  {
8533  /* No need to apply this optimization on a single node */
8534  goto abandon_stop_limit;
8535  }
8536 
8537  orderby = query->info.query.order_by;
8538  if (orderby == NULL)
8539  {
8540  goto abandon_stop_limit;
8541  }
8542 
8544 
8545  /* Verify that we don't have terms qualified as after join. These terms will be evaluated after the SORT-LIMIT plan
8546  * and might invalidate tuples the plan returned.
8547  */
8548  for (i = 0; i < env->nterms; i++)
8549  {
8550  if (QO_TERM_CLASS (&env->terms[i]) == QO_TC_AFTER_JOIN || QO_TERM_CLASS (&env->terms[i]) == QO_TC_OTHER)
8551  {
8552  goto abandon_stop_limit;
8553  }
8554  }
8555 
8556  /* Start by assuming that evaluation of the limit clause depends on all nodes in the query. Since we only have one
8557  * partition, we can get the bitset of nodes from there.
8558  */
8560 
8561  select_list = pt_get_select_list (QO_ENV_PARSER (env), query);
8562  assert_release (select_list != NULL);
8563 
8564  /* Only consider ORDER BY expression which is evaluable during a scan. This means any expression except analytic and
8565  * aggregate functions.
8566  */
8567  for (sort_col = orderby; sort_col != NULL; sort_col = sort_col->next)
8568  {
8569  if (sort_col->node_type != PT_SORT_SPEC)
8570  {
8571  goto abandon_stop_limit;
8572  }
8573 
8574  bitset_init (&expr_segs, env);
8575  bitset_init (&tmp_bitset, env);
8576 
8577  pos_spec = sort_col->info.sort_spec.pos_descr.pos_no;
8578 
8579  /* sort_col is a position specifier in select list. Have to walk the select list to find the actual node */
8580  for (i = 1, col = select_list; col != NULL && i != pos_spec; col = col->next, i++);
8581 
8582  if (col == NULL)
8583  {
8584  assert_release (col != NULL);
8585  goto abandon_stop_limit;
8586  }
8587 
8588  save_next = col->next;
8589  col->next = NULL;
8590  if (pt_has_analytic (QO_ENV_PARSER (env), col) || pt_has_aggregate (QO_ENV_PARSER (env), col))
8591  {
8592  /* abandon search because these expressions cannot be evaluated during SORT_LIMIT evaluation */
8593  col->next = save_next;
8594  goto abandon_stop_limit;
8595  }
8596 
8597  /* get segments from col */
8598  qo_expr_segs (env, col, &expr_segs);
8599  /* get nodes for segments */
8600  qo_seg_nodes (env, &expr_segs, &tmp_bitset);
8601 
8602  /* accumulate nodes to order_nodes */
8603  bitset_union (&order_nodes, &tmp_bitset);
8604 
8605  bitset_delset (&expr_segs);
8606  bitset_delset (&tmp_bitset);
8607 
8608  col->next = save_next;
8609  }
8610 
8611  for (i = bitset_iterate (&order_nodes, &bi); i != -1; i = bitset_next_member (&bi))
8612  {
8613  bitset_init (&dep_nodes, env);
8614  node = QO_ENV_NODE (env, i);
8615 
8616  /* For each orderby node, gather nodes which are SORT_LIMIT independent on this node and remove them from
8617  * sort_limit_nodes.
8618  */
8619  qo_discover_sort_limit_join_nodes (env, node, &order_nodes, &dep_nodes);
8620  bitset_difference (&env->sort_limit_nodes, &dep_nodes);
8621 
8622  bitset_delset (&dep_nodes);
8623  }
8624 
8625  if (bitset_cardinality (&env->sort_limit_nodes) == env->Nnodes)
8626  {
8627  /* There is no subset of nodes on which we can apply SORT_LIMIT so abandon this optimization */
8628  goto abandon_stop_limit;
8629  }
8630 
8631  bitset_delset (&order_nodes);
8632 
8633  /* In order to create a SORT-LIMIT plan, the query must have a valid limit. All other conditions for creating the
8634  * plan have been met.
8635  */
8636  if (DB_IS_NULL (&QO_ENV_LIMIT_VALUE (env)))
8637  {
8638  /* Cannot make a decision at this point. Go ahead with query compilation as if this optimization does not apply.
8639  * The query will be recompiled once a valid limit is supplied. */
8640  goto sort_limit_possible;
8641  }
8642 
8644  if (limit_max_count == 0)
8645  {
8646  /* SORT-LIMIT plans are disabled */
8647  goto abandon_stop_limit;
8648  }
8649 
8650  if ((DB_BIGINT) limit_max_count < db_get_bigint (&QO_ENV_LIMIT_VALUE (env)))
8651  {
8652  /* Limit too large to apply this optimization. Mark it as candidate but do not generate SORT-LIMIT plans at this
8653  * time.
8654  */
8655  goto sort_limit_possible;
8656  }
8657 
8658  if (bitset_cardinality (&env->sort_limit_nodes) == 1)
8659  {
8660  /* Mark this node as a sort stop candidate. We will generate a SORT-LIMIT plan over this node. */
8661  int n = bitset_first_member (&order_nodes);
8662  node = QO_ENV_NODE (env, n);
8663  QO_NODE_SORT_LIMIT_CANDIDATE (node) = true;
8664  }
8665 
8666  env->use_sort_limit = QO_SL_USE;
8667  return;
8668 
8669 sort_limit_possible:
8672  return;
8673 
8674 abandon_stop_limit:
8675  bitset_delset (&order_nodes);
8678 }
8679 
8680 /*
8681  * qo_equivalence () -
8682  * return:
8683  * sega(in):
8684  * segb(in):
8685  */
8686 static void
8688 {
8689 
8690  while (QO_SEG_EQ_ROOT (sega))
8691  {
8692  sega = QO_SEG_EQ_ROOT (sega);
8693  }
8694  while (QO_SEG_EQ_ROOT (segb))
8695  {
8696  segb = QO_SEG_EQ_ROOT (segb);
8697  }
8698 
8699  if (sega != segb)
8700  {
8701  QO_SEG_EQ_ROOT (sega) = segb;
8702  }
8703 }
8704 
8705 /*
8706  * qo_eqclass_wrt () -
8707  * return:
8708  * eqclass(in):
8709  * nodeset(in):
8710  */
8711 static QO_SEGMENT *
8712 qo_eqclass_wrt (QO_EQCLASS * eqclass, BITSET * nodeset)
8713 {
8714  int member;
8715  BITSET_ITERATOR si;
8716  QO_SEGMENT *result = NULL;
8717 
8718  for (member = bitset_iterate (&(QO_EQCLASS_SEGS (eqclass)), &si); member != -1; member = bitset_next_member (&si))
8719  {
8720  QO_SEGMENT *seg = QO_ENV_SEG (QO_EQCLASS_ENV (eqclass), member);
8721  if (BITSET_MEMBER (*nodeset, QO_NODE_IDX (QO_SEG_HEAD (seg))))
8722  {
8723  result = seg;
8724  break;
8725  }
8726  }
8727 
8728  QO_ASSERT (eqclass->env, result != NULL);
8729  return result;
8730 }
8731 
8732 /*
8733  * qo_eqclass_fprint_wrt () -
8734  * return:
8735  * eqclass(in):
8736  * nodeset(in):
8737  * f(in):
8738  */
8739 void
8740 qo_eqclass_fprint_wrt (QO_EQCLASS * eqclass, BITSET * nodeset, FILE * f)
8741 {
8742  if (eqclass == QO_UNORDERED)
8743  {
8744  fputs ("UNORDERED", f);
8745  }
8746  else if (bitset_is_empty (&(QO_EQCLASS_SEGS (eqclass))))
8747  {
8748  /*
8749  * This is a phony eqclass created for a complex merge join.
8750  * Just fabricate some text that will let us know where it came
8751  * from...
8752  */
8753  fprintf (f, "phony (term[%d])", QO_TERM_IDX (QO_EQCLASS_TERM (eqclass)));
8754  }
8755  else
8756  {
8757  qo_seg_fprint (qo_eqclass_wrt (eqclass, nodeset), f);
8758  }
8759 }
8760 
8761 /*
8762  * qo_term_free () -
8763  * return:
8764  * term(in):
8765  */
8766 static void
8768 {
8769  /*
8770  * Free the expr alloced by this term
8771  */
8773  {
8775  }
8776  bitset_delset (&(QO_TERM_NODES (term)));
8777  bitset_delset (&(QO_TERM_SEGS (term)));
8778  bitset_delset (&(QO_TERM_SUBQUERIES (term)));
8779  if (QO_TERM_MULTI_COL_SEGS (term))
8780  {
8782  }
8783 }
8784 
8785 /*
8786  * qo_term_fprint () -
8787  * return:
8788  * term(in):
8789  * f(in):
8790  */
8791 void
8793 {
8794  QO_TERMCLASS tc;
8795 
8796  if (term)
8797  {
8798  switch (tc = QO_TERM_CLASS (term))
8799  {
8800  case QO_TC_PATH:
8801  qo_node_fprint (QO_TERM_HEAD (term), f);
8802  if (!QO_TERM_SEG (term) || !QO_SEG_NAME (QO_TERM_SEG (term)))
8803  {
8804  fprintf (f, " () -> ");
8805  }
8806  else
8807  {
8808  fprintf (f, " %s -> ", QO_SEG_NAME (QO_TERM_SEG (term)));
8809  }
8810  qo_node_fprint (QO_TERM_TAIL (term), f);
8811  break;
8812 
8813  case QO_TC_DEP_LINK:
8814  fprintf (f, "table(");
8815  bitset_print (&(QO_NODE_DEP_SET (QO_TERM_TAIL (term))), f);
8816  fprintf (f, ") -> ");
8817  qo_node_fprint (QO_TERM_TAIL (term), f);
8818  break;
8819 
8820  case QO_TC_DEP_JOIN:
8821  qo_node_fprint (QO_TERM_HEAD (term), f);
8822  fprintf (f, " <dj> ");
8823  qo_node_fprint (QO_TERM_TAIL (term), f);
8824  break;
8825 
8826  default:
8827  fprintf (f, "term[%d]", QO_TERM_IDX (term));
8828  break;
8829  }
8830  }
8831  else
8832  {
8833  fprintf (f, "none");
8834  }
8835 }
8836 
8837 /*
8838  * qo_termset_fprint () -
8839  * return:
8840  * env(in):
8841  * terms(in):
8842  * f(in):
8843  */
8844 void
8845 qo_termset_fprint (QO_ENV * env, BITSET * terms, FILE * f)
8846 {
8847  int tx;
8848  BITSET_ITERATOR si;
8849  const char *prefix = "";
8850 
8851  for (tx = bitset_iterate (terms, &si); tx != -1; tx = bitset_next_member (&si))
8852  {
8853  fputs (prefix, f);
8854  qo_term_fprint (QO_ENV_TERM (env, tx), f);
8855  prefix = " AND ";
8856  }
8857 }
8858 
8859 /*
8860  * qo_term_dump () -
8861  * return:
8862  * term(in):
8863  * f(in):
8864  */
8865 static void
8867 {
8868  PT_NODE *conj, *saved_next = NULL;
8869  QO_TERMCLASS tc;
8870 
8871  conj = QO_TERM_PT_EXPR (term);
8872  if (conj)
8873  {
8874  saved_next = conj->next;
8875  conj->next = NULL;
8876  }
8877 
8878  tc = QO_TERM_CLASS (term);
8879  switch (tc)
8880  {
8881  case QO_TC_PATH:
8882  qo_node_fprint (QO_TERM_HEAD (term), f);
8883  if (!QO_TERM_SEG (term) || !QO_SEG_NAME (QO_TERM_SEG (term)))
8884  {
8885  fprintf (f, " () -> ");
8886  }
8887  else
8888  {
8889  fprintf (f, " %s -> ", QO_SEG_NAME (QO_TERM_SEG (term)));
8890  }
8891  qo_node_fprint (QO_TERM_TAIL (term), f);
8892  break;
8893 
8894  case QO_TC_DEP_LINK:
8895  fprintf (f, "table(");
8896  bitset_print (&(QO_NODE_DEP_SET (QO_TERM_TAIL (term))), f);
8897  fprintf (f, ") -> ");
8898  qo_node_fprint (QO_TERM_TAIL (term), f);
8899  break;
8900 
8901  case QO_TC_DEP_JOIN:
8902  qo_node_fprint (QO_TERM_HEAD (term), f);
8903  fprintf (f, " <dj> ");
8904  qo_node_fprint (QO_TERM_TAIL (term), f);
8905  break;
8906 
8907  case QO_TC_DUMMY_JOIN:
8908  if (conj)
8909  { /* may be transitive dummy join term */
8910  fprintf (f, "%s", parser_print_tree (QO_ENV_PARSER (QO_TERM_ENV (term)), conj));
8911  }
8912  else
8913  {
8914  qo_node_fprint (QO_TERM_HEAD (term), f);
8915  fprintf (f, ", ");
8916  qo_node_fprint (QO_TERM_TAIL (term), f);
8917  }
8918  break;
8919 
8920  default:
8921  assert_release (conj != NULL);
8922  if (conj)
8923  {
8925  PT_PRINT_VALUE_FUNC saved_func = parser->print_db_value;
8926 
8927  /* in order to print auto parameterized values */
8929  fprintf (f, "%s", parser_print_tree (parser, conj));
8930  parser->print_db_value = saved_func;
8931  }
8932  break;
8933  }
8934  fprintf (f, " (sel %g)", QO_TERM_SELECTIVITY (term));
8935 
8936  if (QO_TERM_RANK (term) > 1)
8937  {
8938  fprintf (f, " (rank %d)", QO_TERM_RANK (term));
8939  }
8940 
8941  switch (QO_TERM_CLASS (term))
8942  {
8943  case QO_TC_PATH:
8944  fprintf (f, " (path term)");
8945  break;
8946  case QO_TC_JOIN:
8947  fprintf (f, " (join term)");
8948  break;
8949  case QO_TC_SARG:
8950  fprintf (f, " (sarg term)");
8951  break;
8952  case QO_TC_OTHER:
8953  {
8954  if (conj && conj->node_type == PT_VALUE && conj->info.value.location == 0)
8955  {
8956  /* is an always-false or always-true WHERE condition */
8957  fprintf (f, " (dummy sarg term)");
8958  }
8959  else
8960  {
8961  fprintf (f, " (other term)");
8962  }
8963  }
8964  break;
8965  case QO_TC_DEP_LINK:
8966  fprintf (f, " (dep term)");
8967  break;
8968  case QO_TC_DEP_JOIN:
8969  fprintf (f, " (dep-join term)");
8970  break;
8971  case QO_TC_DURING_JOIN:
8972  fprintf (f, " (during join term)");
8973  break;
8974  case QO_TC_AFTER_JOIN:
8975  fprintf (f, " (after join term)");
8976  break;
8978  fprintf (f, " (instnum term)");
8979  break;
8980  case QO_TC_DUMMY_JOIN:
8981  fprintf (f, " (dummy join term)");
8982  break;
8983  default:
8984  break;
8985  }
8986 
8988  {
8989  fputs (" (mergeable)", f);
8990  }
8991 
8992  switch (QO_TERM_JOIN_TYPE (term))
8993  {
8994  case NO_JOIN:
8995  fputs (" (not-join eligible)", f);
8996  break;
8997 
8998  case JOIN_INNER:
8999  fputs (" (inner-join)", f);
9000  break;
9001 
9002  case JOIN_LEFT:
9003  fputs (" (left-join)", f);
9004  break;
9005 
9006  case JOIN_RIGHT:
9007  fputs (" (right-join)", f);
9008  break;
9009 
9010  case JOIN_OUTER: /* not used */
9011  fputs (" (outer-join)", f);
9012  break;
9013 
9014  default:
9015  break;
9016  }
9017 
9018  if (QO_TERM_CAN_USE_INDEX (term))
9019  {
9020  int i;
9021  fputs (" (indexable", f);
9022  for (i = 0; i < QO_TERM_CAN_USE_INDEX (term); i++)
9023  {
9024  fputs (" ", f);
9025  qo_seg_fprint (QO_TERM_INDEX_SEG (term, i), f);
9026  }
9027  fputs (")", f);
9028  }
9029 
9030  fprintf (f, " (loc %d)", QO_TERM_LOCATION (term));
9031 
9032  /* restore link */
9033  if (conj)
9034  {
9035  conj->next = saved_next;
9036  }
9037 }
9038 
9039 /*
9040  * qo_subquery_dump () -
9041  * return:
9042  * env(in):
9043  * subq(in):
9044  * f(in):
9045  */
9046 static void
9047 qo_subquery_dump (QO_ENV * env, QO_SUBQUERY * subq, FILE * f)
9048 {
9049  int i;
9050  BITSET_ITERATOR bi;
9051  const char *separator;
9052 
9053  fprintf (f, "%p", (void *) subq->node);
9054 
9055  separator = NULL;
9056  fputs (" {", f);
9057  for (i = bitset_iterate (&(subq->segs), &bi); i != -1; i = bitset_next_member (&bi))
9058  {
9059  if (separator)
9060  {
9061  fputs (separator, f);
9062  }
9063  qo_seg_fprint (QO_ENV_SEG (env, i), f);
9064  separator = " ";
9065  }
9066  fputs ("}", f);
9067 
9068  separator = "";
9069  fputs (" {", f);
9070  for (i = bitset_iterate (&(subq->nodes), &bi); i != -1; i = bitset_next_member (&bi))
9071  {
9072  fprintf (f, "%snode[%d]", separator, i);
9073  separator = " ";
9074  }
9075  fputs ("}", f);
9076 
9077  fputs (" (from term(s)", f);
9078  for (i = bitset_iterate (&(subq->terms), &bi); i != -1; i = bitset_next_member (&bi))
9079  {
9080  fprintf (f, " %d", i);
9081  }
9082  fputs (")", f);
9083 }
9084 
9085 /*
9086  * qo_subquery_free () -
9087  * return:
9088  * subq(in):
9089  */
9090 static void
9092 {
9093  bitset_delset (&(subq->segs));
9094  bitset_delset (&(subq->nodes));
9095  bitset_delset (&(subq->terms));
9096 }
9097 
9098 /*
9099  * qo_partition_init () -
9100  * return:
9101  * env(in):
9102  * part(in):
9103  * n(in):
9104  */
9105 static void
9106 qo_partition_init (QO_ENV * env, QO_PARTITION * part, int n)
9107 {
9108  bitset_init (&(QO_PARTITION_NODES (part)), env);
9109  bitset_init (&(QO_PARTITION_EDGES (part)), env);
9110  bitset_init (&(QO_PARTITION_DEPENDENCIES (part)), env);
9111  QO_PARTITION_M_OFFSET (part) = 0;
9112  QO_PARTITION_PLAN (part) = NULL;
9113  QO_PARTITION_IDX (part) = n;
9114 }
9115 
9116 /*
9117  * qo_partition_free () -
9118  * return:
9119  * part(in):
9120  */
9121 static void
9123 {
9124  bitset_delset (&(QO_PARTITION_NODES (part)));
9125  bitset_delset (&(QO_PARTITION_EDGES (part)));
9127 
9128 #if 0
9129  /*
9130  * Do *not* free the plan here; it already had its ref count bumped
9131  * down during combine_partitions(), and it will be (has been)
9132  * collected by the call to qo_plan_discard() that freed the
9133  * top-level plan. What we have here is a dangling pointer.
9134  */
9136 #else
9137  QO_PARTITION_PLAN (part) = NULL;
9138 #endif
9139 }
9140 
9141 
9142 /*
9143  * qo_partition_dump () -
9144  * return:
9145  * part(in):
9146  * f(in):
9147  */
9148 static void
9150 {
9151  fputs ("(nodes ", f);
9152  bitset_print (&(QO_PARTITION_NODES (part)), f);
9153  fputs (") (edges ", f);
9154  bitset_print (&(QO_PARTITION_EDGES (part)), f);
9155  fputs (") (dependencies ", f);
9156  bitset_print (&(QO_PARTITION_DEPENDENCIES (part)), f);
9157  fputs (")", f);
9158 }
9159 
9160 /*
9161  * qo_print_stats () -
9162  * return:
9163  * f(in):
9164  */
9165 void
9166 qo_print_stats (FILE * f)
9167 {
9168  fputs ("\n", f);
9169  qo_info_stats (f);
9170  qo_plans_stats (f);
9171 #if defined (CUBRID_DEBUG)
9172  set_stats (f);
9173 #endif
9174 }
9175 
9176 /*
9177  * qo_seg_nodes () - Return a bitset of node ids produced from the heads
9178  * of all of the segments in segset
9179  * return:
9180  * env(in): The environment in which these segment and node ids make sense
9181  * segset(in): A bitset of segment ids
9182  * result(out): A bitset of node ids (OUTPUT PARAMETER)
9183  */
9184 static void
9185 qo_seg_nodes (QO_ENV * env, BITSET * segset, BITSET * result)
9186 {
9187  BITSET_ITERATOR si;
9188  int i;
9189 
9190  BITSET_CLEAR (*result);
9191  for (i = bitset_iterate (segset, &si); i != -1; i = bitset_next_member (&si))
9192  {
9193  bitset_add (result, QO_NODE_IDX (QO_SEG_HEAD (QO_ENV_SEG (env, i))));
9194  }
9195 }
9196 
9197 /*
9198  * qo_is_prefix_index () - Find out if this is a prefix index
9199  * return:
9200  * ent(in): index entry
9201  */
9202 bool
9204 {
9205  if (ent && ent->class_ && ent->class_->smclass)
9206  {
9207  SM_CLASS_CONSTRAINT *cons;
9208 
9210  if (cons)
9211  {
9212  if (cons->attrs_prefix_length && cons->attrs_prefix_length[0] != -1)
9213  {
9214  return true;
9215  }
9216  }
9217  }
9218 
9219  return false;
9220 }
9221 
9222 /*
9223  * qo_is_filter_index () - Find out if this is a filter index
9224  * return: true/false
9225  * ent(in): index entry
9226  */
9227 bool
9229 {
9230  if (ent && ent->constraints)
9231  {
9232  if (ent->constraints->filter_predicate && ent->force > 0)
9233  {
9234  return true;
9235  }
9236  }
9237 
9238  return false;
9239 }
9240 
9241 /*
9242  * qo_check_coll_optimization () - Checks for attributes with collation in
9243  * index and fills the optimization structure
9244  *
9245  * return:
9246  * ent(in): index entry
9247  * collation_opt(out):
9248  *
9249  * Note : this only checks for index covering optimization.
9250  * If at least one attribute of index does not support index covering,
9251  * this option will be disabled for the entire index.
9252  */
9253 void
9255 {
9256  assert (collation_opt != NULL);
9257 
9258  collation_opt->allow_index_opt = true;
9259 
9260  if (ent && ent->class_ && ent->class_->smclass)
9261  {
9262  SM_CLASS_CONSTRAINT *cons;
9263  SM_ATTRIBUTE **attr;
9265  if (cons == NULL || cons->attributes == NULL)
9266  {
9267  return;
9268  }
9269 
9270  for (attr = cons->attributes; *attr != NULL; attr++)
9271  {
9272  if ((*attr)->domain != NULL && TP_TYPE_HAS_COLLATION (TP_DOMAIN_TYPE ((*attr)->domain)))
9273  {
9274  LANG_COLLATION *lang_coll = lang_get_collation (TP_DOMAIN_COLLATION ((*attr)->domain));
9275 
9276  assert (lang_coll != NULL);
9277 
9278  if (!(lang_coll->options.allow_index_opt))
9279  {
9280  collation_opt->allow_index_opt = false;
9281  return;
9282  }
9283  }
9284  }
9285  }
9286 }
9287 
9288 
9289 /*
9290  * qo_check_type_index_covering () - Checks for attributes with types not able
9291  * to support index covering
9292  *
9293  * return:
9294  * ent(in): index entry
9295  * collation_opt(out):
9296  *
9297  * Note : this only checks for index covering optimization.
9298  * If at least one attribute of index does not support index covering,
9299  * this option will be disabled for the entire index.
9300  */
9301 bool
9303 {
9304  if (ent && ent->class_ && ent->class_->smclass)
9305  {
9306  SM_CLASS_CONSTRAINT *cons;
9307  SM_ATTRIBUTE **attr;
9308 
9310  if (cons == NULL || cons->attributes == NULL)
9311  {
9312  return true;
9313  }
9314 
9315  for (attr = cons->attributes; *attr != NULL; attr++)
9316  {
9317  if ((*attr)->domain != NULL && TP_TYPE_NOT_SUPPORT_COVERING (TP_DOMAIN_TYPE ((*attr)->domain)))
9318  {
9319  return false;
9320  }
9321  }
9322  }
9323 
9324  return true;
9325 }
9326 
9327 /*
9328  * qo_discover_sort_limit_join_nodes () - discover nodes which are joined to
9329  * this node and do not need to be
9330  * taken into consideration when
9331  * evaluating sort and limit operators
9332  * return : void
9333  * env (in) : environment
9334  * node (in) : node to process
9335  * order_nodes (in) : nodes on which the query will be ordered
9336  * dep_nodes (in/out) : nodes which are dependent on this one for sort and
9337  * limit evaluation
9338  *
9339  * Note: A node joined to this node is independent of the sort and limit
9340  * operator evaluation if we are not ordering results based on it and
9341  * one of the following conditions is true:
9342  * 1. Is left outer joined to to node
9343  * 2. Is inner joined to this node through a primary key->foreign key
9344  * relationship (see qo_is_pk_fk_full_join)
9345  */
9346 static void
9347 qo_discover_sort_limit_join_nodes (QO_ENV * env, QO_NODE * node, BITSET * order_nodes, BITSET * dep_nodes)
9348 {
9349  BITSET join_nodes;
9350  BITSET_ITERATOR bi;
9351  QO_TERM *term;
9352  int i;
9353 
9354  bitset_init (dep_nodes, env);
9355  bitset_init (&join_nodes, env);
9356 
9357  for (i = 0; i < env->nedges; i++)
9358  {
9359  term = QO_ENV_TERM (env, i);
9360  if (BITSET_MEMBER (QO_TERM_NODES (term), QO_NODE_IDX (node)))
9361  {
9362  if (QO_TERM_CLASS (term) == QO_TC_JOIN
9363  && ((QO_TERM_JOIN_TYPE (term) == JOIN_LEFT && QO_TERM_HEAD (term) == node)
9364  || (QO_TERM_JOIN_TYPE (term) == JOIN_RIGHT && QO_TERM_TAIL (term) == node)))
9365  {
9366  /* Other nodes in this term are outer joined with our node. We can safely add them to dep_nodes if we're
9367  * not ordering on them */
9368  bitset_union (dep_nodes, &QO_TERM_NODES (term));
9369 
9370  /* remove nodes on which we're ordering */
9371  bitset_difference (dep_nodes, order_nodes);
9372  }
9373  else if (QO_TERM_CLASS (term) == QO_TC_PATH)
9374  {
9375  /* path edges are always independent */
9376  bitset_difference (dep_nodes, &QO_TERM_NODES (term));
9377  }
9378  else
9379  {
9380  bitset_union (&join_nodes, &QO_TERM_NODES (term));
9381  }
9382  }
9383  }
9384 
9385  /* remove nodes on which we're ordering from the list */
9386  bitset_difference (&join_nodes, order_nodes);
9387 
9388  /* process inner joins */
9389  for (i = bitset_iterate (&join_nodes, &bi); i != -1; i = bitset_next_member (&bi))
9390  {
9391  if (qo_is_pk_fk_full_join (env, node, QO_ENV_NODE (env, i)))
9392  {
9393  bitset_add (dep_nodes, i);
9394  }
9395  }
9396 }
9397 
9398 /*
9399  * qo_is_pk_fk_full_join () - verify if the join between two nodes can be
9400  * fully expressed through a foreign key->primary
9401  * key join
9402  * return : true if there is a pk->fk relationship, false otherwise
9403  * env (in) :
9404  * fk_node (in) : node which should have a foreign key
9405  * pk_node (in) : node which should have a primary key
9406  *
9407  * Note: Full PK->FK relationships guarantee that any tuple from the FK node
9408  * generates a single tuple in the PK node. This relationship allows us to
9409  * apply some optimizations (like SORT-LIMIT). This relationship exists if
9410  * the following conditions are met:
9411  * 1. PK node has only EQ predicates.
9412  * 2. All terms from PK node are join edges
9413  * 3. The segments involved in terms are a prefix of the primary key index
9414  * 4. There is a foreign key in the fk_node which references the pk_node's
9415  * primary key and the join uses the same prefix of the foreign key as
9416  * that the of the primary key.
9417  */
9418 static bool
9419 qo_is_pk_fk_full_join (QO_ENV * env, QO_NODE * fk_node, QO_NODE * pk_node)
9420 {
9421  int i, j;
9422  QO_NODE_INDEX *node_indexp;
9423  QO_INDEX_ENTRY *pk_idx = NULL, *fk_idx = NULL;
9424  QO_TERM *term;
9425  QO_SEGMENT *fk_seg, *pk_seg;
9426 
9427  node_indexp = QO_NODE_INDEXES (pk_node);
9428  if (node_indexp == NULL)
9429  {
9430  return false;
9431  }
9432 
9433  pk_idx = NULL;
9434  for (i = 0; i < QO_NI_N (node_indexp); i++)
9435  {
9436  pk_idx = QO_NI_ENTRY (node_indexp, i)->head;
9437  if (pk_idx->constraints->type == SM_CONSTRAINT_PRIMARY_KEY)
9438  {
9439  break;
9440  }
9441  pk_idx = NULL;
9442  }
9443 
9444  if (pk_idx == NULL)
9445  {
9446  /* node either does not have a primary key or it is not referenced in any way in this statement */
9447  return false;
9448  }
9449 
9450  /* find the foreign key on fk_node which references pk_node */
9451  node_indexp = QO_NODE_INDEXES (fk_node);
9452  if (node_indexp == NULL)
9453  {
9454  return false;
9455  }
9456 
9457  fk_idx = NULL;
9458  for (i = 0; i < QO_NI_N (node_indexp); i++)
9459  {
9460  fk_idx = QO_NI_ENTRY (node_indexp, i)->head;
9461  if (fk_idx->constraints->type != SM_CONSTRAINT_FOREIGN_KEY)
9462  {
9463  fk_idx = NULL;
9464  continue;
9465  }
9466  if (BTID_IS_EQUAL (&fk_idx->constraints->fk_info->ref_class_pk_btid, &pk_idx->constraints->index_btid))
9467  {
9468  /* These are the droids we're looking for */
9469  break;
9470  }
9471  fk_idx = NULL;
9472  }
9473 
9474  if (fk_idx == NULL)
9475  {
9476  /* No matching foreign key */
9477  return false;
9478  }
9479 
9480  /* Make sure we don't have gaps in the primary key columns */
9481  for (i = 0; i < pk_idx->nsegs; i++)
9482  {
9483  if (pk_idx->seg_idxs[i] == -1)
9484  {
9485  if (i == 0)
9486  {
9487  /* first col must be present */
9488  return false;
9489  }
9490  /* this has to be the last one */
9491  for (j = i + 1; j < pk_idx->nsegs; j++)
9492  {
9493  if (pk_idx->seg_idxs[j] != -1)
9494  {
9495  return false;
9496  }
9497  }
9498  break;
9499  }
9500  }
9501 
9502  if (pk_idx->nsegs > fk_idx->nsegs)
9503  {
9504  /* The number of segments from primary key should be less than those referenced in the foreign key. We can have
9505  * more segments referenced from the foreign key because we don't care about other terms from the fk node
9506  */
9507  return false;
9508  }
9509 
9510  /* Verify that all terms from pk_node reference terms from fk_node. If we find a term which only references pk_node,
9511  * we can abandon the search.
9512  */
9513  for (i = 0; i < env->nterms; i++)
9514  {
9515  term = QO_ENV_TERM (env, i);
9516 
9517  if (QO_TERM_CLASS (term) == QO_TC_DUMMY_JOIN)
9518  {
9519  /* skip always true dummy join terms */
9520  continue;
9521  }
9522 
9523  if (!BITSET_MEMBER (QO_TERM_NODES (term), QO_NODE_IDX (pk_node)))
9524  {
9525  continue;
9526  }
9527 
9528  if (!BITSET_MEMBER (pk_idx->terms, QO_TERM_IDX (term)))
9529  {
9530  /* Term does not use pk_idx. This means that there is a predicate on pk_node outside of the primary key */
9531  return false;
9532  }
9533 
9534  if (QO_TERM_JOIN_TYPE (term) != JOIN_INNER)
9535  {
9536  /* we're only interested in inner joins */
9537  return false;
9538  }
9539 
9540  if (!BITSET_MEMBER (QO_TERM_NODES (term), QO_NODE_IDX (fk_node)))
9541  {
9542  /* found a term belonging to pk_node which does not reference the fk_node. This means pk_node is not full
9543  * joined with fk_node
9544  */
9545  return false;
9546  }
9547 
9548  if (QO_TERM_CLASS (term) != QO_TC_JOIN || !QO_TERM_IS_FLAGED (term, QO_TERM_EQUAL_OP))
9549  {
9550  /* Not a join term, bail out */
9551  return false;
9552  }
9553 
9554  /* Iterate through segments and make sure we're joining same columns. E.g.: For PK(Pa, Pb) and FK (Fa, Fb), make
9555  * sure the terms are not Pa = Fb or Pb = Fa
9556  */
9557  if (term->can_use_index != 2)
9558  {
9559  return false;
9560  }
9561  if (QO_SEG_HEAD (QO_TERM_INDEX_SEG (term, 0)) == fk_node)
9562  {
9563  fk_seg = QO_TERM_INDEX_SEG (term, 0);
9564  pk_seg = QO_TERM_INDEX_SEG (term, 1);
9565  }
9566  else
9567  {
9568  pk_seg = QO_TERM_INDEX_SEG (term, 0);
9569  fk_seg = QO_TERM_INDEX_SEG (term, 1);
9570  }
9571 
9572  /* make sure pk_seg and fk_seg reference the same position in the two indexes */
9573  for (j = 0; j < pk_idx->nsegs; j++)
9574  {
9575  if (pk_idx->seg_idxs[j] == QO_SEG_IDX (pk_seg))
9576  {
9577  assert (j < fk_idx->nsegs);
9578  if (fk_idx->seg_idxs[j] != QO_SEG_IDX (fk_seg))
9579  {
9580  /* not joining the same column */
9581  return false;
9582  }
9583  break;
9584  }
9585  }
9586  }
9587 
9588  return true;
9589 }
9590 
9591 /*
9592  * qo_is_non_mvcc_class_with_index () - Is disabled-MVCC class with index.
9593  *
9594  * return : True/false.
9595  * class_entry_p (in) : QO class entry.
9596  */
9597 static bool
9599 {
9600  /* Index scan is currently optimized for MVCC and doesn't work properly for non-MVCC classes. Disable index scan for
9601  * MVCC-disabled classes that have indexes. Index is still used to find unique object by key.
9602  */
9603  return (oid_check_cached_class_oid (OID_CACHE_SERIAL_CLASS_ID, &class_entry_p->oid)
9605 }
static void qo_partition_free(QO_PARTITION *)
Definition: query_graph.c:9122
int nsubqueries
Definition: query_graph.h:896
static void qo_node_dump(QO_NODE *, FILE *)
Definition: query_graph.c:8178
BITSET subqueries
Definition: query_graph.h:646
#define RANK_EXPR_HEAVY
Definition: query_graph.c:75
PT_NODE * order_by
Definition: parse_tree.h:2769
static int count_bits(const unsigned char *mem, int nbits)
Definition: unittests_bit.c:31
static bool expr_is_mergable(PT_NODE *pt_expr)
Definition: query_graph.c:2863
DB_TIME time
Definition: dbtype_def.h:1056
QO_CLASS_INFO_ENTRY * class_
Definition: query_graph.h:105
PT_NODE * next
Definition: parse_tree.h:3447
PT_NAME_INFO name
Definition: parse_tree.h:3318
#define QO_TERM_SUBQUERIES(t)
Definition: query_graph.h:726
QO_PARTITION * partitions
Definition: query_graph.h:870
int tp_domain_disk_size(TP_DOMAIN *domain)
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: parse_tree.h:2829
#define ER_FAILED_ASSERTION
Definition: error_code.h:695
static QO_INDEX_ENTRY * is_index_compatible(QO_CLASS_INFO *class_info, int n, QO_INDEX_ENTRY *index_entry)
Definition: query_graph.c:6581
QO_TERM * terms
Definition: query_graph.h:868
void qo_check_coll_optimization(QO_INDEX_ENTRY *ent, COLL_OPT *collation_opt)
Definition: query_graph.c:9254
PT_NODE * arg_list
Definition: parse_tree.h:2258
#define NO_ERROR
Definition: error_code.h:46
int bail_out
Definition: query_graph.h:913
static void qo_free_class_info(QO_ENV *env, QO_CLASS_INFO *)
Definition: query_graph.c:4753
bool pt_is_join_expr(PT_NODE *expr, UINTPTR *spec_id)
bool is_iss_candidate
Definition: query_graph.h:155
#define QO_TERM_MULTI_COLL_PRED
Definition: query_graph.h:745
int neqclasses
Definition: query_graph.h:894
short sh
Definition: dbtype_def.h:1050
#define QO_NODE_PT_JOIN_TYPE(node)
Definition: query_graph.h:382
#define JOIN_TYPE_EXCHANGE(e0, e1)
Definition: query_graph.c:124
#define PT_SELECT_INFO_IS_FLAGED(s, f)
Definition: parse_tree.h:2735
int sm_att_id(MOP classop, const char *name)
int bitset_is_equivalent(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:342
UINTPTR id
Definition: parse_tree.h:2144
static void qo_partition_dump(QO_PARTITION *, FILE *)
Definition: query_graph.c:9149
#define IO_PAGESIZE
static void qo_subquery_free(QO_SUBQUERY *)
Definition: query_graph.c:9091
QO_NODE * lookup_node(PT_NODE *attr, QO_ENV *env, PT_NODE **entity)
Definition: query_graph.c:1357
#define QO_TERM_SEG(t)
Definition: query_graph.h:727
const char * name
Definition: query_graph.h:49
PT_NODE * pt_function_index_skip_expr(PT_NODE *node)
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
bool db_value_type_is_collection(const DB_VALUE *value)
Definition: db_macro.c:1144
BITSET nodes
Definition: query_graph.h:608
bool cover_segments
Definition: query_graph.h:140
PT_NODE * using_index
Definition: parse_tree.h:2693
#define BITSET_CLEAR(s)
Definition: query_bitset.h:68
void qo_env_free(QO_ENV *env)
Definition: query_graph.c:5808
#define QO_ASSERT(env, cond)
Definition: optimizer.h:52
static void qo_discover_edges(QO_ENV *)
Definition: query_graph.c:5935
BITSET terms
Definition: query_graph.h:134
void qo_get_optimization_param(void *retval, QO_PARAM param,...)
Definition: query_graph.c:269
static int qo_get_ils_prefix_length(QO_ENV *env, QO_NODE *nodep, QO_INDEX_ENTRY *index_entry)
Definition: query_graph.c:6866
int Neqclasses
Definition: query_graph.h:894
int nsegs
Definition: query_graph.h:892
bool sm_is_index_visible(SM_CLASS_CONSTRAINT *constraint_list, BTID btid)
#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
#define QO_TERM_IDX(t)
Definition: query_graph.h:723
static int get_expr_fcode_rank(FUNC_TYPE fcode)
Definition: query_graph.c:3351
#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
Definition: query_graph.h:209
#define DETAILED_DUMP(level)
Definition: optimizer.h:86
int rangelist_seg_idx
Definition: query_graph.h:125
int self_allocated
Definition: query_graph.h:77
int bitset_intersects(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:295
static void qo_discover_indexes(QO_ENV *)
Definition: query_graph.c:7530
struct qo_node QO_NODE
Definition: optimizer.h:89
void qo_eqclass_fprint_wrt(QO_EQCLASS *eqclass, BITSET *nodeset, FILE *f)
Definition: query_graph.c:8740
PT_NODE * pt_expr
Definition: query_graph.h:641
DB_TIMESTAMP timestamp
Definition: dbtype_def.h:766
static void qo_equivalence(QO_SEGMENT *, QO_SEGMENT *)
Definition: query_graph.c:8687
int ils_prefix_len
Definition: query_graph.h:158
#define db_get_collection
Definition: dbtype.h:60
DB_TYPE
Definition: dbtype_def.h:670
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
double qo_expr_selectivity(QO_ENV *env, PT_NODE *pt_expr)
#define QO_ENV_PARSER(env)
Definition: query_graph.h:964
PT_RESERVED_NAME pt_Reserved_name_table[]
Definition: parse_tree.c:92
static void qo_eqclass_free(QO_EQCLASS *)
Definition: query_graph.c:8396
static void qo_partition_init(QO_ENV *, QO_PARTITION *, int)
Definition: query_graph.c:9106
#define QO_TERM_CLEAR_FLAG(t, f)
Definition: query_graph.h:751
#define RANK_EXPR_MEDIUM
Definition: query_graph.c:74
bool qo_check_type_index_covering(QO_INDEX_ENTRY *ent)
Definition: query_graph.c:9302
#define QO_ENV_PARTITION(env, n)
Definition: query_graph.h:961
int nsegs
Definition: query_graph.h:119
short location
Definition: parse_tree.h:2152
int n_btstats
Definition: statistics.h:80
QO_PLAN * qo_optimize_query(PARSER_CONTEXT *parser, PT_NODE *tree)
Definition: query_graph.c:358
bool multi_range_opt_candidate
Definition: query_graph.h:954
SM_CLASS * smclass
Definition: query_graph.h:73
QO_PLANNER * planner
Definition: query_graph.h:920
PT_NODE * arg3
Definition: parse_tree.h:2202
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
static void qo_term_dump(QO_TERM *, FILE *)
Definition: query_graph.c:8866
PT_NODE * pt_get_select_list(PARSER_CONTEXT *parser, PT_NODE *query)
Definition: query_result.c:404
#define PT_SELECT_INFO_DISABLE_LOOSE_SCAN
Definition: parse_tree.h:2731
DB_DATETIME datetime
Definition: dbtype_def.h:1060
int correlation_level
Definition: parse_tree.h:2745
static PT_NODE * get_local_subqueries_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: query_graph.c:4066
CLASS_STATS * stats
Definition: class_object.h:747
#define QO_JOIN_INFO_SIZE(_partition)
Definition: query_graph.h:1024
bool groupby_skip
Definition: query_graph.h:149
JOIN_TYPE join_type
Definition: query_graph.h:652
static PT_NODE * build_query_graph_function_index(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
Definition: query_graph.c:1006
static PT_NODE * graph_size_select(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
Definition: query_graph.c:815
PT_NODE * node
Definition: query_graph.h:766
int can_use_index
Definition: query_graph.h:663
short location
Definition: query_graph.h:697
int flag
Definition: query_graph.h:689
#define QO_ENV_TMP_BITSET(env)
Definition: query_graph.h:966
#define PT_IS_SPEC_FLAG_SET(spec_, flags_)
Definition: parse_tree.h:653
int bitset_is_empty(const BITSET *s)
Definition: query_bitset.c:318
#define QO_UNORDERED
Definition: query_graph.h:553
#define assert_release(e)
Definition: error_manager.h:96
#define pt_is_query(n)
Definition: parse_tree.h:258
static void qo_analyze_term(QO_TERM *term, int term_type)
Definition: query_graph.c:1915
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
#define QO_TERM_LOCATION(t)
Definition: query_graph.h:725
FUNC_TYPE
#define NOMINAL_OBJECT_SIZE(class)
Definition: query_graph.c:107
static QO_ATTR_INFO * qo_get_attr_info_func_index(QO_ENV *env, QO_SEGMENT *seg, const char *expr_str)
Definition: query_graph.c:4892
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
static QO_TERM * qo_add_term(PT_NODE *conjunct, int term_type, QO_ENV *env)
Definition: query_graph.c:1656
#define QO_TERM_PT_EXPR(t)
Definition: query_graph.h:724
int pkeys_size
Definition: statistics.h:66
static int get_operand_rank(PT_NODE *node)
Definition: query_graph.c:3400
PT_NODE * pt_tree
Definition: query_graph.h:863
static bool qo_is_usable_index(SM_CLASS_CONSTRAINT *constraint, QO_NODE *nodep)
Definition: query_graph.c:7089
TP_DOMAIN * key_type
Definition: statistics.h:65
#define QO_NI_N(ni)
Definition: query_graph.h:237
#define QO_SEG_EQCLASS(seg)
Definition: query_graph.h:513
#define SM_IS_CONSTRAINT_UNIQUE_FAMILY(c)
Definition: class_object.h:111
union pt_query_info::@124 q
#define OID_SET_NULL(oidp)
Definition: oid.h:85
PT_NODE * path_entities
Definition: parse_tree.h:2138
#define QO_TERM_COPY_PT_EXPR
Definition: query_graph.h:742
int first_sort_column
Definition: query_graph.h:143
static void qo_eqclass_add(QO_EQCLASS *, QO_SEGMENT *)
Definition: query_graph.c:8408
int projected_size
Definition: xasl.h:1034
#define LOG2_SIZEOF_POINTER
Definition: query_graph.c:85
void qo_term_fprint(QO_TERM *term, FILE *f)
Definition: query_graph.c:8792
static void qo_seg_clear(QO_ENV *, int)
Definition: query_graph.c:8261
SM_FUNCTION_INFO * func_index_info
Definition: class_object.h:541
bool pt_false_search_condition(PARSER_CONTEXT *parser, const PT_NODE *statement)
#define QO_NODE_INFO_N(node)
Definition: query_graph.h:404
PT_NODE * group_by
Definition: parse_tree.h:2688
DB_DOMAIN * pt_node_to_db_domain(PARSER_CONTEXT *parser, PT_NODE *node, const char *class_name)
Definition: parse_dbi.c:2244
#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
struct sm_class_constraint * next
Definition: class_object.h:530
#define BTID_IS_EQUAL(b1, b2)
SM_CLASS_CONSTRAINT * constraints
Definition: query_graph.h:108
#define PREDICATE_TERM
Definition: query_graph.c:68
#define DOUBLE_EXCHANGE(e0, e1)
Definition: query_graph.c:117
int npartitions
Definition: query_graph.h:897
#define QO_TERM_MULTI_COLL_CONST
Definition: query_graph.h:746
PT_NODE * indx_key_limit
Definition: parse_tree.h:2579
bool orderby_skip
Definition: query_graph.h:146
struct qo_eqclass QO_EQCLASS
Definition: optimizer.h:92
const char * qo_plan_set_cost_fn(const char *, int)
#define INT_EXCHANGE(e0, e1)
Definition: query_graph.c:119
static void qo_term_clear(QO_ENV *, int)
Definition: query_graph.c:8451
HFID * sm_get_ch_heap(MOP classmop)
static PT_NODE * set_seg_expr(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
Definition: query_graph.c:2772
#define QO_NODE_INFO(node)
Definition: query_graph.h:403
Definition: query_graph.h:44
MOP mop
Definition: query_graph.h:63
int Nsegs
Definition: query_graph.h:892
int nedges
Definition: query_graph.h:898
void prm_set_integer_value(PARAM_ID prm_id, int value)
static void qo_free_attr_info(QO_ENV *env, QO_ATTR_INFO *info)
Definition: query_graph.c:5308
static bool qo_is_pk_fk_full_join(QO_ENV *env, QO_NODE *fk_node, QO_NODE *pk_node)
Definition: query_graph.c:9419
#define QO_EQCLASS_IDX(e)
Definition: query_graph.h:558
#define QO_SEG_EQ_ROOT(seg)
Definition: query_graph.h:512
QO_SUBQUERY * subqueries
Definition: query_graph.h:869
#define QO_SEG_NAME(seg)
Definition: query_graph.h:514
unsigned single_table_opt
Definition: parse_tree.h:2711
#define PT_IS_OID_NAME(n)
Definition: parse_tree.h:323
#define QO_NODE_REL_IDX(node)
Definition: query_graph.h:393
#define QO_SEG_INDEX_TERMS(seg)
Definition: query_graph.h:523
double selectivity
Definition: query_graph.h:623
#define SIZEOF_NODE_INDEX(n)
Definition: query_graph.c:110
TP_DOMAIN * key_type
Definition: optimizer.h:124
bool all_unique_index_columns_are_equi_terms
Definition: query_graph.h:137
PT_DOT_INFO dot
Definition: parse_tree.h:3287
#define QO_SEG_TAIL(seg)
Definition: query_graph.h:511
PT_NODE * arg2
Definition: parse_tree.h:2086
bool is_func_index
Definition: query_graph.h:175
SM_CLASS_CONSTRAINT * sm_class_constraints(MOP classop)
static bool qo_is_non_mvcc_class_with_index(QO_CLASS_INFO_ENTRY *class_entry_p)
Definition: query_graph.c:9598
#define PT_NODE_EXCHANGE(e0, e1)
Definition: query_graph.c:118
#define QO_PARTITION_PLAN(p)
Definition: query_graph.h:832
static PT_NODE * build_query_graph(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
Definition: query_graph.c:938
#define QO_NODE_DEP_SET(node)
Definition: query_graph.h:387
PT_NODE * index_ss
Definition: parse_tree.h:2698
PT_JSON_TABLE_INFO json_table_info
Definition: parse_tree.h:3312
#define QO_PARTITION_IDX(p)
Definition: query_graph.h:833
PT_PRINT_VALUE_FUNC print_db_value
Definition: parse_tree.h:3553
#define QO_NODE_NCARD(node)
Definition: query_graph.h:405
static DB_OBJECT * is_class(OID *obj_oid, OID *class_oid)
Definition: compactdb.c:637
#define QO_TERM_CLASS(t)
Definition: query_graph.h:716
FUNC_TYPE function_type
Definition: parse_tree.h:2259
PT_TYPE_ENUM type_enum
Definition: parse_tree.h:3457
PT_NODE * or_next
Definition: parse_tree.h:3448
DB_TYPE pt_type_enum_to_db(const PT_TYPE_ENUM t)
Definition: parse_dbi.c:2314
#define SIZEOF_ATTR_CUM_STATS_PKEYS(n)
Definition: query_graph.c:103
#define QO_PARTITION_M_OFFSET(p)
Definition: query_graph.h:831
static void graph_size_for_entity(QO_ENV *env, PT_NODE *entity)
Definition: query_graph.c:856
double QO_INFINITY
Definition: query_graph.c:160
DB_BIGINT bigint
Definition: dbtype_def.h:1051
static void qo_exchange(QO_TERM *t0, QO_TERM *t1)
Definition: query_graph.c:5897
bool use_descending
Definition: query_graph.h:152
char * parser_print_function_index_expr(PARSER_CONTEXT *parser, const PT_NODE *expr)
#define NODEPTR_EXCHANGE(e0, e1)
Definition: query_graph.c:121
QO_SEGMENT * seg
Definition: query_graph.h:671
static QO_NODE * build_graph_for_entity(QO_ENV *env, PT_NODE *entity, QO_BUILD_STATUS status)
Definition: query_graph.c:1103
PT_MISC_TYPE derived_table_type
Definition: parse_tree.h:2147
static PT_NODE * qo_add_final_segment(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
Definition: query_graph.c:1628
TP_DOMAIN * key_type
Definition: query_graph.h:116
#define PT_IS_SELECT(n)
Definition: parse_tree.h:284
PT_OP_TYPE pt_converse_op(PT_OP_TYPE op)
#define QO_TERM_MULTI_COL_SEGS(t)
Definition: query_graph.h:735
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
Definition: db_set.h:35
int bitset_subset(const BITSET *r, const BITSET *s)
Definition: query_bitset.c:263
PT_HINT_ENUM
Definition: parse_tree.h:1161
DB_TIMESTAMP utime
Definition: dbtype_def.h:1058
PT_NODE * arg2
Definition: parse_tree.h:2198
LANG_COLLATION * lang_get_collation(const int coll_id)
#define QO_INDEX_INDEX(ind, n)
Definition: query_graph.h:196
PT_FUNCTION_INFO function
Definition: parse_tree.h:3301
#define QO_NODE_RIGHT_DEP_SET(node)
Definition: query_graph.h:398
DB_OBJECT * db_object
Definition: parse_tree.h:2546
static void qo_node_free(QO_NODE *)
Definition: query_graph.c:8115
void qo_termset_fprint(QO_ENV *env, BITSET *terms, FILE *f)
Definition: query_graph.c:8845
#define assert(x)
BITSET final_segs
Definition: query_graph.h:886
static void swap_node(T_LIST *node1, T_LIST *node2)
Definition: broker_list.c:323
#define QO_TERM_TAIL(t)
Definition: query_graph.h:722
int * pkeys
Definition: statistics.h:67
void bitset_print(const BITSET *s, FILE *fp)
Definition: query_bitset.c:527
#define QO_EQCLASS_ENV(e)
Definition: query_graph.h:555
QO_SEGMENT * lookup_seg(QO_NODE *head, PT_NODE *name, QO_ENV *env)
Definition: query_graph.c:1558
void bitset_delset(BITSET *s)
Definition: query_bitset.c:571
PT_NODE * parser_walk_leaves(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE_WALK_FUNCTION pre_function, void *pre_argument, PT_NODE_WALK_FUNCTION post_function, void *post_argument)
static void qo_add_dep_term(QO_NODE *derived_node, BITSET *depend_nodes, BITSET *depend_segs, QO_ENV *env)
Definition: query_graph.c:1774
#define SEGMENTPTR_EXCHANGE(e0, e1)
Definition: query_graph.c:120
#define _WORDSIZE
Definition: query_bitset.h:40
void bitset_assign(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:120
#define QO_NODE_ENV(node)
Definition: query_graph.h:380
#define QO_UI_N(ui)
Definition: query_graph.h:259
#define QO_TERM_SINGLE_PRED
Definition: query_graph.h:741
int prm_get_integer_value(PARAM_ID prm_id)
int pt_get_query_limit_value(PARSER_CONTEXT *parser, PT_NODE *query, DB_VALUE *limit_val)
static void set_seg_node(PT_NODE *attr, QO_ENV *env, BITSET *bitset)
Definition: query_graph.c:2836
static void add_using_index(QO_ENV *env, PT_NODE *using_index)
Definition: query_graph.c:4394
static void add_hint(QO_ENV *env, PT_NODE *tree)
Definition: query_graph.c:4266
#define QO_SEG_IDX(seg)
Definition: query_graph.h:519
#define PT_IS_CLASSOID_NAME(x)
Definition: parse_tree.h:119
QO_INDEX * index
Definition: query_graph.h:82
void bitset_union(BITSET *dst, const BITSET *src)
Definition: query_bitset.c:176
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
PT_NODE * on_cond
Definition: parse_tree.h:2149
unsigned int BITSET
Definition: esql_misc.h:94
static QO_SEGMENT * qo_eqclass_wrt(QO_EQCLASS *, BITSET *)
Definition: query_graph.c:8712
#define QO_NODE_USING_INDEX(node)
Definition: query_graph.h:395
bool pt_is_pseudo_const(PT_NODE *expr)
Definition: query_graph.c:3655
#define NOMINAL_HEAP_SIZE(class)
Definition: query_graph.c:106
static void qo_term_free(QO_TERM *)
Definition: query_graph.c:8767
QO_SEGMENT * index_seg[2]
Definition: query_graph.h:664
static void qo_discover_sort_limit_join_nodes(QO_ENV *env, QO_NODE *nodep, BITSET *order_nodes, BITSET *dep_nodes)
Definition: query_graph.c:9347
static void qo_free_index(QO_ENV *env, QO_INDEX *)
Definition: query_graph.c:4651
PT_NODE * flat_entity_list
Definition: parse_tree.h:2140
static int is_equivalent_indexes(QO_INDEX_ENTRY *index1, QO_INDEX_ENTRY *index2)
Definition: query_graph.c:6488
void qo_plans_stats(FILE *f)
#define QO_NODE_SARGABLE(node)
Definition: query_graph.h:399
PT_MISC_TYPE all_distinct
Definition: parse_tree.h:2746
bool pt_has_analytic(PARSER_CONTEXT *parser, PT_NODE *node)
const char * original
Definition: parse_tree.h:2544
DB_DATETIME datetime
Definition: dbtype_def.h:783
static void qo_seg_free(QO_SEGMENT *)
Definition: query_graph.c:8286
#define QO_UI_FORCE(ui, n)
Definition: query_graph.h:261
PT_HINT_ENUM hint
Definition: parse_tree.h:2707
int intl_identifier_casecmp(const char *str1, const char *str2)
bool plan_dump_enabled
Definition: query_graph.h:948
static void qo_find_index_seg_terms(QO_ENV *env, QO_INDEX_ENTRY *index_entry, int idx, BITSET *index_segsp)
Definition: query_graph.c:6416
static void qo_eqclass_dump(QO_EQCLASS *, FILE *)
Definition: query_graph.c:8422
#define BTREE_STATS_PKEYS_NUM
Definition: statistics.h:41
static bool is_local_name(QO_ENV *env, PT_NODE *expr)
Definition: query_graph.c:3558
#define QO_SEG_SHARED_ATTR(seg)
Definition: query_graph.h:517
struct qo_segment QO_SEGMENT
Definition: optimizer.h:90
#define TP_DOMAIN_COLLATION(dom)
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
PARSER_CONTEXT * parser
Definition: query_graph.h:856
int qo_seg_width(QO_SEGMENT *seg)
Definition: query_graph.c:8313
BITSET nodes
Definition: query_graph.h:773
#define QO_TERM_NOMINAL_SEG(t)
Definition: query_graph.h:730
#define OPTIMIZATION_ENABLED(level)
Definition: optimizer.h:83
#define QO_NODE_SUBQUERIES(node)
Definition: query_graph.h:390
FILE * query_Plan_dump_fp
PT_NODE * having
Definition: parse_tree.h:2692
const char * sm_get_ch_name(MOP op)
QO_NODE * nodes
Definition: query_graph.h:866
#define RANK_DEFAULT
Definition: query_graph.c:70
PT_NODE * from
Definition: parse_tree.h:2686
#define PT_SELECT_INFO_HAS_AGG
Definition: parse_tree.h:2717
static bool qo_is_coverage_index(QO_ENV *env, QO_NODE *nodep, QO_INDEX_ENTRY *index_entry)
Definition: query_graph.c:6736
#define PT_SELECT_INFO_COLS_SCHEMA
Definition: parse_tree.h:2721
static int qo_find_matching_index(QO_INDEX_ENTRY *index_entry, QO_INDEX *class_indexes)
Definition: query_graph.c:6533
#define PT_IS_CONST(n)
Definition: parse_tree.h:364
static void qo_discover_partitions(QO_ENV *)
Definition: query_graph.c:7645
QO_EQCLASS * eqclass
Definition: query_graph.h:686
UINTPTR spec_id
Definition: parse_tree.h:2543
static void qo_assign_eq_classes(QO_ENV *)
Definition: query_graph.c:7840
BITSET multi_col_range_segs
Definition: query_graph.h:184
void qo_set_optimization_param(void *retval, QO_PARAM param,...)
Definition: query_graph.c:316
static void qo_classify_outerjoin_terms(QO_ENV *)
Definition: query_graph.c:6099
#define TP_DOMAIN_TYPE(dom)
void qo_expr_segs(QO_ENV *env, PT_NODE *pt_expr, BITSET *result)
Definition: query_graph.c:2734
#define QO_IS_DEP_TERM(t)
Definition: query_graph.h:586
static void cleanup(int signo)
Definition: broker.c:717
QO_ENV * env
Definition: query_graph.c:156
#define QO_TERM_MULTI_COL_CNT(t)
Definition: query_graph.h:736
SP_PARSER_CTX * parser
PT_NODE * arg1
Definition: parse_tree.h:2197
PT_NODE * pt_find_entity(PARSER_CONTEXT *parser, const PT_NODE *scope, UINTPTR id)
#define NULL
Definition: freelistheap.h:34
PT_NODE * as_attr_list
Definition: parse_tree.h:2136
int rank
Definition: query_graph.h:634
static void qo_subquery_dump(QO_ENV *, QO_SUBQUERY *, FILE *)
Definition: query_graph.c:9047
static int get_opcode_rank(PT_OP_TYPE opcode)
Definition: query_graph.c:3026
PT_NODE * referenced_attrs
Definition: parse_tree.h:2137
int db_is_class(MOP obj)
Definition: db_info.c:310
int nterms
Definition: query_graph.h:895
#define QO_NODE_SARGS(node)
Definition: query_graph.h:388
PT_MISC_TYPE is_subquery
Definition: parse_tree.h:2747
if(extra_options)
Definition: dynamic_load.c:958
#define RANK_EXPR_FUNCTION
Definition: query_graph.c:76
DB_DATE date
Definition: dbtype_def.h:1057
#define PT_SPEC_IS_DERIVED(spec_)
Definition: parse_tree.h:690
DB_TIMESTAMPTZ timestamptz
Definition: dbtype_def.h:1059
#define QO_ADD_RIGHT_TO_OUTER(tail, head)
Definition: query_graph.h:435
#define UTIL_infinity()
Definition: util_func.h:35
#define QO_EQCLASS_TERM(e)
Definition: query_graph.h:557
char * pt_append_string(const PARSER_CONTEXT *parser, const char *old_string, const char *new_tail)
Definition: parse_tree.c:980
#define QO_SEG_FUNC_INDEX(seg)
Definition: query_graph.h:524
#define pt_is_multi_col_term(n)
Definition: parse_tree.h:263
#define RANK_VALUE
Definition: query_graph.c:72
#define SM_IS_CONSTRAINT_INDEX_FAMILY(c)
Definition: class_object.h:117
TP_DOMAIN * tp_domain_cache(TP_DOMAIN *transient)
#define PT_EXPR_INFO_TRANSITIVE
Definition: parse_tree.h:2217
static bool qo_is_iss_index(QO_ENV *env, QO_NODE *nodep, QO_INDEX_ENTRY *index_entry)
Definition: query_graph.c:6978
#define QO_SEG_PT_NODE(seg)
Definition: query_graph.h:509
jmp_buf catch_
Definition: query_graph.h:928
QO_BUILD_STATUS
Definition: query_graph.c:147
#define QO_TERM_MERGEABLE_EDGE
Definition: query_graph.h:743
#define PT_SPEC_IS_CTE(spec_)
Definition: parse_tree.h:694
PT_NODE * pt_continue_walk(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
static QO_SEGMENT * qo_join_segment(QO_NODE *head, QO_NODE *tail, PT_NODE *name, QO_ENV *env)
Definition: query_graph.c:1537
static bool qo_validate(QO_ENV *env)
Definition: query_graph.c:758
static PT_NODE * get_local_subqueries_post(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: query_graph.c:4112
static void qo_estimate_statistics(MOP class_mop, CLASS_STATS *)
Definition: query_graph.c:5687
PT_NODE * where
Definition: parse_tree.h:2687
PT_QUERY_INFO query
Definition: parse_tree.h:3325
short location
Definition: parse_tree.h:2243
#define QO_TERM_CAN_USE_INDEX(t)
Definition: query_graph.h:731
PT_NODE * use_idx
Definition: parse_tree.h:2697
BITSET * tmp_bitset
Definition: query_graph.h:875
bool pt_has_aggregate(PARSER_CONTEXT *parser, PT_NODE *node)
void qo_seg_fprint(QO_SEGMENT *seg, FILE *f)
Definition: query_graph.c:8361
static QO_ATTR_INFO * qo_get_attr_info(QO_ENV *env, QO_SEGMENT *seg)
Definition: query_graph.c:5049
static QO_ENV * qo_env_init(PARSER_CONTEXT *parser, PT_NODE *query)
Definition: query_graph.c:629
int db_col_size(DB_COLLECTION *col)
Definition: db_set.c:1167
#define QO_ADD_RIGHT_DEP_SET(tail, head)
Definition: query_graph.h:431
int pr_clear_value(DB_VALUE *value)
#define QO_SEG_CLASS_ATTR(seg)
Definition: query_graph.h:516
DB_BIGINT db_get_bigint(const DB_VALUE *value)
struct qo_term QO_TERM
Definition: optimizer.h:91
#define QO_NODE_SELECTIVITY(node)
Definition: query_graph.h:389
#define QO_SEG_IS_OID_SEG(seg)
Definition: query_graph.h:522
BITSET terms
Definition: query_graph.h:782
#define QO_ADD_OUTER_DEP_SET(tail, head)
Definition: query_graph.h:427
PT_NODE * pt_has_non_idx_sarg_coll_pre(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
PT_NODE * pt_check_instnum_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
int bitset_next_member(BITSET_ITERATOR *si)
Definition: query_bitset.c:478
QO_CLASS_INFO * info
Definition: query_graph.h:328
int64_t DB_BIGINT
Definition: dbtype_def.h:751
#define RANK_QUERY
Definition: query_graph.c:77
#define QO_ENV_SORT_LIMIT_NODES(env)
Definition: query_graph.h:968
DB_TYPE sm_att_type_id(MOP classop, const char *name)
void bitset_remove(BITSET *dst, int x)
Definition: query_bitset.c:158
QO_SEGMENT * nominal_seg
Definition: query_graph.h:687
SM_CLASS_CONSTRAINT * constraints
Definition: class_object.h:757
int pt_is_function_index_expression(PT_NODE *node)
#define QO_TERM_ENV(t)
Definition: query_graph.h:715
#define QO_NODE_EQCLASSES(node)
Definition: query_graph.h:385
bool qo_need_skip_execution(void)
Definition: query_graph.c:297
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
static void error(const char *msg)
Definition: gencat.c:331
#define QO_ENTRY_MULTI_COL(entry)
Definition: query_graph.h:187
BITSET index_segs
Definition: query_graph.h:181
int rangelist_term_idx
Definition: query_graph.h:178
int normal_class
Definition: query_graph.h:80
QO_PLAN * final_plan
Definition: query_graph.h:880
unsigned is_system_generated_stmt
Definition: parse_tree.h:3484
QO_TERM * term
Definition: query_graph.c:157
#define QO_TERM_OID_SEG(t)
Definition: query_graph.h:728
#define RANK_EXPR_LIGHT
Definition: query_graph.c:73
static void qo_get_index_info(QO_ENV *env, QO_NODE *node)
Definition: query_graph.c:5330
static void qo_discover_sort_limit_nodes(QO_ENV *env)
Definition: query_graph.c:8493
#define TERMCLASS_EXCHANGE(e0, e1)
Definition: query_graph.c:116
SM_CLASS_CONSTRAINT * classobj_find_class_index(SM_CLASS *class_, const char *name)
static PT_NODE * build_query_graph_post(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
Definition: query_graph.c:978
#define QO_NODE_TCARD(node)
Definition: query_graph.h:406
double cardinality
Definition: xasl.h:1030
#define TP_TYPE_HAS_COLLATION(typeid)
static bool is_dependent_table(PT_NODE *entity)
Definition: query_graph.c:2936
#define QO_TERM_OR_PRED
Definition: query_graph.h:747
#define HFID_IS_NULL(hfid)
static void qo_find_index_terms(QO_ENV *env, BITSET *segsp, QO_INDEX_ENTRY *index_entry)
Definition: query_graph.c:6370
PT_SORT_SPEC_INFO sort_spec
Definition: parse_tree.h:3343
#define ARG_FILE_LINE
Definition: error_manager.h:44
static QO_PLAN * qo_optimize_helper(QO_ENV *env)
Definition: query_graph.c:429
bool qo_is_prefix_index(QO_INDEX_ENTRY *ent)
Definition: query_graph.c:9203
#define SIZEOF_CLASS_INFO(n)
Definition: query_graph.c:97
CLASS_STATS * stats
Definition: query_graph.h:76
#define OPTIMIZATION_LIMIT
#define QO_TERM_SELECTIVITY(t)
Definition: query_graph.h:719
#define QO_UI_INDEX(ui, n)
Definition: query_graph.h:260
PT_NODE * index_ls
Definition: parse_tree.h:2699
QO_ENV * env
Definition: query_graph.h:599
bool pt_name_equal(PARSER_CONTEXT *parser, const PT_NODE *name1, const PT_NODE *name2)
void parser_free_tree(PARSER_CONTEXT *parser, PT_NODE *tree)
#define QO_TERM_NON_IDX_SARG_COLL
Definition: query_graph.h:744
#define WS_OID(mop)
Definition: work_space.h:293
#define QO_NODE_PARTITION(node)
Definition: query_graph.h:386
static QO_NODE * qo_add_node(PT_NODE *entity, QO_ENV *env)
Definition: query_graph.c:1239
BTREE_STATS * bt_stats
Definition: statistics.h:81
static PT_NODE * get_referenced_attrs(PT_NODE *entity)
Definition: query_graph.c:4208
#define QO_ABORT(env)
Definition: optimizer.h:59
static void get_term_rank(QO_ENV *env, QO_TERM *term)
Definition: query_graph.c:3458
#define QO_UI_KEYLIMIT(ui, n)
Definition: query_graph.h:262
static void get_rank(QO_ENV *env)
Definition: query_graph.c:4191
#define QO_NODE_LOCATION(node)
Definition: query_graph.h:383
#define QO_TERM_RANGELIST
Definition: query_graph.h:740
struct qo_index_entry * next
Definition: query_graph.h:102
struct qo_partition QO_PARTITION
Definition: optimizer.h:96
#define QO_IS_FAKE_TERM(t)
Definition: query_graph.h:585
bool allow_index_opt
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
Definition: intl_support.c:43
#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
SM_COMPONENT header
Definition: class_object.h:441
bool pt_is_function_index_expr(PARSER_CONTEXT *parser, PT_NODE *expr, bool report_error)
PT_OP_TYPE
Definition: parse_tree.h:1320
PT_NODE * connect_by
Definition: parse_tree.h:2689
#define DB_PAGESIZE
#define PT_SELECT_FULL_INFO_COLS_SCHEMA
Definition: parse_tree.h:2722
unsigned int date
Definition: dbtype_def.h:776
static int count_classes(PT_NODE *p)
Definition: query_graph.c:4792
static void get_local_subqueries(QO_ENV *env, PT_NODE *tree)
Definition: query_graph.c:4149
QO_SORT_LIMIT_USE use_sort_limit
Definition: query_graph.h:907
#define QO_SEG_ENV(seg)
Definition: query_graph.h:508
#define BITSET_MOVE(dst, src)
Definition: query_bitset.h:80
#define QO_GET_CLASS_STATS(entryp)
Definition: query_graph.h:201
bool prm_get_bool_value(PARAM_ID prm_id)
#define QO_TERM_EQCLASS(t)
Definition: query_graph.h:729
PT_NODE * start_with
Definition: parse_tree.h:2690
SM_ATTRIBUTE ** attributes
Definition: class_object.h:533
void qo_abort(QO_ENV *env, const char *file, int line)
Definition: query_graph.c:5796
int pt_is_attr(PT_NODE *node)
int pt_is_single_tuple(PARSER_CONTEXT *parser, PT_NODE *select_node)
PT_NODE * after_cb_filter
Definition: parse_tree.h:2691
#define QO_TERM_HEAD(t)
Definition: query_graph.h:721
#define QO_NODE_NAME(node)
Definition: query_graph.h:401
#define SIZEOF_INDEX(n)
Definition: query_graph.c:91
PARSER_VARCHAR * pt_print_node_value(PARSER_CONTEXT *parser, const PT_NODE *val)
#define QO_TERM_RANK(t)
Definition: query_graph.h:720
static bool qo_is_equi_join_term(QO_TERM *term)
Definition: query_graph.c:2897
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2146
int qo_plan_get_cost_fn(const char *)
static void get_term_subqueries(QO_ENV *env, QO_TERM *term)
Definition: query_graph.c:2974
int * seg_idxs
Definition: query_graph.h:122
#define QO_ENV_NODE(env, n)
Definition: query_graph.h:958
SM_CLASS * sm_get_class_with_statistics(MOP classop)
static QO_SEGMENT * qo_insert_segment(QO_NODE *head, QO_NODE *tail, PT_NODE *node, QO_ENV *env, const char *expr_str)
Definition: query_graph.c:1476
#define QO_ENV_EQCLASS(env, n)
Definition: query_graph.h:959
#define QO_ENV_TERM(env, n)
Definition: query_graph.h:960
static int qo_data_compare(DB_DATA *data1, DB_DATA *data2, DB_TYPE type)
Definition: query_graph.c:5582
void * etc
Definition: parse_tree.h:3450
SM_CONSTRAINT_TYPE type
Definition: class_object.h:540
char * parser_print_tree(PARSER_CONTEXT *parser, const PT_NODE *node)
QO_SEGMENT * segs
Definition: query_graph.h:865
#define QO_ENV_SEG(env, n)
Definition: query_graph.h:957
PT_NODE * ordered
Definition: parse_tree.h:2695
#define PUT_FLAG(cond, flag)
Definition: query_graph.c:136
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
int has_function
Definition: statistics.h:64
int db_make_null(DB_VALUE *value)
int heap_num_pages
Definition: statistics.h:90
#define QO_TERM_NODES(t)
Definition: query_graph.h:717
#define QO_OUTER_JOIN_TERM(term)
Definition: query_graph.h:1002
bool oid_check_cached_class_oid(const int cache_id, const OID *oid)
Definition: oid.c:327
#define QO_TERM_SET_FLAG(t, f)
Definition: query_graph.h:750
PT_NODE * list
Definition: parse_tree.h:2685
#define DB_IS_NULL(value)
Definition: dbtype.h:63
PT_NODE * use_merge
Definition: parse_tree.h:2700
static void qo_find_node_indexes(QO_ENV *, QO_NODE *)
Definition: query_graph.c:7125
int heap_num_objects
Definition: statistics.h:89
PT_OP_TYPE op
Definition: parse_tree.h:2200
#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
#define pt_is_set_type(n)
Definition: parse_tree.h:267
const char * name
Definition: class_object.h:385
#define RANK_NAME
Definition: query_graph.c:71
void bitset_init(BITSET *s, QO_ENV *env)
Definition: query_bitset.c:557
char * statistics_attribute_name
Definition: query_graph.h:164
PT_NODE * path_conjuncts
Definition: parse_tree.h:2139
#define PT_SPEC_SPECIAL_INDEX_SCAN(spec_)
Definition: parse_tree.h:656
static void qo_seg_nodes(QO_ENV *, BITSET *, BITSET *)
Definition: query_graph.c:9185
char * strdup(const char *str)
Definition: porting.c:901
QO_TERMCLASS term_class
Definition: query_graph.h:629
static void add_hint_args(QO_ENV *env, PT_NODE *arg_list, PT_HINT_ENUM hint)
Definition: query_graph.c:4222
SM_INDEX_STATUS index_status
Definition: class_object.h:544
#define QO_NODE_IDX(node)
Definition: query_graph.h:392
static QO_EQCLASS * qo_eqclass_new(QO_ENV *)
Definition: query_graph.c:8372
static PT_NODE * check_subquery_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
Definition: query_graph.c:3506
int bitset_cardinality(const BITSET *s)
Definition: query_bitset.c:393
#define PT_INTERNAL_ERROR(parser, what)
Definition: parse_tree.h:112
#define BISET_EXCHANGE(s0, s1)
Definition: query_graph.c:128
#define NELEMENTS
Definition: query_bitset.h:37
bool qo_is_filter_index(QO_INDEX_ENTRY *ent)
Definition: query_graph.c:9228
QO_NODE * head
Definition: query_graph.h:682
#define QO_NODE_OID_SEG(node)
Definition: query_graph.h:384
#define QO_ENV_PT_TREE(env)
Definition: query_graph.h:965
MOP sm_find_class(const char *name)
const char * alias_print
Definition: parse_tree.h:3455
QO_SEGMENT * oid_seg
Definition: query_graph.h:672
QO_CLASS_INFO_ENTRY info[1]
Definition: query_graph.h:89
#define QO_NODE_ENTITY_SPEC(node)
Definition: query_graph.h:381
#define QO_PARTITION_NODES(p)
Definition: query_graph.h:828
const char * resolved
Definition: parse_tree.h:2545
static void qo_env_dump(QO_ENV *, FILE *)
Definition: query_graph.c:7961
static QO_ENV * qo_env_new(PARSER_CONTEXT *, PT_NODE *)
Definition: query_graph.c:5710
int bitset_first_member(const BITSET *s)
Definition: query_bitset.c:514
#define QO_TERM_FLAG(t)
Definition: query_graph.h:734
#define TP_TYPE_NOT_SUPPORT_COVERING(typeid)
PT_NODE * use_nl
Definition: parse_tree.h:2696
static QO_TERM * qo_add_dummy_join_term(QO_ENV *env, QO_NODE *p_node, QO_NODE *on_node)
Definition: query_graph.c:1851
#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)
#define QO_NODE_SEGS(node)
Definition: query_graph.h:391
#define EQCLASSPTR_EXCHANGE(e0, e1)
Definition: query_graph.c:122
void bitset_add(BITSET *dst, int x)
Definition: query_bitset.c:138
QO_PARAM
Definition: optimizer.h:136
QO_TERMCLASS
Definition: query_graph.h:562
struct parser_node::@132 flag
Definition: query_graph.h:99
PT_NODE * entity_name
Definition: parse_tree.h:2130
int force
Definition: query_graph.h:110
bool dump_enable
Definition: query_graph.h:941
PT_SELECT_INFO select
Definition: parse_tree.h:2781
#define pt_is_const(n)
Definition: parse_tree.h:271
#define QO_NODE_SORT_LIMIT_CANDIDATE(node)
Definition: query_graph.h:409
#define QO_NODE_IS_OUTER_JOIN(node)
Definition: query_graph.h:422
double amount
Definition: dbtype_def.h:831
#define PLAN_DUMP_ENABLED(level)
Definition: optimizer.h:84
void qo_node_fprint(QO_NODE *node, FILE *f)
Definition: query_graph.c:8162
BITSET segs
Definition: query_graph.h:772
PT_NODE * key_limit
Definition: query_graph.h:167
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
OID oid
Definition: query_graph.h:54
BITSET * seg_other_terms
Definition: query_graph.h:131
#define QO_PARTITION_EDGES(p)
Definition: query_graph.h:829
BITSET segments
Definition: query_graph.h:614
static bool qo_find_index_segs(QO_ENV *, SM_CLASS_CONSTRAINT *, QO_NODE *, int *, int, int *, BITSET *)
Definition: query_graph.c:6636
float f
Definition: dbtype_def.h:1052
static QO_INDEX * qo_alloc_index(QO_ENV *env, int)
Definition: query_graph.c:4594
PT_NODE * pt_check_instnum_post(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define QO_SEG_SET_VALUED(seg)
Definition: query_graph.h:515
ATTR_STATS * attr_stats
Definition: statistics.h:92
#define QO_TERM_EQUAL_OP
Definition: query_graph.h:739
int Nterms
Definition: query_graph.h:895
static QO_CLASS_INFO_ENTRY * grok_classes(QO_ENV *env, PT_NODE *dom_set, QO_CLASS_INFO_ENTRY *info)
Definition: query_graph.c:4819
#define QO_SEG_INFO(seg)
Definition: query_graph.h:518
static void add_local_subquery(QO_ENV *env, PT_NODE *node)
Definition: query_graph.c:4001
const char ** p
Definition: dynamic_load.c:945
int col_num
Definition: query_graph.h:113
#define SIZEOF_USING_INDEX(n)
Definition: query_graph.c:64
double d
Definition: dbtype_def.h:1053
#define QO_TERM_JOIN_TYPE(t)
Definition: query_graph.h:733
QO_ENV * env
Definition: query_graph.h:530
DB_MONETARY money
Definition: dbtype_def.h:1062
static void qo_node_clear(QO_ENV *, int)
Definition: query_graph.c:8081
unsigned int time
Definition: dbtype_def.h:777
#define FLAG_EXCHANGE(e0, e1)
Definition: query_graph.c:125
static QO_CLASS_INFO * qo_get_class_info(QO_ENV *env, QO_NODE *node)
Definition: query_graph.c:4708
PT_JOIN_TYPE join_type
Definition: parse_tree.h:2151
int Nnodes
Definition: query_graph.h:893
#define QO_EQCLASS_SEGS(e)
Definition: query_graph.h:556
static void qo_free_node_index_info(QO_ENV *env, QO_NODE_INDEX *node_indexp)
Definition: query_graph.c:5548
const char * name
Definition: class_object.h:532
const char * class_name
Definition: query_graph.h:347
PT_NODE * derived_table
Definition: parse_tree.h:2134
int nnodes
Definition: query_graph.h:893
DB_TYPE type
Definition: statistics.h:79
#define INT_PTR_EXCHANGE(e0, e1)
Definition: query_graph.c:126
static void qo_node_add_sarg(QO_NODE *, QO_TERM *)
Definition: query_graph.c:8142
BITSET fake_terms
Definition: query_graph.h:935
PT_NODE * range_var
Definition: parse_tree.h:2135
int * multi_col_segs
Definition: query_graph.h:703
void qo_info_stats(FILE *f)
int multi_col_cnt
Definition: query_graph.h:704
DB_DATETIMETZ datetimetz
Definition: dbtype_def.h:1061