CUBRID Engine  latest
query_rewrite.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_rewrite.c - Query rewrite optimization
21  */
22 
23 #ident "$Id$"
24 
25 #include <assert.h>
26 
27 #include "parser.h"
28 #include "parser_message.h"
29 #include "parse_tree.h"
30 #include "optimizer.h"
31 #include "xasl_generation.h"
32 #include "virtual_object.h"
33 #include "system_parameter.h"
34 #include "semantic_check.h"
35 #include "execute_schema.h"
36 #include "view_transform.h"
37 #include "parser.h"
38 #include "object_primitive.h"
39 #include "object_representation.h"
40 
41 #include "dbtype.h"
42 
43 #define DB_MAX_LITERAL_PRECISION 255
44 
45 typedef struct spec_id_info SPEC_ID_INFO;
47 {
48  UINTPTR id;
49  bool appears;
50  bool nullable;
51 };
52 
53 typedef struct to_dot_info TO_DOT_INFO;
55 {
58 };
59 
62 {
63  PT_NODE *c_name; /* attr name which will be reduced to constant */
65  int query_serial_num; /* query, serial number */
66  PT_NODE *s_point_list; /* list of other specs name. these are joined with spec of c_name */
67 };
68 
69 /* result of CompDBValueWithOpType() function */
71 {
72  CompResultLess = -2, /* less than */
73  CompResultLessAdj = -1, /* less than and adjacent to */
74  CompResultEqual = 0, /* equal */
75  CompResultGreaterAdj = 1, /* greater than and adjacent to */
76  CompResultGreater = 2, /* greater than */
77  CompResultError = 3 /* error */
79 
80 typedef enum
81 {
86 
89 {
91  short start;
92  short end;
94 };
95 
96 static PT_NODE *qo_reset_location (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
97 
99  PT_NODE ** wherep);
100 static PT_NODE *qo_optimize_queries (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk);
103 static PT_NODE *qo_optimize_queries_post (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk);
104 
105 /*
106  * qo_find_best_path_type () -
107  * return: PT_NODE *
108  * spec(in): path entity to test
109  *
110  * Note: prunes non spec's
111  */
112 static PT_MISC_TYPE
114 {
115  PT_MISC_TYPE best_path_type = PT_PATH_OUTER;
116  PT_MISC_TYPE path_type;
117 
118  /* if any is an inner, the result is inner. if all are outer, the result is outer */
119 
120  while (spec)
121  {
122  path_type = spec->info.spec.meta_class;
123  if (path_type == PT_PATH_INNER)
124  return PT_PATH_INNER;
125  if (path_type != PT_PATH_OUTER)
126  best_path_type = PT_PATH_OUTER_WEASEL;
127 
128  path_type = qo_find_best_path_type (spec->info.spec.path_entities);
129  if (path_type == PT_PATH_INNER)
130  return PT_PATH_INNER;
131  if (path_type != PT_PATH_OUTER)
132  best_path_type = PT_PATH_OUTER_WEASEL;
133 
134  spec = spec->next;
135  }
136 
137  return best_path_type;
138 }
139 
140 /*
141  * qo_get_name_by_spec_id () - looks for a name with a matching id
142  * return: PT_NODE *
143  * parser(in): parser environment
144  * node(in): (name) node to compare id's with
145  * arg(in): info of spec and result
146  * continue_walk(in):
147  */
148 static PT_NODE *
149 qo_get_name_by_spec_id (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
150 {
151  SPEC_ID_INFO *info = (SPEC_ID_INFO *) arg;
152 
153  if (node->node_type == PT_NAME && node->info.name.spec_id == info->id)
154  {
155  *continue_walk = PT_STOP_WALK;
156  info->appears = true;
157  }
158 
159  return node;
160 }
161 
162 /*
163  * qo_check_nullable_expr () -
164  * return:
165  * parser(in):
166  * node(in):
167  * arg(in):
168  * continue_walk(in):
169  */
170 PT_NODE *
171 qo_check_nullable_expr (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
172 {
173  int *nullable_cntp = (int *) arg;
174 
175  if (node->node_type == PT_EXPR)
176  {
177  /* check for nullable term: expr(..., NULL, ...) can be non-NULL */
178  switch (node->info.expr.op)
179  {
180  case PT_IS_NULL:
181  case PT_CASE:
182  case PT_COALESCE:
183  case PT_NVL:
184  case PT_NVL2:
185  case PT_DECODE:
186  case PT_IF:
187  case PT_IFNULL:
188  case PT_ISNULL:
189  case PT_CONCAT_WS:
190  /* NEED FUTURE OPTIMIZATION */
191  (*nullable_cntp)++;
192  break;
193  default:
194  break;
195  }
196  }
197 
198  return node;
199 }
200 
201 /*
202  * qo_check_nullable_expr_with_spec () -
203  * return:
204  * parser(in):
205  * node(in):
206  * arg(in):
207  * continue_walk(in):
208  */
209 PT_NODE *
210 qo_check_nullable_expr_with_spec (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
211 {
212  SPEC_ID_INFO *info = (SPEC_ID_INFO *) arg;
213 
214  if (node->node_type == PT_EXPR)
215  {
216  /* check for nullable term: expr(..., NULL, ...) can be non-NULL */
217  switch (node->info.expr.op)
218  {
219  case PT_IS_NULL:
220  case PT_CASE:
221  case PT_COALESCE:
222  case PT_NVL:
223  case PT_NVL2:
224  case PT_DECODE:
225  case PT_IF:
226  case PT_IFNULL:
227  case PT_ISNULL:
228  case PT_CONCAT_WS:
229  info->appears = false;
230  parser_walk_tree (parser, node, qo_get_name_by_spec_id, info, NULL, NULL);
231  if (info->appears)
232  {
233  info->nullable = true;
234  *continue_walk = PT_STOP_WALK;
235  }
236  break;
237  default:
238  break;
239  }
240  }
241 
242  return node;
243 }
244 
245 /*
246  * qo_replace_spec_name_with_null () - replace spec names with PT_TYPE_NULL pt_values
247  * return: PT_NODE *
248  * parser(in): parser environment
249  * node(in): (name) node to compare id's with
250  * arg(in): spec
251  * continue_walk(in):
252  */
253 static PT_NODE *
254 qo_replace_spec_name_with_null (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
255 {
256  PT_NODE *spec = (PT_NODE *) arg;
257  PT_NODE *name;
258 
259  if (node->node_type == PT_NAME && node->info.name.spec_id == spec->info.spec.id)
260  {
261  node->node_type = PT_VALUE;
262  node->type_enum = PT_TYPE_NULL;
263  }
264 
265  if (node->node_type == PT_DOT_ && (name = node->info.dot.arg2) && name->info.name.spec_id == spec->info.spec.id)
266  {
267  parser_free_tree (parser, name);
268  parser_free_tree (parser, node->info.expr.arg1);
269  node->node_type = PT_VALUE;
270  node->type_enum = PT_TYPE_NULL;
271  /* By changing this node, we need to null the value container so that we protect parts of the code that ignore
272  * type_enum set to PT_TYPE_NULL. This is particularly problematic on PCs since they have different alignment
273  * requirements. */
274  node->info.value.data_value.set = NULL;
275  }
276 
277  return node;
278 }
279 
280 /*
281  * qo_check_condition_yields_null () -
282  * return:
283  * parser(in): parser environment
284  * path_spec(in): to test attributes as NULL
285  * query_where(in): clause to evaluate
286  */
287 static bool
289 {
290  PT_NODE *where;
291  bool result = false;
292  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
293 
294  if (query_where == NULL)
295  {
296  return result;
297  }
298 
299  where = parser_copy_tree_list (parser, query_where);
300  where = parser_walk_tree (parser, where, qo_replace_spec_name_with_null, path_spec, NULL, NULL);
301 
302  sc_info.top_node = where;
303  sc_info.donot_fold = false;
304  where = pt_semantic_type (parser, where, &sc_info);
305  result = pt_false_search_condition (parser, where);
306  parser_free_tree (parser, where);
307 
308  /*
309  * Ignore any error returned from semantic type check.
310  * Just wanted to evaluate where clause with nulled spec names.
311  */
312  if (pt_has_error (parser))
313  {
314  parser_free_tree (parser, parser->error_msgs);
315  parser->error_msgs = NULL;
316  }
317 
318  return result;
319 }
320 
321 /*
322  * qo_analyze_path_join_pre () -
323  * return: PT_NODE *
324  * parser(in): parser environment
325  * spec(in): path entity to test
326  * arg(in): where clause to test
327  * continue_walk(in):
328  *
329  * Note : prunes non spec's
330  */
331 static PT_NODE *
332 qo_analyze_path_join_pre (PARSER_CONTEXT * parser, PT_NODE * spec, void *arg, int *continue_walk)
333 {
334  *continue_walk = PT_CONTINUE_WALK;
335 
336  if (spec->node_type != PT_SPEC)
337  {
338  *continue_walk = PT_STOP_WALK;
339  }
340 
341  return spec;
342 }
343 
344 /*
345  * qo_analyze_path_join () -
346  * return: PT_NODE *
347  * parser(in): parser environment
348  * path_spec(in): path entity to test
349  * arg(in): where clause to test
350  * continue_walk(in):
351  *
352  * Note: tests all non-selector path spec's for the type of join
353  * that can be done.
354  * if a null path can be guaranteed to produce no row
355  * tags spec as PT_INNER_PATH
356  *
357  * if a null path can have no effect on
358  * (does not appear in) the where clause
359  * tags spec as PT_PATH_OUTER
360  *
361  * if a null path COULD affect the where clause (appears),
362  * but cannot be guaranteed to have no effect,
363  * tags the spec as PT_PATH_OUTER_WEASEL. This means
364  * no merge, since I can't prove that this is equivalent
365  * to PT_PATH_INNER. This is treated the same as
366  * PT_PATH_OUTER, with apologies for the silly name.
367  *
368  */
369 static PT_NODE *
370 qo_analyze_path_join (PARSER_CONTEXT * parser, PT_NODE * path_spec, void *arg, int *continue_walk)
371 {
372  PT_NODE *where = (PT_NODE *) arg;
373  PT_MISC_TYPE path_type;
374  SPEC_ID_INFO info;
375 
376  *continue_walk = PT_CONTINUE_WALK;
377 
378  if (path_spec->node_type == PT_SPEC && path_spec->info.spec.path_conjuncts
379  && path_spec->info.spec.meta_class != PT_PATH_INNER)
380  {
381  /* to get here, this must be a 'normal' outer path entity We may be able to optimize this to an inner path if
382  * any sub path is an PT_PATH_INNER, so is this one. otherwise, if any sub-path is NOT an PT_PATH_OUTER, the best
383  * we can be is a WEASEL :). Since we are a post function, sub-paths are already set. */
384  path_type = qo_find_best_path_type (path_spec->info.spec.path_entities);
385 
386  path_spec->info.spec.meta_class = path_type;
387 
388  if (path_type != PT_PATH_INNER)
389  {
390  info.id = path_spec->info.spec.id;
391  info.appears = false;
392  parser_walk_tree (parser, where, qo_get_name_by_spec_id, &info, NULL, NULL);
393 
394  if (info.appears)
395  {
396  if (qo_check_condition_yields_null (parser, path_spec, where))
397  {
398  path_spec->info.spec.meta_class = PT_PATH_INNER;
399  }
400  else
401  {
403  }
404  }
405  else
406  {
407  /* best path type already assigned above */
408  }
409  }
410  }
411 
412  return path_spec;
413 }
414 
415 #if defined(ENABLE_UNUSED_FUNCTION)
416 /*
417  * qo_convert_path_to_name () -
418  * return: PT_NODE *
419  * parser(in): parser environment
420  * node(in): node to test for path conversion
421  * arg(in):
422  * continue_walk(in):
423  */
424 static PT_NODE *
425 qo_convert_path_to_name (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
426 {
427  PT_NODE *spec = (PT_NODE *) arg;
428  PT_NODE *name;
429 
430  if (node->node_type == PT_DOT_ && (name = node->info.dot.arg2) && name->node_type == PT_NAME
431  && name->info.name.spec_id == spec->info.spec.id)
432  {
433  node->info.dot.arg2 = NULL;
434  name->next = node->next;
435  node->next = NULL;
436  parser_free_tree (parser, node);
437  node = name;
438  if (spec->info.spec.range_var)
439  {
441  }
442  }
443  return node;
444 }
445 
446 /*
447  * qo_rewrite_as_join () - Given a statement, a path root, a path spec ptr,
448  * rewrite the statement into a join with the path spec
449  * return:
450  * parser(in):
451  * root(in):
452  * statement(in):
453  * path_spec_ptr(in):
454  */
455 static void
456 qo_rewrite_as_join (PARSER_CONTEXT * parser, PT_NODE * root, PT_NODE * statement, PT_NODE ** path_spec_ptr)
457 {
458  PT_NODE *path_spec;
459  PT_NODE *conjunct;
460 
461  path_spec = *path_spec_ptr;
462 
463  conjunct = path_spec->info.spec.path_conjuncts;
464  path_spec->info.spec.path_conjuncts = NULL;
465  *path_spec_ptr = path_spec->next;
466  path_spec->next = root->next;
467  root->next = path_spec;
468  statement->info.query.q.select.where = parser_append_node (conjunct, statement->info.query.q.select.where);
469  statement = parser_walk_tree (parser, statement, qo_convert_path_to_name, path_spec, NULL, NULL);
470 }
471 
472 /*
473  * qo_rewrite_as_derived () - Given a statement, a path root, a path spec ptr,
474  * rewrite the spec to be a table derived from a join
475  * of the path_spec table and the root table
476  * return:
477  * parser(in):
478  * root(in):
479  * root_where(in):
480  * statement(in):
481  * path_spec_ptr(in):
482  */
483 static void
484 qo_rewrite_as_derived (PARSER_CONTEXT * parser, PT_NODE * root, PT_NODE * root_where, PT_NODE * statement,
485  PT_NODE ** path_spec_ptr)
486 {
487  PT_NODE *path_spec;
488  PT_NODE *conjunct;
489  PT_NODE *new_spec;
490  PT_NODE *new_root;
491  PT_NODE *query;
492  PT_NODE *temp;
493 
494  path_spec = *path_spec_ptr;
495  new_spec = parser_copy_tree (parser, path_spec);
496  if (new_spec == NULL)
497  {
498  PT_INTERNAL_ERROR (parser, "copy tree");
499  return;
500  }
501 
502  conjunct = new_spec->info.spec.path_conjuncts;
503  new_spec->info.spec.path_conjuncts = NULL;
504 
505  if (root->info.spec.derived_table)
506  {
507  /* if the root spec is a derived table query, construct a derived table query for this path spec by building on
508  * top of that. This will be the case for outer path expressions 2 or more deep. */
509  query = parser_copy_tree (parser, root->info.spec.derived_table);
510  if (query == NULL)
511  {
512  PT_INTERNAL_ERROR (parser, "copy tree");
513  return;
514  }
515 
516  new_root = query->info.query.q.select.from;
517  parser_free_tree (parser, query->info.query.q.select.list);
518  }
519  else
520  {
521  /* if the root spec is a class spec, construct a derived table query for this path spec from scratch. */
522  new_root = parser_copy_tree (parser, root);
523  query = parser_new_node (parser, PT_SELECT);
524 
525  if (query == NULL)
526  {
527  PT_INTERNAL_ERROR (parser, "allocate new node");
528  return;
529  }
530 
531  query->info.query.q.select.from = new_root;
532  query->info.query.correlation_level = 0;
533  }
534  new_root = parser_append_node (new_spec, new_root);
536  query->info.query.q.select.where = parser_append_node (root_where, query->info.query.q.select.where);
537  query->info.query.q.select.where = parser_append_node (conjunct, query->info.query.q.select.where);
538  temp = query->info.query.q.select.list = parser_copy_tree_list (parser, path_spec->info.spec.referenced_attrs);
539  while (temp)
540  {
541  /* force all the names to be fully qualified */
542  temp->info.name.resolved = new_spec->info.spec.range_var->info.name.original;
543  temp = temp->next;
544  }
546  mq_regenerate_if_ambiguous (parser, new_spec, query, new_root);
547  mq_set_references (parser, query, new_spec);
548  mq_set_references (parser, query, new_root);
549 
550  /* Here we set up positional correspondance to the derived queries select list, but we must preserve the spec
551  * identity of the path_spec, so we copy the original referenced attrs, not the copied/reset list. */
552  temp = path_spec->info.spec.as_attr_list = parser_copy_tree_list (parser, path_spec->info.spec.referenced_attrs);
553  while (temp)
554  {
555  temp->info.name.resolved = NULL;
556  temp = temp->next;
557  }
558 
559  parser_free_tree (parser, path_spec->info.spec.entity_name);
560  path_spec->info.spec.entity_name = NULL;
561  parser_free_tree (parser, path_spec->info.spec.flat_entity_list);
562  path_spec->info.spec.flat_entity_list = NULL;
563 
564  path_spec->info.spec.derived_table = query;
566 }
567 #endif /* ENABLE_UNUSED_FUNCTION */
568 
569 /*
570  * qo_convert_attref_to_dotexpr_pre () -
571  * return:
572  * parser(in):
573  * spec(in):
574  * arg(in):
575  * continue_walk(in):
576  *
577  * Note: prunes PT_SPEC
578  */
579 static PT_NODE *
580 qo_convert_attref_to_dotexpr_pre (PARSER_CONTEXT * parser, PT_NODE * spec, void *arg, int *continue_walk)
581 {
582  TO_DOT_INFO *info = (TO_DOT_INFO *) arg;
583 
584  *continue_walk = PT_CONTINUE_WALK;
585 
586  if (spec->node_type == PT_SPEC && spec->info.spec.id == info->old_spec->info.spec.id)
587  {
588  *continue_walk = PT_LIST_WALK;
589  }
590  return spec;
591 }
592 
593 /*
594  * qo_convert_attref_to_dotexpr () -
595  * return:
596  * parser(in):
597  * node(in):
598  * arg(in):
599  * continue_walk(in):
600  *
601  * Note: looks for any attribute reference x.i in
602  * select x.i, ... from c x, ... where x.i ... and x {=|IN} expr
603  * and rewrites those into path expressions t.x.i in
604  * select t.x.i, ... from table({expr}) as t(x), ... where t.x.i ...
605  */
606 static PT_NODE *
607 qo_convert_attref_to_dotexpr (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
608 {
609  TO_DOT_INFO *info = (TO_DOT_INFO *) arg;
610  PT_NODE *arg1, *arg2, *attr, *rvar;
611  PT_NODE *new_spec = info->new_spec;
612 
613  if (node->node_type == PT_NAME && node->info.name.spec_id == info->old_spec->info.spec.id)
614  {
615  attr = new_spec->info.spec.as_attr_list;
616  rvar = new_spec->info.spec.range_var;
617 
618  switch (node->info.name.meta_class)
619  {
620  case PT_CLASS:
621  /* must be a data_type entity, so don't change its original name because later xasl domain handling code may
622  * use that name to look up the class. */
623  break;
624  case PT_OID_ATTR:
625  /* resolve the name to the new_spec */
626  node->info.name.spec_id = new_spec->info.spec.id;
627  node->info.name.original = attr->info.name.original;
628  node->info.name.resolved = rvar->info.name.original;
629  /* an OID_ATTR becomes a NORMAL attribute reference */
630  if (node->info.name.meta_class == PT_OID_ATTR)
631  node->info.name.meta_class = PT_NORMAL;
632  break;
633  case PT_NORMAL:
634  /* we must transform this NAME node into a DOT node in place to preserve its address. (Otherwise, we have to
635  * find all the places that point to it and change them all.) */
636  {
637  arg2 = parser_copy_tree (parser, node);
638  if (arg2)
639  {
640  arg2->next = NULL;
641  }
642  arg1 = pt_name (parser, attr->info.name.original);
643  if (arg1)
644  {
645  arg1->info.name.resolved = rvar->info.name.original;
646  arg1->info.name.spec_id = new_spec->info.spec.id;
647  arg1->info.name.meta_class = PT_NORMAL;
648  arg1->type_enum = attr->type_enum;
649  arg1->data_type = parser_copy_tree (parser, attr->data_type);
650  }
651 
652  int coll_modifier = node->info.name.coll_modifier;
653  short tag_click_counter = node->info.name.tag_click_counter;
654 
655  pt_init_node (node, PT_DOT_);
656  node->info.dot.arg1 = arg1;
657  node->info.dot.arg2 = arg2;
658  node->info.dot.coll_modifier = coll_modifier;
659  node->info.dot.tag_click_counter = tag_click_counter;
660  }
661  break;
662  default:
663  break;
664  }
665  }
666  else if (node->node_type == PT_SPEC && node->info.spec.id == info->old_spec->info.spec.id)
667  {
668  *continue_walk = PT_LIST_WALK;
669  }
670  return node;
671 }
672 
673 /*
674  * qo_get_next_oid_pred () -
675  * return:
676  * pred(in): cursor into a subquery's where clause
677  *
678  * Note:
679  * It requires pred is a cursor into a subquery's where clause that has been
680  * transformed into conjunctive normal form and
681  * effects that returns a pointer to subquery's next CNF-term that can be
682  * rewritten into an oid attribute equality test, if one exists.
683  * returns a NULL pointer otherwise.
684  */
685 static PT_NODE *
687 {
688  while (pred && pred->node_type == PT_EXPR && pred->or_next == NULL)
689  {
690  if (pred->info.expr.op == PT_EQ || pred->info.expr.op == PT_IS_IN)
691  {
692  if (pred->info.expr.arg1 && pred->info.expr.arg1->node_type == PT_NAME
694  {
695  return pred;
696  }
697  if (pred->info.expr.arg2 && pred->info.expr.arg2->node_type == PT_NAME
699  {
700  return pred;
701  }
702  }
703  pred = pred->next;
704  }
705 
706  return pred;
707 }
708 
709 /*
710  * qo_is_oid_const () -
711  * return: Returns true iff the argument looks like a constant for
712  * the purposes f the oid equality rewrite optimization
713  * node(in):
714  */
715 static int
717 {
718  if (node == NULL)
719  {
720  return 0;
721  }
722 
723  switch (node->node_type)
724  {
725  case PT_VALUE:
726  case PT_HOST_VAR:
727  return 1;
728 
729  case PT_NAME:
730  /*
731  * This *could* look to see if the name is correlated to the same
732  * level as the caller, but that's going to require more context
733  * to come in...
734  */
735  return node->info.name.meta_class == PT_PARAMETER;
736 
737  case PT_FUNCTION:
740  {
741  return 0;
742  }
743  else
744  {
745  /*
746  * The is the case for an expression like
747  *
748  * {:a, :b, :c}
749  *
750  * Here the the expression '{:a, :b, :c}' comes in as a
751  * sequence function call, with PT_NAMEs 'a', 'b', and 'c' as
752  * its arglist.
753  */
754  PT_NODE *p;
755 
756  for (p = node->info.function.arg_list; p; p = p->next)
757  {
758  if (!qo_is_oid_const (p))
759  return 0;
760  }
761  return 1;
762  }
763 
764  case PT_SELECT:
765  case PT_UNION:
766  case PT_DIFFERENCE:
767  case PT_INTERSECTION:
768  return node->info.query.correlation_level != 1;
769 
770  default:
771  return 0;
772  }
773 }
774 
775 /*
776  * qo_construct_new_set () -
777  * return:
778  * parser(in): parser context
779  * node(in): an OID_ATTR equality/IN predicate
780  *
781  * Note:
782  * It requires that node is an OID_ATTR predicate (x {=|IN} expr) from
783  * select ... from c x, ... where ... and x {=|IN} expr
784  * and modifies parser heap
785  * and effects that creates, initializes, returns a new set constructor
786  * subtree that can be used for the derived table field of a new PT_SPEC
787  * node representing 'table({expr}) as t(x)' in the rewritten
788  * select ... from table({expr}) as t(x), ... where ...
789  */
790 static PT_NODE *
792 {
793  PT_NODE *arg = NULL, *set = NULL;
794  /* jabaek: modify SQLM */
795  PT_NODE *targ = NULL;
796 
797  /* make sure we have reasonable arguments */
798  if (!node || node->node_type != PT_EXPR)
799  return set;
800 
801  /* if control reaches here, then qo_get_next_oid_pred must have succeeded in finding a CNF-term: 'x {=|IN} expr' from
802  * a query select ... from c x, ... where ... and x {=|IN} expr Now, copy 'expr' into a derived table:
803  * 'table({expr})' which the caller will put into the transformed query select ... from table({expr}) as t(x), ...
804  * where ... */
805  switch (node->info.expr.op)
806  {
807  case PT_EQ:
808  if (node->info.expr.arg1 && node->info.expr.arg1->node_type == PT_NAME
810  {
811  arg = parser_copy_tree (parser, node->info.expr.arg2);
812  targ = node->info.expr.arg1;
813  }
814  else if (node->info.expr.arg2 && node->info.expr.arg2->node_type == PT_NAME
816  {
817  arg = parser_copy_tree (parser, node->info.expr.arg1);
818  targ = node->info.expr.arg2;
819  }
820  break;
821  case PT_IS_IN:
822  if (PT_IS_OID_NAME (node->info.expr.arg1) && PT_IS_FUNCTION (node->info.expr.arg2)
824  {
825  arg = parser_copy_tree (parser, node->info.expr.arg2->info.function.arg_list);
826  targ = node->info.expr.arg1;
827  }
828  else if (PT_IS_OID_NAME (node->info.expr.arg2) && PT_IS_FUNCTION (node->info.expr.arg1)
830  {
831  arg = parser_copy_tree (parser, node->info.expr.arg1->info.function.arg_list);
832  targ = node->info.expr.arg2;
833  }
834  break;
835  default:
836  break;
837  }
838 
839  /* create mset constructor subtree */
840  if (arg && (set = parser_new_node (parser, PT_FUNCTION)) != NULL)
841  {
843  set->info.function.arg_list = arg;
845 
846  set->data_type = parser_copy_tree_list (parser, arg->data_type);
847  }
848 
849  return set;
850 }
851 
852 /*
853  * qo_make_new_derived_tblspec () -
854  * return:
855  * parser(in): parser context
856  * node(in): a PT_SPEC node
857  * pred(in): node's OID_ATTR predicate
858  * seqno(in/out): sequence number for generating unique derived table names
859  *
860  * Note:
861  * It requires that node is the PT_SPEC node (c x) and
862  * pred is the OID_ATTR predicate (x {=|IN} expr) from
863  * select ... from c x, ... where ... and x {=|IN} expr
864  * and modifies parser heap, node
865  * and effects that creates, initializes, returns a new derived table
866  * type PT_SPEC node representing 'table({expr}) as t(x)' in the rewritten
867  * select ... from table({expr}) as t(x), ... where ...
868  */
869 static PT_NODE *
870 qo_make_new_derived_tblspec (PARSER_CONTEXT * parser, PT_NODE * node, PT_NODE * pred, int *seqno)
871 {
872  PT_NODE *spec = NULL, *dtbl, *eq = NULL, *rvar;
873  UINTPTR spec_id;
874  const char *dtblnam, *dattnam;
875 
876  dtbl = qo_construct_new_set (parser, pred);
877  if (!dtbl)
878  {
879  return NULL;
880  }
881 
882  spec = parser_new_node (parser, PT_SPEC);
883  if (spec)
884  {
885  spec_id = (UINTPTR) spec;
886  spec->info.spec.id = spec_id;
887  spec->info.spec.only_all = PT_ONLY;
889  spec->info.spec.derived_table = dtbl;
890  dtblnam = mq_generate_name (parser, "dt", seqno);
891  dattnam = mq_generate_name (parser, "da", seqno);
892  spec->info.spec.range_var = pt_name (parser, dtblnam);
893  if (spec->info.spec.range_var == NULL)
894  {
895  goto exit_on_error;
896  }
897  spec->info.spec.range_var->info.name.spec_id = spec_id;
898  spec->info.spec.as_attr_list = pt_name (parser, dattnam);
899  if (spec->info.spec.as_attr_list == NULL)
900  {
901  goto exit_on_error;
902  }
903  spec->info.spec.as_attr_list->info.name.spec_id = spec_id;
906  spec->info.spec.as_attr_list->data_type = parser_copy_tree (parser, dtbl->data_type);
907  if (node && node->node_type == PT_SPEC && (rvar = node->info.spec.range_var) != NULL)
908  {
909  /* new derived table spec needs path entities */
910  spec->info.spec.path_entities = node;
911 
912  /* we also need to graft a path conjunct to node */
913  node->info.spec.path_conjuncts = eq = parser_new_node (parser, PT_EXPR);
914  if (eq)
915  {
916  eq->type_enum = PT_TYPE_LOGICAL;
917  eq->info.expr.op = PT_EQ;
918  eq->info.expr.arg1 = pt_name (parser, dattnam);
919  if (eq->info.expr.arg1 == NULL)
920  {
921  goto exit_on_error;
922  }
923  eq->info.expr.arg1->info.name.spec_id = spec_id;
924  eq->info.expr.arg1->info.name.resolved = dtblnam;
925  eq->info.expr.arg1->info.name.meta_class = PT_NORMAL;
926  eq->info.expr.arg1->type_enum = PT_TYPE_OBJECT;
927  eq->info.expr.arg1->data_type = parser_copy_tree (parser, dtbl->data_type);
928  eq->info.expr.arg2 = pt_name (parser, "");
929  if (eq->info.expr.arg2 == NULL)
930  {
931  goto exit_on_error;
932  }
933  eq->info.expr.arg2->info.name.spec_id = node->info.spec.id;
934  eq->info.expr.arg2->info.name.resolved = rvar->info.name.original;
935  eq->info.expr.arg2->info.name.meta_class = PT_OID_ATTR;
936  eq->info.expr.arg2->type_enum = PT_TYPE_OBJECT;
937  eq->info.expr.arg2->data_type = parser_copy_tree (parser, dtbl->data_type);
938  }
939  }
940  }
941  return spec;
942 
943 exit_on_error:
944  if (eq)
945  {
946  if (eq->info.expr.arg1)
947  {
948  parser_free_node (parser, eq->info.expr.arg1);
949  }
950  if (eq->info.expr.arg2)
951  {
952  parser_free_node (parser, eq->info.expr.arg2);
953  }
954  }
955  if (spec->info.spec.range_var)
956  {
957  parser_free_node (parser, spec->info.spec.range_var);
958  }
959  if (spec->info.spec.as_attr_list)
960  {
961  parser_free_node (parser, spec->info.spec.as_attr_list);
962  }
963  parser_free_node (parser, spec);
964  return NULL;
965 }
966 
967 /*
968  * qo_rewrite_oid_equality () -
969  * return:
970  * parser(in): parser context
971  * node(in): a subquery
972  * pred(in): subquery's OID_ATTR equality/IN predicate
973  * seqno(in/out): seq number for generating unique derived table/attr names
974  *
975  * Note:
976  * It requires that node is a subquery of the form
977  * select ... from c x, ... where ... and x {=|IN} expr
978  * pred is x {=|IN} expr
979  * and modifies node
980  * and effects that rewrites node into the form
981  * select ... from table({expr}) as t(x), ... where ...
982  */
983 static PT_NODE *
984 qo_rewrite_oid_equality (PARSER_CONTEXT * parser, PT_NODE * node, PT_NODE * pred, int *seqno)
985 {
986  PT_NODE *prev, *next, *from, *new_spec, *prev_spec = NULL;
987  UINTPTR spec_id = 0;
988  int found;
989 
990  /* make sure we have reasonable arguments */
991  if (pred->node_type != PT_EXPR || pred->type_enum != PT_TYPE_LOGICAL
992  || (pred->info.expr.op != PT_EQ && pred->info.expr.op != PT_IS_IN))
993  {
994  return node;
995  }
996  else if (pred->info.expr.arg1 && pred->info.expr.arg1->node_type == PT_NAME
998  {
999  spec_id = pred->info.expr.arg1->info.name.spec_id;
1000  }
1001  else if (pred->info.expr.arg2 && pred->info.expr.arg2->node_type == PT_NAME
1003  {
1004  spec_id = pred->info.expr.arg2->info.name.spec_id;
1005  }
1006  else
1007  {
1008  return node; /* bail out without rewriting node */
1009  }
1010 
1011  /* make sure spec_id resolves to a regular spec in node */
1012  from = node->info.query.q.select.from;
1013  if (from && from->node_type == PT_SPEC && from->info.spec.id == spec_id)
1014  {
1015  found = 1;
1016  }
1017  else
1018  {
1019  found = 0;
1020  prev_spec = from;
1021  while (from && from->node_type == PT_SPEC)
1022  {
1023  if (from->info.spec.id == spec_id)
1024  {
1025  found = 1;
1026  break;
1027  }
1028  prev_spec = from;
1029  from = from->next;
1030  }
1031  }
1032 
1033  if (!found)
1034  {
1035  return node; /* bail out without rewriting node */
1036  }
1037 
1038  /* There is no advantage to rewriting class OID predicates like select ... from class c x, ... where x = expr so
1039  * screen those cases out now. */
1040  if (from->info.spec.meta_class == PT_META_CLASS)
1041  return node; /* bail out without rewriting node */
1042 
1043  /* put node's PT_SPEC into a new derived table type PT_SPEC */
1044  new_spec = qo_make_new_derived_tblspec (parser, from, pred, seqno);
1045  if (!new_spec)
1046  return node; /* bail out without rewriting node */
1047 
1048  /* excise pred from node's where clause */
1049  if (pred == node->info.query.q.select.where)
1050  {
1051  node->info.query.q.select.where = pred->next;
1052  }
1053  else
1054  {
1055  prev = next = node->info.query.q.select.where;
1056  while (next)
1057  {
1058  if (next == pred)
1059  {
1060  prev->next = next->next;
1061  break;
1062  }
1063  prev = next;
1064  next = next->next;
1065  }
1066  }
1067 
1068  /* replace old PT_SPEC with new_spec in node's from list */
1069  new_spec->next = from->next;
1070  from->next = NULL;
1071  if (from == node->info.query.q.select.from)
1072  {
1073  node->info.query.q.select.from = new_spec;
1074  }
1075  else if (prev_spec != NULL)
1076  {
1077  prev_spec->next = new_spec;
1078  }
1079 
1080  /* transform attribute references x.i in select x.i, ... from c x, ... where x.i ... and x {=|IN} expr into path
1081  * expressions t.x.i in select t.x.i, ... from table({expr}) as t(x), ... where t.x.i ... */
1082  {
1083  TO_DOT_INFO dinfo;
1084  dinfo.old_spec = from;
1085  dinfo.new_spec = new_spec;
1087  }
1088 
1089  node = mq_reset_ids_in_statement (parser, node);
1090  return node;
1091 }
1092 
1093 /*
1094  * qo_collect_name_spec () -
1095  * return:
1096  * parser(in):
1097  * node(in):
1098  * arg(in):
1099  * continue_walk(in):
1100  */
1101 static PT_NODE *
1102 qo_collect_name_spec (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
1103 {
1104  PT_NAME_SPEC_INFO *info = (PT_NAME_SPEC_INFO *) arg;
1105 
1106  *continue_walk = PT_CONTINUE_WALK;
1107 
1108  switch (node->node_type)
1109  {
1110  case PT_DOT_:
1111  node = pt_get_end_path_node (node);
1112  if (node->node_type != PT_NAME)
1113  {
1114  break; /* impossible case, give up */
1115  }
1116 
1117  /* FALL THROUGH */
1118 
1119  case PT_NAME:
1120  if (info->c_name->info.name.location > 0 && info->c_name->info.name.location < node->info.name.location)
1121  {
1122  /* next outer join location */
1123  }
1124  else
1125  {
1126  if (node->info.name.spec_id == info->c_name->info.name.spec_id)
1127  {
1128  /* check for name spec is same */
1129  if (pt_name_equal (parser, node, info->c_name))
1130  {
1131  info->c_name_num++; /* found reduced attr */
1132  }
1133  }
1134  else
1135  {
1136  PT_NODE *point, *s_name;
1137 
1138  /* check for spec in other spec */
1139  for (point = info->s_point_list; point; point = point->next)
1140  {
1141  s_name = point;
1142  CAST_POINTER_TO_NODE (s_name);
1143  if (s_name->info.name.spec_id == node->info.name.spec_id)
1144  break;
1145  }
1146 
1147  /* not found */
1148  if (!point)
1149  {
1150  info->s_point_list = parser_append_node (pt_point (parser, node), info->s_point_list);
1151  }
1152  }
1153  }
1154 
1155  *continue_walk = PT_LIST_WALK;
1156  break;
1157 
1158  case PT_SELECT:
1159  case PT_UNION:
1160  case PT_DIFFERENCE:
1161  case PT_INTERSECTION:
1162  /* simply give up when we find query in predicate */
1163  info->query_serial_num++;
1164  break;
1165 
1166  case PT_EXPR:
1167  if (node->info.expr.op == PT_NEXT_VALUE || node->info.expr.op == PT_CURRENT_VALUE)
1168  {
1169  /* simply give up when we find serial */
1170  info->query_serial_num++;
1171  break;
1172  }
1173 
1174  if (PT_HAS_COLLATION (info->c_name->type_enum) && node->info.expr.op == PT_CAST
1175  && PT_HAS_COLLATION (node->type_enum) && node->info.expr.arg1 != NULL
1176  && node->info.expr.arg1->node_type == PT_NAME
1177  && node->info.expr.arg1->info.name.spec_id == info->c_name->info.name.spec_id)
1178  {
1179  int cast_coll = LANG_SYS_COLLATION;
1180  int name_coll = LANG_SYS_COLLATION;
1181 
1182  name_coll = PT_GET_COLLATION_MODIFIER (info->c_name);
1183 
1184  if (name_coll == -1 && info->c_name->data_type != NULL)
1185  {
1186  name_coll = info->c_name->data_type->info.data_type.collation_id;
1187  }
1188 
1190  {
1191  cast_coll = PT_GET_COLLATION_MODIFIER (node);
1192  }
1193  else if (node->data_type != NULL)
1194  {
1195  cast_coll = node->data_type->info.data_type.collation_id;
1196  }
1197 
1198  if (cast_coll != name_coll)
1199  {
1200  /* predicate evaluates with different collation */
1201  info->query_serial_num++;
1202  }
1203  }
1204  break;
1205  default:
1206  break;
1207  } /* switch (node->node_type) */
1208 
1209  if (info->query_serial_num > 0)
1210  {
1211  *continue_walk = PT_STOP_WALK;
1212  }
1213 
1214  return node;
1215 }
1216 
1217 /*
1218  * qo_collect_name_spec_post () -
1219  * return:
1220  * parser(in):
1221  * node(in):
1222  * arg(in):
1223  * continue_walk(in):
1224  */
1225 static PT_NODE *
1226 qo_collect_name_spec_post (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
1227 {
1228  PT_NAME_SPEC_INFO *info = (PT_NAME_SPEC_INFO *) arg;
1229 
1230  *continue_walk = PT_CONTINUE_WALK;
1231 
1232  if (info->query_serial_num > 0)
1233  {
1234  *continue_walk = PT_STOP_WALK;
1235  }
1236 
1237  return node;
1238 }
1239 
1240 /*
1241  * qo_is_cast_attr () -
1242  * return:
1243  * expr(in):
1244  */
1245 static int
1247 {
1248  PT_NODE *arg1;
1249 
1250  /* check for CAST-expr */
1251  if (!expr || expr->node_type != PT_EXPR || expr->info.expr.op != PT_CAST || !(arg1 = expr->info.expr.arg1))
1252  {
1253  return 0;
1254  }
1255 
1256  return pt_is_attr (arg1);
1257 }
1258 
1259 /*
1260  * qo_is_reduceable_const () -
1261  * return:
1262  * expr(in):
1263  */
1264 static int
1266 {
1267  while (expr && expr->node_type == PT_EXPR)
1268  {
1269  if (expr->info.expr.op == PT_CAST || expr->info.expr.op == PT_TO_ENUMERATION_VALUE)
1270  {
1271  expr = expr->info.expr.arg1;
1272  }
1273  else
1274  {
1275  return false; /* give up */
1276  }
1277  }
1278 
1279  return PT_IS_CONST_INPUT_HOSTVAR (expr);
1280 }
1281 
1282 /*
1283  * qo_reduce_equality_terms () -
1284  * return:
1285  * parser(in):
1286  * node(in):
1287  * wherep(in):
1288  *
1289  * Obs: modified to support PRIOR operator as follows:
1290  * -> PRIOR field = exp1 AND PRIOR field = exp2 =>
1291  * PRIOR field = exp1 AND exp1 = exp2
1292  * -> PRIOR ? -> replace with ?
1293  */
1294 static void
1296 {
1297  PT_NODE *from;
1298  PT_NODE **orgp;
1299  PT_NODE *accumulator, *expr, *arg1, *arg2, *temp, *next;
1300  PT_NODE *join_term, *join_term_list, *s_name1, *s_name2;
1301  PT_NAME_SPEC_INFO info1, info2;
1302  int spec1_cnt, spec2_cnt;
1303  bool found_equality_term, found_join_term;
1304  PT_NODE *spec, *derived_table, *attr, *col;
1305  int i, num_check, idx;
1306  PT_NODE *save_where_next;
1307  bool copy_arg2;
1308  PT_NODE *dt1, *dt2;
1309 
1310  /* init */
1311  orgp = wherep;
1312  accumulator = NULL;
1313  join_term_list = NULL;
1314 
1315  while ((expr = *wherep))
1316  {
1317  col = NULL; /* init - reserve for constant column of derived-table */
1318 
1319  /* check for 1st phase; keep out OR conjunct; 1st init */
1320  found_equality_term = (expr->or_next == NULL) ? true : false;
1321 
1322  if (found_equality_term != true)
1323  {
1324  wherep = &(*wherep)->next;
1325  continue; /* give up */
1326  }
1327 
1328  /* check for 2nd phase; '=', 'range ( =)' keep out function index expr = const */
1329  found_equality_term = false; /* 2nd init */
1330 
1331  if (expr->info.expr.op == PT_EQ && expr->info.expr.arg1 && expr->info.expr.arg2
1334  { /* 'opd = opd' */
1335  found_equality_term = true; /* pass 2nd phase */
1336  num_check = 2;
1337  }
1338  else if (expr->info.expr.op == PT_RANGE)
1339  { /* 'opd range (opd =)' */
1340  PT_NODE *between_and;
1341 
1342  between_and = expr->info.expr.arg2;
1343  if (between_and->or_next == NULL /* has only one range */
1344  && between_and->info.expr.op == PT_BETWEEN_EQ_NA)
1345  {
1346  found_equality_term = true; /* pass 2nd phase */
1347  num_check = 1;
1348  }
1349  }
1350 
1351  if (found_equality_term != true)
1352  {
1353  wherep = &(*wherep)->next;
1354  continue; /* give up */
1355  }
1356 
1357  /* check for 3rd phase; 'attr = const', 'attr range (const =)' */
1358  found_equality_term = false; /* 3rd init */
1359 
1360  for (i = 0; i < num_check; i++)
1361  {
1362  arg1 = (i == 0) ? expr->info.expr.arg1 : expr->info.expr.arg2;
1363  arg2 = (i == 0) ? expr->info.expr.arg2 : expr->info.expr.arg1;
1364 
1365  if (expr->info.expr.op == PT_RANGE)
1366  {
1367  arg2 = arg2->info.expr.arg1;
1368  }
1369 
1370  /* if arg1 is expression with PRIOR, move arg1 to the arg1 of PRIOR */
1371 
1372  if (arg1->node_type == PT_EXPR && arg1->info.expr.op == PT_PRIOR && pt_is_attr (arg1->info.expr.arg1))
1373  {
1374  arg1 = arg1->info.expr.arg1;
1375  }
1376 
1377  if (pt_is_attr (arg1) || pt_is_function_index_expression (arg1))
1378  {
1379  if (qo_is_reduceable_const (arg2))
1380  {
1381  found_equality_term = true;
1382  break; /* immediately break */
1383  }
1384  else if (pt_is_attr (arg2))
1385  {
1386  ; /* nop */
1387  }
1388  else if (qo_is_cast_attr (arg2))
1389  {
1390  arg2 = arg2->info.expr.arg1;
1391  }
1392  else
1393  {
1394  continue; /* not found. step to next */
1395  }
1396 
1397  if (node->node_type == PT_SELECT)
1398  {
1399  from = node->info.query.q.select.from;
1400  }
1401  else if (node->node_type == PT_DELETE)
1402  {
1403  from = node->info.delete_.spec;
1404  }
1405  else if (node->node_type == PT_UPDATE)
1406  {
1407  from = node->info.update.spec;
1408  }
1409  else
1410  {
1411  from = NULL; /* not found. step to next */
1412  }
1413 
1414  for (spec = from; spec; spec = spec->next)
1415  {
1416  if (spec->info.spec.id == arg2->info.name.spec_id)
1417  break; /* found match */
1418  }
1419 
1420  /* if arg2 is derived alias col, get its corresponding constant column from derived-table */
1421  if (spec && spec->info.spec.derived_table_type == PT_IS_SUBQUERY
1422  && (derived_table = spec->info.spec.derived_table) && derived_table->node_type == PT_SELECT)
1423  {
1424  /* traverse as_attr_list */
1425  for (attr = spec->info.spec.as_attr_list, idx = 0; attr; attr = attr->next, idx++)
1426  {
1427  if (pt_name_equal (parser, attr, arg2))
1428  break; /* found match */
1429  } /* for (attr = ...) */
1430 
1431  /* get corresponding column */
1432  col = pt_get_select_list (parser, derived_table);
1433  for (; col && idx; col = col->next, idx--)
1434  {
1435  ; /* step to next */
1436  }
1437 
1438  /* do not reduce PT_NAME that belongs to PT_NODE_LIST to PT_VALUE */
1439  if (attr && col && !PT_IS_VALUE_QUERY (col) && qo_is_reduceable_const (col))
1440  {
1441  /* add additional equailty-term; is reduced */
1442  PT_NODE *expr_copy = parser_copy_tree (parser, expr);
1444  *wherep = parser_append_node (expr_copy, *wherep);
1445 
1446  /* select-list's PT_NODE can have next PT_NODEs. so copy select_list to col node */
1447  col = parser_copy_tree (parser, col);
1448 
1449  /* reset arg1, arg2 */
1450  arg1 = arg2;
1451  arg2 = col;
1452 
1453  found_equality_term = true;
1454  break; /* immediately break */
1455  }
1456  } /* if arg2 is derived alias-column */
1457  } /* if (pt_is_attr(arg1)) */
1458  } /* for (i = 0; ...) */
1459 
1460  if (found_equality_term != true)
1461  {
1462  wherep = &(*wherep)->next;
1463  continue; /* give up */
1464  }
1465 
1466  /*
1467  * now, finally pass all check
1468  */
1469 
1470  save_where_next = (*wherep)->next;
1471 
1472  if (pt_is_attr (arg2))
1473  {
1474  temp = arg1;
1475  arg1 = arg2;
1476  arg2 = temp;
1477  }
1478 
1479  /* at here, arg1 is reduced attr */
1480 
1481  *wherep = expr->next;
1482  if (col)
1483  {
1484  ; /* corresponding constant column of derived-table */
1485  }
1486  else
1487  {
1488  expr->next = accumulator;
1489  accumulator = expr;
1490  }
1491 
1492  /* Restart where at beginning of WHERE clause because we may find new terms after substitution, and must
1493  * substitute entire where clause because incoming order is arbitrary. */
1494  wherep = orgp;
1495 
1496  temp = pt_get_end_path_node (arg1);
1497 
1498  info1.c_name = temp;
1499  info2.c_name = temp;
1500 
1501  /* save reduced join terms */
1502  for (temp = *wherep; temp; temp = temp->next)
1503  {
1504  if (temp == expr)
1505  {
1506  /* this is the working equality_term, skip and go ahead */
1507  continue;
1508  }
1509 
1510  if (temp->node_type != PT_EXPR || !pt_is_symmetric_op (temp->info.expr.op))
1511  {
1512  /* skip and go ahead */
1513  continue;
1514  }
1515 
1516  next = temp->next; /* save and cut-off link */
1517  temp->next = NULL;
1518 
1519  /* check for already added join term */
1520  for (join_term = join_term_list; join_term; join_term = join_term->next)
1521  {
1522  if (join_term->etc == (void *) temp)
1523  {
1524  break; /* found */
1525  }
1526  }
1527 
1528  /* check for not added join terms */
1529  if (join_term == NULL)
1530  {
1531 
1532  found_join_term = false; /* init */
1533 
1534  /* check for attr of other specs */
1535  if (temp->or_next == NULL)
1536  {
1537  info1.c_name_num = 0;
1538  info1.query_serial_num = 0;
1539  info1.s_point_list = NULL;
1540  (void) parser_walk_tree (parser, temp->info.expr.arg1, qo_collect_name_spec, &info1,
1541  qo_collect_name_spec_post, &info1);
1542 
1543  info2.c_name_num = 0;
1544  info2.query_serial_num = 0;
1545  info2.s_point_list = NULL;
1546  if (info1.query_serial_num == 0)
1547  {
1548  (void) parser_walk_tree (parser, temp->info.expr.arg2, qo_collect_name_spec, &info2,
1549  qo_collect_name_spec_post, &info2);
1550  }
1551 
1552  if (info1.query_serial_num == 0 && info2.query_serial_num == 0)
1553  {
1554  /* check for join term related to reduced attr lhs and rhs has name of other spec CASE 1:
1555  * X.c_name = Y.attr CASE 2: X.c_name + Y.attr = ? CASE 3: Y.attr = X.c_name CASE 4: ? = Y.attr +
1556  * X.c_name */
1557 
1558  spec1_cnt = pt_length_of_list (info1.s_point_list);
1559  spec2_cnt = pt_length_of_list (info2.s_point_list);
1560 
1561  if (info1.c_name_num)
1562  {
1563  if (spec1_cnt == 0)
1564  { /* CASE 1 */
1565  if (spec2_cnt == 1)
1566  {
1567  found_join_term = true;
1568  }
1569  }
1570  else if (spec1_cnt == 1)
1571  { /* CASE 2 */
1572  if (spec2_cnt == 0)
1573  {
1574  found_join_term = true;
1575  }
1576  else if (spec2_cnt == 1)
1577  {
1578  s_name1 = info1.s_point_list;
1579  s_name2 = info2.s_point_list;
1580  CAST_POINTER_TO_NODE (s_name1);
1581  CAST_POINTER_TO_NODE (s_name2);
1582  if (s_name1->info.name.spec_id == s_name2->info.name.spec_id)
1583  {
1584  /* X.c_name + Y.attr = Y.attr */
1585  found_join_term = true;
1586  }
1587  else
1588  {
1589  /* X.c_name + Y.attr = Z.attr */
1590  ; /* nop */
1591  }
1592  }
1593  }
1594  }
1595  else if (info2.c_name_num)
1596  {
1597  if (spec2_cnt == 0)
1598  { /* CASE 3 */
1599  if (spec1_cnt == 1)
1600  {
1601  found_join_term = true;
1602  }
1603  }
1604  else if (spec2_cnt == 1)
1605  { /* CASE 4 */
1606  if (spec1_cnt == 0)
1607  {
1608  found_join_term = true;
1609  }
1610  else if (spec1_cnt == 1)
1611  {
1612  s_name1 = info1.s_point_list;
1613  s_name2 = info2.s_point_list;
1614  CAST_POINTER_TO_NODE (s_name1);
1615  CAST_POINTER_TO_NODE (s_name2);
1616  if (s_name1->info.name.spec_id == s_name2->info.name.spec_id)
1617  {
1618  /* Y.attr = Y.attr + X.c_name */
1619  found_join_term = true;
1620  }
1621  else
1622  {
1623  /* Z.attr = Y.attr + X.c_name */
1624  ; /* nop */
1625  }
1626  }
1627  }
1628  }
1629  }
1630 
1631  /* free name list */
1632  if (info1.s_point_list)
1633  {
1634  parser_free_tree (parser, info1.s_point_list);
1635  }
1636  if (info2.s_point_list)
1637  {
1638  parser_free_tree (parser, info2.s_point_list);
1639  }
1640  } /* if (temp->or_next == NULL) */
1641 
1642  if (found_join_term)
1643  {
1644  join_term = parser_copy_tree (parser, temp);
1645 
1646  if (join_term != NULL)
1647  {
1648  join_term->etc = (void *) temp; /* mark as added */
1649  join_term_list = parser_append_node (join_term, join_term_list);
1650  }
1651  }
1652 
1653  } /* if (join_term == NULL) */
1654 
1655  temp->next = next; /* restore link */
1656  } /* for (term = *wherep; term; term = term->next) */
1657 
1658  copy_arg2 = false; /* init */
1659 
1660  if (PT_IS_PARAMETERIZED_TYPE (arg1->type_enum))
1661  {
1662  DB_VALUE *dbval, dbval_res;
1663  TP_DOMAIN *dom;
1664 
1665  /* don't replace node's data type precision, scale */
1666  if (PT_IS_CONST_NOT_HOSTVAR (arg2))
1667  {
1668  dom = pt_node_to_db_domain (parser, arg1, NULL);
1669  dom = tp_domain_cache (dom);
1670  if (dom->precision <= DB_MAX_LITERAL_PRECISION)
1671  {
1672  if ((dbval = pt_value_to_db (parser, arg2)) == NULL)
1673  {
1674  *wherep = save_where_next;
1675  continue; /* give up */
1676  }
1677  db_make_null (&dbval_res);
1678  if (tp_value_cast_force (dbval, &dbval_res, dom, false) != DOMAIN_COMPATIBLE)
1679  {
1681  pt_short_print (parser, arg2), pt_show_type_enum (arg1->type_enum));
1682  *wherep = save_where_next;
1683  continue; /* give up */
1684  }
1685  temp = pt_dbval_to_value (parser, &dbval_res);
1686  pr_clear_value (&dbval_res);
1687  }
1688  else
1689  { /* too big literal string */
1690  PT_NODE *dt = NULL;
1691  if (arg1->type_enum == PT_TYPE_ENUMERATION)
1692  {
1693  /* be sure to cast to the same enumeration type */
1694  dt = arg1->data_type;
1695  }
1696 
1697  temp =
1698  pt_wrap_with_cast_op (parser, parser_copy_tree_list (parser, arg2), arg1->type_enum,
1700  if (temp == NULL)
1701  {
1703  *wherep = save_where_next;
1704  continue; /* give up */
1705  }
1706  }
1707  }
1708  else
1709  { /* is CAST expr */
1710  if ((dt1 = arg1->data_type) && (dt2 = arg2->data_type) && dt1->type_enum == dt2->type_enum
1711  && (dt1->info.data_type.precision == dt2->info.data_type.precision)
1713  {
1714  /* exactly the same type */
1715  if ((temp = parser_copy_tree_list (parser, arg2)) == NULL)
1716  {
1718  *wherep = save_where_next;
1719  continue; /* give up */
1720  }
1721  }
1722  else
1723  { /* create nested CAST node */
1724  PT_NODE *dt = NULL;
1725  if (arg1->type_enum == PT_TYPE_ENUMERATION)
1726  {
1727  /* be sure to cast to the same enumeration type */
1728  dt = arg1->data_type;
1729  }
1730  temp =
1731  pt_wrap_with_cast_op (parser, parser_copy_tree_list (parser, arg2), arg1->type_enum,
1733  if (temp == NULL)
1734  {
1736  *wherep = save_where_next;
1737  continue; /* give up */
1738  }
1739  }
1740  }
1741 
1742  arg2 = temp;
1743 
1744  copy_arg2 = true; /* mark as copy */
1745  }
1746 
1747  /* replace 'arg1' in '*wherep' with 'arg2' with location checking */
1748  temp = pt_get_end_path_node (arg1);
1749 
1750  if (node->node_type == PT_SELECT)
1751  {
1752  /* query with WHERE condition */
1753  node->info.query.q.select.list = pt_lambda_with_arg (parser, node->info.query.q.select.list, arg1, arg2,
1754  (temp->info.name.location > 0 ? true : false), 1,
1755  true /* dont_replace */ );
1756  }
1757  *wherep = pt_lambda_with_arg (parser, *wherep, arg1, arg2, (temp->info.name.location > 0 ? true : false), 1,
1758  false /* dont_replace: DEFAULT */ );
1759 
1760  /* Leave "wherep" pointing at the begining of the rest of the predicate. We still gurantee loop termination
1761  * because we have removed a term. future iterations which do not fall into this case will advance to the next
1762  * term. */
1763 
1764  /* free copied constant column */
1765  if (copy_arg2)
1766  {
1767  parser_free_tree (parser, arg2);
1768  }
1769  }
1770 
1771  *orgp = parser_append_node (accumulator, *orgp);
1772 
1773  if (join_term_list)
1774  {
1775  /* mark as transitive join terms and append to the WHERE clause */
1776  for (join_term = join_term_list; join_term; join_term = join_term->next)
1777  {
1779  join_term->etc = (void *) NULL; /* clear */
1780  }
1781 
1782  *orgp = parser_append_node (join_term_list, *orgp);
1783  }
1784 
1785 }
1786 
1787 /*
1788  * qo_reduce_order_by_for () - move orderby_num() to groupby_num()
1789  * return: NO_ERROR if successful, otherwise returns error number
1790  * parser(in): parser global context info for reentrancy
1791  * node(in): query node has ORDER BY
1792  *
1793  * Note:
1794  * It modifies parser's heap of PT_NODEs(parser->error_msgs)
1795  * and effects that remove order by for clause
1796  */
1797 static int
1799 {
1800  int error = NO_ERROR;
1801  PT_NODE *ord_num, *grp_num;
1802 
1803  if (node->node_type != PT_SELECT)
1804  {
1805  return error;
1806  }
1807 
1808  ord_num = NULL;
1809  grp_num = NULL;
1810 
1811  /* move orderby_num() to groupby_num() */
1812  if (node->info.query.orderby_for)
1813  {
1814  /* generate orderby_num(), groupby_num() */
1815  if (!(ord_num = parser_new_node (parser, PT_EXPR)) || !(grp_num = parser_new_node (parser, PT_FUNCTION)))
1816  {
1817  if (ord_num)
1818  {
1819  parser_free_tree (parser, ord_num);
1820  }
1822  goto exit_on_error;
1823  }
1824 
1825  ord_num->type_enum = PT_TYPE_BIGINT;
1826  ord_num->info.expr.op = PT_ORDERBY_NUM;
1828 
1829  grp_num->type_enum = PT_TYPE_BIGINT;
1831  grp_num->info.function.arg_list = NULL;
1832  grp_num->info.function.all_or_distinct = PT_ALL;
1833 
1834  /* replace orderby_num() to groupby_num() */
1835  node->info.query.orderby_for = pt_lambda_with_arg (parser, node->info.query.orderby_for, ord_num, grp_num,
1836  false /* loc_check: DEFAULT */ ,
1837  0 /* type: DEFAULT */ ,
1838  false /* dont_replace: DEFAULT */ );
1839 
1840  /* Even though node->info.q.query.q.select has no orderby_num so far, it is a safe guard to prevent potential
1841  * rewrite problem. */
1842  node->info.query.q.select.list = pt_lambda_with_arg (parser, node->info.query.q.select.list, ord_num, grp_num,
1843  false /* loc_check: DEFAULT */ ,
1844  0 /* type: DEFAULT */ ,
1845  false /* dont_replace: DEFAULT */ );
1846 
1847  node->info.query.q.select.having =
1849 
1850  node->info.query.orderby_for = NULL;
1851 
1852  parser_free_tree (parser, ord_num);
1853  parser_free_tree (parser, grp_num);
1854  }
1855 
1856 exit_on_end:
1857 
1858  return error;
1859 
1860 exit_on_error:
1861 
1862  if (error == NO_ERROR)
1863  {
1864  /* missing compiler error list */
1865  error = ER_GENERIC_ERROR;
1866  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
1867  }
1868  goto exit_on_end;
1869 }
1870 
1871 /*
1872  * reduce_order_by () -
1873  * return: NO_ERROR, if successful, otherwise returns error number
1874  * parser(in): parser global context info for reentrancy
1875  * node(in): query node has ORDER BY
1876  *
1877  * Note:
1878  * It modifies parser's heap of PT_NODEs(parser->error_msgs)
1879  * and effects that reduce the constant orders
1880  */
1881 static int
1883 {
1884  int error = NO_ERROR;
1885  PT_NODE *order, *order_next, *order_prev, *col, *col2, *col2_next;
1886  PT_NODE *r, *new_r;
1887  int i, j;
1888  int const_order_count, order_move_count;
1889  bool need_merge_check;
1890  bool has_orderbynum_with_groupby;
1891 
1892  /* do not reduce order by siblings */
1893  if (node->node_type != PT_SELECT || node->info.query.q.select.connect_by)
1894  {
1895  return error;
1896  }
1897 
1898  /* init */
1899  const_order_count = order_move_count = 0;
1900  need_merge_check = false;
1901  has_orderbynum_with_groupby = false;
1902 
1903  /* check for merge order by to group by( without DISTINCT and HAVING clause) */
1904 
1905  if (node->info.query.all_distinct == PT_DISTINCT)
1906  {
1907  ; /* give up */
1908  }
1909  else
1910  {
1911  if (node->info.query.q.select.group_by && node->info.query.q.select.having == NULL && node->info.query.order_by)
1912  {
1913  bool ordbynum_flag;
1914 
1915  ordbynum_flag = false; /* init */
1916 
1917  /* check for orderby_num() in the select list */
1919  pt_check_orderbynum_post, &ordbynum_flag);
1920 
1921  if (ordbynum_flag)
1922  { /* found orderby_num() in the select list */
1923  has_orderbynum_with_groupby = true; /* give up */
1924  }
1925  else
1926  {
1927  need_merge_check = true; /* mark to checking */
1928  }
1929  }
1930  }
1931 
1932  /* the first phase, do check the current order by */
1933  if (need_merge_check)
1934  {
1936  {
1937  if (qo_reduce_order_by_for (parser, node) != NO_ERROR)
1938  {
1939  goto exit_on_error;
1940  }
1941 
1942  if (node->info.query.orderby_for == NULL && !node->info.query.q.select.connect_by)
1943  {
1944  /* clear unnecessary node info */
1945  parser_free_tree (parser, node->info.query.order_by);
1946  node->info.query.order_by = NULL;
1947  }
1948 
1949  need_merge_check = false; /* clear */
1950  }
1951  }
1952 
1953  order_prev = NULL;
1954  for (order = node->info.query.order_by; order; order = order_next)
1955  {
1956  order_next = order->next;
1957 
1958  r = order->info.sort_spec.expr;
1959 
1960  /*
1961  * safe guard: check for integer value. */
1962  if (r->node_type != PT_VALUE)
1963  {
1964  goto exit_on_error;
1965  }
1966 
1967  col = node->info.query.q.select.list;
1968  for (i = 1; i < r->info.value.data_value.i; i++)
1969  {
1970  if (col == NULL)
1971  { /* impossible case */
1972  break;
1973  }
1974  col = col->next;
1975  }
1976 
1977  /*
1978  * safe guard: invalid parse tree */
1979  if (col == NULL)
1980  {
1981  goto exit_on_error;
1982  }
1983 
1984  col = pt_get_end_path_node (col);
1985  if (col->node_type == PT_NAME)
1986  {
1988  {
1989  /* remove constant order node */
1990  if (order_prev == NULL)
1991  { /* the first */
1992  node->info.query.order_by = order->next; /* re-link */
1993  }
1994  else
1995  {
1996  order_prev->next = order->next; /* re-link */
1997  }
1998  order->next = NULL; /* cut-off */
1999  parser_free_tree (parser, order);
2000 
2001  const_order_count++; /* increase const entry remove count */
2002 
2003  continue; /* go ahead */
2004  }
2005 
2006  /* for non-constant order, change order position to the same left-most col's position */
2007  col2 = node->info.query.q.select.list;
2008  for (j = 1; j < i; j++)
2009  {
2010  col2_next = col2->next; /* save next link */
2011 
2012  col2 = pt_get_end_path_node (col2);
2013 
2014  /* change to the same left-most col */
2015  if (pt_name_equal (parser, col2, col))
2016  {
2017  new_r = parser_new_node (parser, PT_VALUE);
2018  if (new_r == NULL)
2019  {
2021  PT_ERRORm (parser, col, MSGCAT_SET_PARSER_SEMANTIC, error);
2022  goto exit_on_error;
2023  }
2024 
2025  new_r->type_enum = PT_TYPE_INTEGER;
2026  new_r->info.value.data_value.i = j;
2027  pt_value_to_db (parser, new_r);
2028  parser_free_tree (parser, r);
2029  order->info.sort_spec.expr = new_r;
2030  order->info.sort_spec.pos_descr.pos_no = j;
2031 
2032  order_move_count++; /* increase entry move count */
2033 
2034  break; /* exit for-loop */
2035  }
2036 
2037  col2 = col2_next; /* restore next link */
2038  }
2039  }
2040 
2041  order_prev = order; /* go ahead */
2042  }
2043 
2044  if (order_move_count > 0)
2045  {
2046  PT_NODE *match;
2047 
2048  /* now check for duplicate entries. - If they match on ascending/descending, remove the second. - If they do
2049  * not, generate an error. */
2050  for (order = node->info.query.order_by; order; order = order->next)
2051  {
2052  while ((match = pt_find_order_value_in_list (parser, order->info.sort_spec.expr, order->next)))
2053  {
2054  if ((order->info.sort_spec.asc_or_desc != match->info.sort_spec.asc_or_desc)
2055  || (pt_to_null_ordering (order) != pt_to_null_ordering (match)))
2056  {
2058  PT_ERRORmf (parser, match, MSGCAT_SET_PARSER_SEMANTIC, error, pt_short_print (parser, match));
2059  goto exit_on_error;
2060  }
2061  else
2062  {
2063  order->next = pt_remove_from_list (parser, match, order->next);
2064  }
2065  } /* while */
2066  } /* for (order = ...) */
2067  }
2068 
2069  if (const_order_count > 0)
2070  { /* is reduced */
2071  /* the second phase, do check with reduced order by */
2072  if (need_merge_check)
2073  {
2075  {
2076  if (qo_reduce_order_by_for (parser, node) != NO_ERROR)
2077  {
2078  goto exit_on_error;
2079  }
2080 
2081  if (node->info.query.orderby_for == NULL && !node->info.query.q.select.connect_by)
2082  {
2083  /* clear unnecessary node info */
2084  parser_free_tree (parser, node->info.query.order_by);
2085  node->info.query.order_by = NULL;
2086  }
2087 
2088  need_merge_check = false; /* clear */
2089  }
2090  }
2091  else
2092  {
2093  if (node->info.query.order_by == NULL)
2094  {
2095  /* move orderby_num() to inst_num() */
2096  if (node->info.query.orderby_for)
2097  {
2098  PT_NODE *ord_num, *ins_num;
2099 
2100  ord_num = NULL;
2101  ins_num = NULL;
2102 
2103  /* generate orderby_num(), inst_num() */
2104  if (!(ord_num = parser_new_node (parser, PT_EXPR)) || !(ins_num = parser_new_node (parser, PT_EXPR)))
2105  {
2106  if (ord_num)
2107  {
2108  parser_free_tree (parser, ord_num);
2109  }
2111  goto exit_on_error;
2112  }
2113 
2114  ord_num->type_enum = PT_TYPE_BIGINT;
2115  ord_num->info.expr.op = PT_ORDERBY_NUM;
2117 
2118  ins_num->type_enum = PT_TYPE_BIGINT;
2119  ins_num->info.expr.op = PT_INST_NUM;
2121 
2122  /* replace orderby_num() to inst_num() */
2123  node->info.query.orderby_for =
2124  pt_lambda_with_arg (parser, node->info.query.orderby_for, ord_num, ins_num,
2125  false /* loc_check: DEFAULT */ ,
2126  0 /* type: DEFAULT */ ,
2127  false /* dont_replace: DEFAULT */ );
2128 
2129  node->info.query.q.select.list =
2130  pt_lambda_with_arg (parser, node->info.query.q.select.list, ord_num, ins_num,
2131  false /* loc_check: DEFAULT */ ,
2132  0 /* type: DEFAULT */ ,
2133  false /* dont_replace: DEFAULT */ );
2134 
2135  node->info.query.q.select.where =
2137 
2138  node->info.query.orderby_for = NULL;
2139 
2140  parser_free_tree (parser, ord_num);
2141  parser_free_tree (parser, ins_num);
2142  }
2143  else if (has_orderbynum_with_groupby == true)
2144  {
2145  PT_NODE *ord_num, *grp_num;
2146 
2147  ord_num = NULL;
2148  grp_num = NULL;
2149 
2150  /* generate orderby_num(), groupby_num() */
2151  if (!(ord_num = parser_new_node (parser, PT_EXPR))
2152  || !(grp_num = parser_new_node (parser, PT_FUNCTION)))
2153  {
2154  if (ord_num)
2155  {
2156  parser_free_tree (parser, ord_num);
2157  }
2159  goto exit_on_error;
2160  }
2161 
2162  ord_num->type_enum = PT_TYPE_BIGINT;
2163  ord_num->info.expr.op = PT_ORDERBY_NUM;
2165 
2166  grp_num->type_enum = PT_TYPE_BIGINT;
2168  grp_num->info.function.arg_list = NULL;
2169  grp_num->info.function.all_or_distinct = PT_ALL;
2170 
2171  /* replace orderby_num() to groupby_num() */
2172  node->info.query.q.select.list = pt_lambda_with_arg (parser, node->info.query.q.select.list, ord_num,
2173  grp_num, false /* loc_check: DEFAULT */ ,
2174  0 /* type: DEFAULT */ ,
2175  false /* dont_replace: DEFAULT */ );
2176 
2177  parser_free_tree (parser, ord_num);
2178  parser_free_tree (parser, grp_num);
2179  }
2180  }
2181  }
2182  }
2183 
2184 exit_on_end:
2185 
2186  return error;
2187 
2188 exit_on_error:
2189 
2190  if (error == NO_ERROR)
2191  {
2192  /* missing compiler error list */
2193  error = ER_GENERIC_ERROR;
2194  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
2195  }
2196  goto exit_on_end;
2197 }
2198 
2199 /*
2200  * qo_converse_sarg_terms () -
2201  * return:
2202  * parser(in):
2203  * where(in): CNF list of WHERE clause
2204  *
2205  * Note:
2206  * Convert terms of the form 'constant op attr' to 'attr op constant'
2207  * by traversing expression tree with prefix order (left child,
2208  * right child, and then parent). Convert 'attr op attr' so, LHS has more
2209  * common attribute.
2210  *
2211  * examples:
2212  * 0. where 5 = a --> where a = 5
2213  * 1. where -5 = -a --> where a = 5
2214  * 2. where -5 = -(-a) --> where a = -5
2215  * 3. where 5 = -a --> where a = -5
2216  * 4. where 5 = -(-a) --> where a = 5
2217  * 5. where 5 > x.a and/or x.a = y.b --> where x.a < 5 and/or x.a = y.b
2218  * 6. where b = a or c = a --> where a = b or a = c
2219  * 7. where b = -a or c = a --> where a = -b or a = c
2220  * 8. where b = a or c = a --> where a = b or a = c
2221  * 9. where a = b or b = c or d = b --> where b = a or b = c or b = d
2222  *
2223  * Obs: modified to support PRIOR
2224  * examples:
2225  * 0. connect by 5 = prior a --> connect by prior a = 5
2226  * 1. connect by -5 = prior (-a) --> connect by prior a = 5
2227  * ...
2228  * prior(-attr) between opd1 and opd2 -->
2229  * prior(-attr) >= opd1 AND prior(-attr) <= opd2 -->
2230  * prior (attr) <= -opd1 AND prior(attr) >= -opd2 -->
2231  * prior (attr) between -opd2 and -opd1
2232  */
2233 static void
2235 {
2236  PT_NODE *cnf_node, *dnf_node, *arg1, *arg2, *arg1_arg1, *arg2_arg1;
2237  PT_NODE *arg1_prior_father, *arg2_prior_father;
2238  PT_OP_TYPE op_type;
2239  PT_NODE *attr, *attr_list;
2240  int arg1_cnt, arg2_cnt;
2241 
2242 
2243  /* traverse CNF list */
2244  for (cnf_node = where; cnf_node; cnf_node = cnf_node->next)
2245  {
2246  attr_list = NULL; /* init */
2247 
2248  /* STEP 1: traverse DNF list to generate attr_list */
2249  for (dnf_node = cnf_node; dnf_node; dnf_node = dnf_node->or_next)
2250  {
2251 
2252  if (dnf_node->node_type != PT_EXPR)
2253  {
2254  continue;
2255  }
2256 
2257  op_type = dnf_node->info.expr.op;
2258  /* not CNF/DNF form; give up */
2259  if (op_type == PT_AND || op_type == PT_OR)
2260  {
2261  if (attr_list)
2262  {
2263  parser_free_tree (parser, attr_list);
2264  attr_list = NULL;
2265  }
2266 
2267  break; /* immediately, exit loop */
2268  }
2269 
2270  arg1_prior_father = arg2_prior_father = NULL;
2271 
2272  arg1 = dnf_node->info.expr.arg1;
2273  /* go in PRIOR argument but memorize it for further node manag */
2274  if (pt_is_expr_node (arg1) && arg1->info.expr.op == PT_PRIOR)
2275  {
2276  arg1_prior_father = arg1;
2277  arg1 = arg1->info.expr.arg1;
2278  }
2279 
2280  arg1_arg1 = ((pt_is_expr_node (arg1) && arg1->info.expr.op == PT_UNARY_MINUS) ? arg1->info.expr.arg1 : NULL);
2281  while (pt_is_expr_node (arg1) && arg1->info.expr.op == PT_UNARY_MINUS)
2282  {
2283  arg1 = arg1->info.expr.arg1;
2284  }
2285 
2286  if (op_type == PT_BETWEEN && arg1_arg1 && pt_is_attr (arg1))
2287  {
2288  /* term in the form of '-attr between opd1 and opd2' convert to '-attr >= opd1 and -attr <= opd2' */
2289 
2290  /* check for one range spec */
2291  if (cnf_node == dnf_node && dnf_node->or_next == NULL)
2292  {
2293  arg2 = dnf_node->info.expr.arg2;
2294  assert (arg2->node_type == PT_EXPR);
2295  /* term of '-attr >= opd1' */
2296  dnf_node->info.expr.arg2 = arg2->info.expr.arg1;
2297  op_type = dnf_node->info.expr.op = PT_GE;
2298  /* term of '-attr <= opd2' */
2299  arg2->info.expr.arg1 = parser_copy_tree (parser, dnf_node->info.expr.arg1);
2300  arg2->info.expr.op = PT_LE;
2301  /* term of 'and' */
2302  arg2->next = dnf_node->next;
2303  dnf_node->next = arg2;
2304  }
2305  }
2306 
2307  arg2 = dnf_node->info.expr.arg2;
2308 
2309  /* go in PRIOR argument but memorize it for further node manag */
2310  if (pt_is_expr_node (arg2) && arg2->info.expr.op == PT_PRIOR)
2311  {
2312  arg2_prior_father = arg2;
2313  arg2 = arg2->info.expr.arg1;
2314  }
2315 
2316  while (pt_is_expr_node (arg2) && arg2->info.expr.op == PT_UNARY_MINUS)
2317  {
2318  arg2 = arg2->info.expr.arg1;
2319  }
2320 
2321  /* add sargable attribute to attr_list */
2322  if (arg1 && arg2 && pt_converse_op (op_type) != 0)
2323  {
2324  if (pt_is_attr (arg1))
2325  {
2326  for (attr = attr_list; attr; attr = attr->next)
2327  {
2328  if (pt_name_equal (parser, attr, arg1))
2329  {
2330  attr->line_number++; /* increase attribute count */
2331  break;
2332  }
2333  }
2334 
2335  /* not found; add new attribute */
2336  if (attr == NULL)
2337  {
2338  attr = pt_point (parser, arg1);
2339  if (attr != NULL)
2340  {
2341  attr->line_number = 1; /* set attribute count */
2342 
2343  attr_list = parser_append_node (attr_list, attr);
2344  }
2345  }
2346  }
2347 
2348  if (pt_is_attr (arg2))
2349  {
2350  for (attr = attr_list; attr; attr = attr->next)
2351  {
2352  if (pt_name_equal (parser, attr, arg2))
2353  {
2354  attr->line_number++; /* increase attribute count */
2355  break;
2356  }
2357  }
2358 
2359  /* not found; add new attribute */
2360  if (attr == NULL)
2361  {
2362  attr = pt_point (parser, arg2);
2363 
2364  if (attr != NULL)
2365  {
2366  attr->line_number = 1; /* set attribute count */
2367 
2368  attr_list = parser_append_node (attr_list, attr);
2369  }
2370  }
2371  }
2372  }
2373  }
2374 
2375  /* STEP 2: re-traverse DNF list to converse sargable terms */
2376  for (dnf_node = cnf_node; dnf_node; dnf_node = dnf_node->or_next)
2377  {
2378  if (dnf_node->node_type != PT_EXPR)
2379  continue;
2380 
2381  arg1_prior_father = arg2_prior_father = NULL;
2382 
2383  /* filter out unary minus nodes */
2384  while ((arg1 = dnf_node->info.expr.arg1) && (arg2 = dnf_node->info.expr.arg2))
2385  {
2386  /* go in PRIOR argument but memorize it for further node manag */
2387  if (pt_is_expr_node (arg1) && arg1->info.expr.op == PT_PRIOR)
2388  {
2389  arg1_prior_father = arg1;
2390  arg1 = arg1->info.expr.arg1;
2391  }
2392 
2393  if (pt_is_expr_node (arg2) && arg2->info.expr.op == PT_PRIOR)
2394  {
2395  arg2_prior_father = arg2;
2396  arg2 = arg2->info.expr.arg1;
2397  }
2398 
2399  op_type = pt_converse_op (dnf_node->info.expr.op);
2400  arg1_arg1 =
2401  ((pt_is_expr_node (arg1) && arg1->info.expr.op == PT_UNARY_MINUS) ? arg1->info.expr.arg1 : NULL);
2402  arg2_arg1 =
2403  ((pt_is_expr_node (arg2) && arg2->info.expr.op == PT_UNARY_MINUS) ? arg2->info.expr.arg1 : NULL);
2404 
2405  if (arg1_arg1 && arg2_arg1)
2406  {
2407  /* Delete both minus from prior also. */
2408  if (arg1_prior_father)
2409  {
2410  arg1_prior_father->info.expr.arg1 = arg1_prior_father->info.expr.arg1->info.expr.arg1;
2411  }
2412  if (arg2_prior_father)
2413  {
2414  arg2_prior_father->info.expr.arg1 = arg2_prior_father->info.expr.arg1->info.expr.arg1;
2415  }
2416 
2417  /* term in the form of '-something op -something' */
2418  dnf_node->info.expr.arg1 = arg1->info.expr.arg1;
2419  arg1->info.expr.arg1 = NULL;
2420  parser_free_tree (parser, arg1);
2421  dnf_node->info.expr.arg2 = arg2->info.expr.arg1;
2422  arg2->info.expr.arg1 = NULL;
2423  parser_free_tree (parser, arg2);
2424 
2425  /* both minus operators are gone but they were written over the prior operator so we must add them
2426  * again. */
2427  if (arg1_prior_father)
2428  {
2429  dnf_node->info.expr.arg1 = arg1_prior_father;
2430  }
2431  if (arg2_prior_father)
2432  {
2433  dnf_node->info.expr.arg2 = arg2_prior_father;
2434  }
2435  }
2436  else if (op_type != 0 && arg1_arg1
2437  && (pt_is_attr (arg1_arg1)
2438  || (pt_is_expr_node (arg1_arg1) && arg1_arg1->info.expr.op == PT_UNARY_MINUS))
2439  && pt_is_const (arg2))
2440  {
2441  /* arg1 was with prior, make the modifications in prior and move the prior to
2442  * dnf_node->info.expr.arg2 */
2443 
2444  /* prior (-attr) op const => prior attr op -const */
2445  if (arg1_prior_father)
2446  {
2447  /* cut - from prior -attr */
2448  arg1_prior_father->info.expr.arg1 = arg1->info.expr.arg1;
2449 
2450  dnf_node->info.expr.arg1 = arg1_prior_father;
2451  arg1->info.expr.arg1 = arg2;
2452  dnf_node->info.expr.arg2 = arg1;
2453  }
2454  else
2455  {
2456  /* term in the form of '-attr op const' or '-(-something) op const' */
2457  dnf_node->info.expr.arg1 = arg1->info.expr.arg1;
2458  arg1->info.expr.arg1 = arg2;
2459  dnf_node->info.expr.arg2 = arg1;
2460  }
2461  }
2462  else if (op_type != 0 && arg2_arg1
2463  && (pt_is_attr (arg2->info.expr.arg1)
2464  || (pt_is_expr_node (arg2_arg1) && arg2_arg1->info.expr.op == PT_UNARY_MINUS))
2465  && pt_is_const (arg1))
2466  {
2467  /* arg2 was with prior, make the modifications in prior and move the prior to
2468  * dnf_node->info.expr.arg1 */
2469 
2470  /* const op prior (-attr) => -const op prior attr */
2471  if (arg2_prior_father)
2472  {
2473  /* cut - from prior -attr */
2474  arg2_prior_father->info.expr.arg1 = arg2_prior_father->info.expr.arg1->info.expr.arg1;
2475 
2476  dnf_node->info.expr.arg2 = arg2_prior_father;
2477  arg2->info.expr.arg1 = arg1;
2478  dnf_node->info.expr.arg1 = arg2;
2479  }
2480  else
2481  {
2482  /* term in the form of 'const op -attr' or 'const op -(-something)' */
2483  dnf_node->info.expr.arg2 = arg2->info.expr.arg1;
2484  arg2->info.expr.arg1 = arg1;
2485  dnf_node->info.expr.arg1 = arg2;
2486  }
2487  }
2488  else
2489  {
2490  break;
2491  }
2492 
2493  /* swap term's operator */
2494  dnf_node->info.expr.op = op_type;
2495  }
2496 
2497  op_type = dnf_node->info.expr.op;
2498  arg1 = dnf_node->info.expr.arg1;
2499  arg2 = dnf_node->info.expr.arg2;
2500 
2501  arg1_prior_father = arg2_prior_father = NULL;
2502  /* if arg1 or arg2 is PT_PRIOR, go in its argument */
2503  if (pt_is_expr_node (arg1) && arg1->info.expr.op == PT_PRIOR)
2504  {
2505  /* keep its parent so when swapping the two elements, swap with its father */
2506  arg1_prior_father = arg1;
2507  arg1 = arg1->info.expr.arg1;
2508  }
2509  if (pt_is_expr_node (arg2) && arg2->info.expr.op == PT_PRIOR)
2510  {
2511  arg2_prior_father = arg2;
2512  arg2 = arg2->info.expr.arg1;
2513  }
2514 
2515  if (op_type == PT_AND)
2516  {
2517  /* not CNF form; what do I have to do? */
2518 
2519  /* traverse left child */
2520  qo_converse_sarg_terms (parser, arg1);
2521  /* traverse right child */
2522  qo_converse_sarg_terms (parser, arg2);
2523 
2524  }
2525  else if (op_type == PT_OR)
2526  {
2527  /* not DNF form; what do I have to do? */
2528 
2529  /* traverse left child */
2530  qo_converse_sarg_terms (parser, arg1);
2531  /* traverse right child */
2532  qo_converse_sarg_terms (parser, arg2);
2533 
2534  }
2535  /* sargable term, where 'op_type' is one of '=', '<' '<=', '>', or '>=' */
2536  else if (arg1 && arg2 && (op_type = pt_converse_op (op_type)) != 0 && pt_is_attr (arg2))
2537  {
2538 
2539  if (pt_is_attr (arg1))
2540  {
2541  /* term in the form of 'attr op attr' */
2542 
2543  arg1_cnt = arg2_cnt = 0; /* init */
2544  for (attr = attr_list; attr; attr = attr->next)
2545  {
2546  if (pt_name_equal (parser, attr, arg1))
2547  {
2548  arg1_cnt = attr->line_number;
2549  }
2550  else if (pt_name_equal (parser, attr, arg2))
2551  {
2552  arg2_cnt = attr->line_number;
2553  }
2554 
2555  if (arg1_cnt && arg2_cnt)
2556  {
2557  break; /* already found both arg1, arg2 */
2558  }
2559  }
2560 
2561  if (!arg1_cnt || !arg2_cnt)
2562  {
2563  /* something wrong; skip and go ahead */
2564  continue;
2565  }
2566 
2567  /* swap */
2568  if (arg1_cnt < arg2_cnt)
2569  {
2570  /* check if arg1 and/or arg2 have PRIOR above them. If so, swap the arg with the prior also */
2571  if (arg1_prior_father)
2572  {
2573  arg1 = arg1_prior_father;
2574  }
2575  if (arg2_prior_father)
2576  {
2577  arg2 = arg2_prior_father;
2578  }
2579 
2580  dnf_node->info.expr.arg1 = arg2;
2581  dnf_node->info.expr.arg2 = arg1;
2582  dnf_node->info.expr.op = op_type;
2583 
2584  /* change back arg1 and arg2 */
2585  if (arg1_prior_father)
2586  {
2587  arg1 = arg1_prior_father->info.expr.arg1;
2588  }
2589  if (arg2_prior_father)
2590  {
2591  arg2 = arg2_prior_father->info.expr.arg1;
2592  }
2593  }
2594  }
2595  else
2596  {
2597  /* term in the form of 'non-attr op attr' */
2598 
2599  /* swap */
2600 
2601  /* check if arg1 and/or arg2 have PRIOR above them. If so, swap the arg with the prior also */
2602  if (arg1_prior_father)
2603  {
2604  arg1 = arg1_prior_father;
2605  }
2606  if (arg2_prior_father)
2607  {
2608  arg2 = arg2_prior_father;
2609  }
2610 
2611  dnf_node->info.expr.arg1 = arg2;
2612  dnf_node->info.expr.arg2 = arg1;
2613  dnf_node->info.expr.op = op_type;
2614 
2615  /* change back arg1 and arg2 */
2616  if (arg1_prior_father)
2617  {
2618  arg1 = arg1_prior_father->info.expr.arg1;
2619  }
2620  if (arg2_prior_father)
2621  {
2622  arg2 = arg2_prior_father->info.expr.arg1;
2623  }
2624  }
2625  }
2626  }
2627 
2628  if (attr_list)
2629  {
2630  parser_free_tree (parser, attr_list);
2631  attr_list = NULL;
2632  }
2633  }
2634 }
2635 
2636 /*
2637  * qo_fold_is_and_not_null () - Make IS NOT NULL node that is always true as 1
2638  * and make IS NULL node that is always false as 0
2639  * return:
2640  * parser(in):
2641  * wherep(in): pointer to WHERE list
2642  */
2643 static void
2645 {
2646  PT_NODE *node, *sibling, *prev, *fold;
2647  DB_VALUE value;
2648  bool found;
2649  PT_NODE *node_prior, *sibling_prior;
2650 
2651  /* traverse CNF list and keep track of the pointer to previous node */
2652  prev = NULL;
2653  while ((node = (prev ? prev->next : *wherep)))
2654  {
2655  if (node->node_type != PT_EXPR || (node->info.expr.op != PT_IS_NULL && node->info.expr.op != PT_IS_NOT_NULL)
2656  || node->or_next != NULL)
2657  {
2658  /* neither expression node, IS NULL/IS NOT NULL node nor one predicate term */
2659  prev = prev ? prev->next : node;
2660  continue;
2661  }
2662 
2663  node_prior = pt_get_first_arg_ignore_prior (node);
2664  if (!pt_is_attr (node_prior))
2665  {
2666  /* LHS is not an attribute */
2667  prev = prev ? prev->next : node;
2668  continue;
2669  }
2670 
2671  /* search if there's a term that make this IS NULL/IS NOT NULL node meaningless; that is, a term that has the
2672  * same attribute */
2673  found = false;
2674  for (sibling = *wherep; sibling; sibling = sibling->next)
2675  {
2676  if (sibling == node || sibling->node_type != PT_EXPR || sibling->or_next != NULL)
2677  {
2678  continue;
2679  }
2680 
2681  if (sibling->info.expr.location != node->info.expr.location)
2682  {
2683  continue;
2684  }
2685 
2686  sibling_prior = pt_get_first_arg_ignore_prior (sibling);
2687 
2688  /* just one node from node and sibling contains the PRIOR -> do nothing, they are not comparable */
2689  if ((PT_IS_EXPR_WITH_PRIOR_ARG (node) && !PT_IS_EXPR_WITH_PRIOR_ARG (sibling))
2690  || (!PT_IS_EXPR_WITH_PRIOR_ARG (node) && PT_IS_EXPR_WITH_PRIOR_ARG (sibling)))
2691  {
2692  continue;
2693  }
2694 
2695  if (pt_check_path_eq (parser, node_prior, sibling_prior) == 0
2696  || pt_check_path_eq (parser, node_prior, sibling->info.expr.arg2) == 0)
2697  {
2698  found = true;
2699  break;
2700  }
2701  }
2702 
2703  if (found)
2704  {
2705  int truefalse;
2706 
2707  if (sibling->info.expr.op == PT_IS_NULL || sibling->info.expr.op == PT_IS_NOT_NULL)
2708  {
2709  /* a IS NULL(IS NOT NULL) AND a IS NULL(IS NOT NULL) case */
2710  truefalse = (node->info.expr.op == sibling->info.expr.op);
2711  }
2712  else if (sibling->info.expr.op == PT_NULLSAFE_EQ)
2713  {
2714  if (PT_IS_NULL_NODE (sibling->info.expr.arg1) || PT_IS_NULL_NODE (sibling->info.expr.arg2))
2715  {
2716  /* a IS NULL(IS NOT NULL) AND a <=> NULL case */
2717  truefalse = (node->info.expr.op == PT_IS_NULL);
2718  }
2719  else
2720  {
2721  /* a IS NULL(IS NOT NULL) AND a <=> expr(except NULL) case */
2722 
2723  /* We may optimize (a is null and a <=> expr) as (a is null and expr is null), (a is not null and a
2724  * <=> expr) as (a = expr) in the near future. */
2725  break;
2726  }
2727  }
2728  else
2729  {
2730  /* a IS NULL(IS NOT NULL) AND a < 10 case */
2731  truefalse = (node->info.expr.op == PT_IS_NOT_NULL);
2732  }
2733 
2734  db_make_int (&value, truefalse);
2735  fold = pt_dbval_to_value (parser, &value);
2736  if (fold == NULL)
2737  {
2738  return;
2739  }
2740 
2741  fold->type_enum = node->type_enum;
2742  fold->info.value.location = node->info.expr.location;
2743  pr_clear_value (&value);
2744  /* replace IS NULL/IS NOT NULL node with newly created VALUE node */
2745  if (prev)
2746  {
2747  prev->next = fold;
2748  }
2749  else
2750  {
2751  *wherep = fold;
2752  }
2753  fold->next = node->next;
2754  node->next = NULL;
2755  /* node->or_next == NULL */
2756  parser_free_tree (parser, node);
2757  node = fold->next;
2758  }
2759 
2760  prev = prev ? prev->next : node;
2761  }
2762 }
2763 
2764 /*
2765  * qo_search_comp_pair_term () -
2766  * return:
2767  * parser(in):
2768  * start(in):
2769  */
2770 static PT_NODE *
2772 {
2773  PT_NODE *node, *arg2;
2774  PT_OP_TYPE op_type1, op_type2;
2775  int find_const, find_attr;
2776  PT_NODE *arg_prior, *arg_prior_start;
2777 
2778  arg_prior = arg_prior_start = NULL;
2779 
2780  switch (start->info.expr.op)
2781  {
2782  case PT_GE:
2783  case PT_GT:
2784  op_type1 = PT_LE;
2785  op_type2 = PT_LT;
2786  break;
2787  case PT_LE:
2788  case PT_LT:
2789  op_type1 = PT_GE;
2790  op_type2 = PT_GT;
2791  break;
2792  default:
2793  return NULL;
2794  }
2795  /* skip out unary minus expr */
2796  arg2 = start->info.expr.arg2;
2797  while (pt_is_expr_node (arg2) && arg2->info.expr.op == PT_UNARY_MINUS)
2798  {
2799  arg2 = arg2->info.expr.arg1;
2800  }
2801  find_const = pt_is_const_expr_node (arg2);
2802  find_attr = pt_is_attr (start->info.expr.arg2);
2803 
2804  arg_prior_start = start->info.expr.arg1; /* original value */
2805  if (arg_prior_start->info.expr.op == PT_PRIOR)
2806  {
2807  arg_prior_start = arg_prior_start->info.expr.arg1;
2808  }
2809 
2810  /* search CNF list */
2811  for (node = start; node; node = node->next)
2812  {
2813  if (node->node_type != PT_EXPR || node->or_next != NULL)
2814  {
2815  /* neither expression node nor one predicate term */
2816  continue;
2817  }
2818 
2819  if (node->info.expr.location != start->info.expr.location)
2820  {
2821  continue;
2822  }
2823 
2824  arg_prior = pt_get_first_arg_ignore_prior (node);
2825 
2826  if (node->info.expr.op == op_type1 || node->info.expr.op == op_type2)
2827  {
2828  if (find_const && pt_is_attr (arg_prior) && (pt_check_path_eq (parser, arg_prior_start, arg_prior) == 0))
2829  {
2830  /* skip out unary minus expr */
2831  arg2 = node->info.expr.arg2;
2832  while (pt_is_expr_node (arg2) && arg2->info.expr.op == PT_UNARY_MINUS)
2833  {
2834  arg2 = arg2->info.expr.arg1;
2835  }
2836  if (pt_is_const_expr_node (arg2))
2837  {
2838  /* found 'attr op const' term */
2839  break;
2840  }
2841  }
2842  if (find_attr && pt_is_attr (arg_prior) && pt_is_attr (node->info.expr.arg2)
2843  && (pt_check_path_eq (parser, arg_prior_start, node->info.expr.arg1) == 0)
2844  && (pt_check_class_eq (parser, start->info.expr.arg2, node->info.expr.arg2) == 0))
2845  {
2846  /* found 'attr op attr' term */
2847  break;
2848  }
2849  }
2850  }
2851 
2852  return node;
2853 }
2854 
2855 /*
2856  * qo_reduce_comp_pair_terms () - Convert a pair of comparison terms to one
2857  * BETWEEN term
2858  * return:
2859  * parser(in):
2860  * wherep(in): pointer to WHERE
2861  *
2862  * Note:
2863  * examples:
2864  * 1) where a<=20 and a=>10 --> where a between 10 and(ge_le) 20
2865  * 2) where a<20 and a>10 --> where a between 10 gt_lt 20
2866  * 3) where a<B.b and a>=B.c --> where a between B.c ge_lt B.b
2867  */
2868 static void
2870 {
2871  PT_NODE *node, *pair, *lower, *upper, *prev, *next, *arg2;
2872  int location;
2873  DB_VALUE *lower_val, *upper_val;
2875 
2876  /* traverse CNF list */
2877  for (node = *wherep; node; node = node->next)
2878  {
2879  if (node->node_type != PT_EXPR
2880  || (!pt_is_attr (node->info.expr.arg1)
2881  && (!PT_IS_EXPR_WITH_PRIOR_ARG (node) || !pt_is_attr (node->info.expr.arg1->info.expr.arg1)))
2882  || node->or_next != NULL)
2883  {
2884  /* neither expression node, LHS is attribute, nor one predicate term */
2885  continue;
2886  }
2887 
2888  switch (node->info.expr.op)
2889  {
2890  case PT_GT:
2891  case PT_GE:
2892  lower = node;
2893  upper = pair = qo_search_comp_pair_term (parser, node);
2894  break;
2895  case PT_LT:
2896  case PT_LE:
2897  lower = pair = qo_search_comp_pair_term (parser, node);
2898  upper = node;
2899  break;
2900  default:
2901  /* not comparison term; continue to next node */
2902  continue;
2903  }
2904  if (!pair)
2905  {
2906  /* there's no pair comparison term having the same attribute */
2907  continue;
2908  }
2909 
2910  if ((PT_IS_EXPR_WITH_PRIOR_ARG (lower) && !PT_IS_EXPR_WITH_PRIOR_ARG (upper))
2911  || (!PT_IS_EXPR_WITH_PRIOR_ARG (lower) && PT_IS_EXPR_WITH_PRIOR_ARG (upper)))
2912  {
2913  /* one of the bounds does not contain prior */
2914  continue;
2915  }
2916 
2917  /* the node will be converted to BETWEEN node and the pair node will be converted to the right operand(arg2) of
2918  * BETWEEN node denoting the range of BETWEEN such as BETWEEN_GE_LE, BETWEEN_GE_LT, BETWEEN_GT_LE, and
2919  * BETWEEN_GT_LT */
2920 
2921  /* make the pair node to the right operand of BETWEEN node */
2923  &pair->info.expr.op) != 0)
2924  {
2925  /* cannot be occurred but something wrong */
2926  continue;
2927  }
2928  parser_free_tree (parser, pair->info.expr.arg1);
2929  pair->info.expr.arg1 = lower->info.expr.arg2;
2930  pair->info.expr.arg2 = upper->info.expr.arg2;
2931  /* should set pair->info.expr.arg1 before pair->info.expr.arg2 */
2932  /* make the node to BETWEEN node */
2933  node->info.expr.op = PT_BETWEEN;
2934  /* revert BETWEEN_GE_LE to BETWEEN_AND */
2935  if (pair->info.expr.op == PT_BETWEEN_GE_LE)
2936  {
2937  pair->info.expr.op = PT_BETWEEN_AND;
2938  }
2939  node->info.expr.arg2 = pair;
2940 
2941  /* adjust linked list */
2942  for (prev = node; prev->next != pair; prev = prev->next)
2943  ;
2944  prev->next = pair->next;
2945  pair->next = NULL;
2946 
2947  /* check if the between range is valid */
2948  arg2 = node->info.expr.arg2;
2949 
2950  lower = arg2->info.expr.arg1;
2951  upper = arg2->info.expr.arg2;
2952  if (pt_is_const_not_hostvar (lower) && pt_is_const_not_hostvar (upper))
2953  {
2954  lower_val = pt_value_to_db (parser, lower);
2955  upper_val = pt_value_to_db (parser, upper);
2956  cmp = (DB_VALUE_COMPARE_RESULT) db_value_compare (lower_val, upper_val);
2957  if (cmp == DB_GT
2958  || (cmp == DB_EQ
2959  && (arg2->info.expr.op == PT_BETWEEN_GE_LT || arg2->info.expr.op == PT_BETWEEN_GT_LE
2960  || arg2->info.expr.op == PT_BETWEEN_GT_LT)))
2961  {
2962  /* lower bound is greater than upper bound */
2963 
2964  location = node->info.expr.location; /* save location */
2965 
2966  if (location == 0)
2967  {
2968  /* empty conjuctive make whole condition always false */
2969  /* NOTICE: that is valid only when we handle one predicate terms in this function */
2970  parser_free_tree (parser, *wherep);
2971 
2972  /* make a single false node */
2973  node = parser_new_node (parser, PT_VALUE);
2974  if (node == NULL)
2975  {
2976  PT_INTERNAL_ERROR (parser, "allocate new node");
2977  return;
2978  }
2979 
2980  node->type_enum = PT_TYPE_LOGICAL;
2981  node->info.value.data_value.i = 0;
2982  node->info.value.location = location;
2983  (void) pt_value_to_db (parser, node);
2984  *wherep = node;
2985  }
2986  else
2987  {
2988  /* empty conjunctive is outer join ON condition. remove all nodes which have same location number */
2989  prev = NULL;
2990  node = *wherep;
2991  while (node)
2992  {
2993  if ((node->node_type == PT_EXPR && node->info.expr.location == location)
2994  || (node->node_type == PT_VALUE && node->info.value.location == location))
2995  {
2996  next = node->next;
2997  node->next = NULL;
2998  parser_free_tree (parser, node);
2999  if (prev)
3000  {
3001  prev->next = next;
3002  }
3003  else
3004  {
3005  *wherep = next;
3006  }
3007  node = next;
3008  }
3009  else
3010  {
3011  prev = node;
3012  node = node->next;
3013  }
3014  }
3015 
3016  /* make a single false node and append it to WHERE list */
3017  node = parser_new_node (parser, PT_VALUE);
3018  if (node == NULL)
3019  {
3020  PT_INTERNAL_ERROR (parser, "allocate new node");
3021  return;
3022  }
3023 
3024  node->type_enum = PT_TYPE_LOGICAL;
3025  node->info.value.data_value.i = 0;
3026  node->info.value.location = location;
3027  (void) pt_value_to_db (parser, node);
3028  node->next = *wherep;
3029  *wherep = node;
3030  }
3031 
3032  return;
3033  }
3034  }
3035  }
3036 }
3037 
3038 /*
3039  * pt_is_ascii_string_value_node () -
3040  * return: whether the node is a non-national string value (CHAR or VARCHAR)
3041  * node(in):
3042  */
3043 static bool
3045 {
3046  return (PT_IS_VALUE_NODE (node) && PT_IS_CHAR_STRING_TYPE (node->type_enum)
3048 }
3049 
3050 /*
3051  * pt_free_escape_char () - Frees the escape sequence of a PT_LIKE node and
3052  * leaves only the LIKE pattern in the parse tree.
3053  * parser(in):
3054  * like(in):
3055  * pattern(in):
3056  * escape(in):
3057  */
3058 static void
3059 pt_free_escape_char (PARSER_CONTEXT * const parser, PT_NODE * const like, PT_NODE * const pattern,
3060  PT_NODE * const escape)
3061 {
3062  PT_NODE *const save_arg2 = like->info.expr.arg2;
3063 
3064  assert (escape != NULL);
3066  assert (save_arg2->info.expr.arg1 == pattern);
3067  assert (save_arg2->info.expr.arg2 == escape);
3068 
3069  save_arg2->info.expr.arg1 = NULL;
3070  parser_free_tree (parser, save_arg2);
3071 
3072  like->info.expr.arg2 = pattern;
3073 }
3074 
3075 /*
3076  * qo_find_like_rewrite_bound () -
3077  * return: the lower or upper bound for the LIKE query rewrite (depending on
3078  * the value of the compute_lower_bound parameter), NULL on error.
3079  * See qo_rewrite_one_like_term for details.
3080  * parser(in):
3081  * pattern(in): the pattern tree node
3082  * pattern_str(in): a DB_VALUE of the string in the pattern argument
3083  * has_escape_char(in): whether the LIKE pattern can use an escape character
3084  * escape_str(in):if has_escape_char is true this is the escaping character
3085  * used in the pattern, otherwise the parameter has no
3086  * meaning and should have the value NULL
3087  * compute_lower_bound(in): whether to compute the lower or the upper bound
3088  * last_safe_logical_pos(in): the value returned by a
3089  * db_get_info_for_like_optimization call
3090  */
3091 static PT_NODE *
3092 qo_find_like_rewrite_bound (PARSER_CONTEXT * const parser, PT_NODE * const pattern, DB_VALUE * const pattern_str,
3093  const bool has_escape_char, const char *escape_str, const bool compute_lower_bound,
3094  const int last_safe_logical_pos)
3095 {
3096  int error_code = NO_ERROR;
3097  PT_NODE *bound;
3098  DB_VALUE tmp_result;
3099 
3100  db_make_null (&tmp_result);
3101 
3102  assert (parser != NULL);
3103  if (parser == NULL)
3104  {
3105  return NULL;
3106  }
3107 
3108  assert (has_escape_char ^ (escape_str == NULL));
3109 
3110  bound = parser_new_node (parser, PT_VALUE);
3111  if (bound == NULL)
3112  {
3113  PT_INTERNAL_ERROR (parser, "allocate new node");
3114  goto error_exit;
3115  }
3116 
3117  error_code =
3118  db_get_like_optimization_bounds (pattern_str, &tmp_result, has_escape_char, escape_str, compute_lower_bound,
3119  last_safe_logical_pos);
3120  if (error_code != NO_ERROR)
3121  {
3122  PT_INTERNAL_ERROR (parser, "db_get_like_optimization_bounds");
3123  goto error_exit;
3124  }
3125 
3126  bound->type_enum = pattern->type_enum;
3127  if (pattern->data_type != NULL)
3128  {
3129  bound->data_type = parser_copy_tree (parser, pattern->data_type);
3130  }
3131  bound->info.value.data_value.str =
3132  pt_append_bytes (parser, NULL, db_get_string (&tmp_result), db_get_string_size (&tmp_result));
3133  PT_NODE_PRINT_VALUE_TO_TEXT (parser, bound);
3134  (void) pt_value_to_db (parser, bound);
3135 
3137  assert (PT_HAS_COLLATION (pattern->type_enum));
3138 
3140  db_get_string_collation (&tmp_result));
3141 
3142  db_value_clear (&tmp_result);
3143  return bound;
3144 
3145 error_exit:
3146  if (bound != NULL)
3147  {
3148  parser_free_tree (parser, bound);
3149  }
3150 
3151  db_value_clear (&tmp_result);
3152  return NULL;
3153 }
3154 
3155 /*
3156  * qo_rewrite_one_like_term () - Convert a leftmost LIKE term to a BETWEEN
3157  * (GE_LT) term to increase the chance of using
3158  * an index.
3159  * parser(in):
3160  * like(in):
3161  * pattern(in):
3162  * escape(in):
3163  * perform_generic_rewrite(out): true if this function did not perform a
3164  * rewrite, but the expression will benefit
3165  * from the more generic rewrite performed by
3166  * qo_rewrite_like_for_index_scan
3167  *
3168  * Note: See the notes of the db_get_info_for_like_optimization function for
3169  * details on what rewrites can be performed.
3170  * This function will only be applied to pattern values known at
3171  * compile-time. It will only perform a rewrite if the LIKE predicate
3172  * can be fully expressed with other predicates (cases 1, 2 and 3.2
3173  * described in db_get_info_for_like_optimization).
3174  * If this function cannot perform the above rewrites, but the rewrite
3175  * of form 3.1 would benefit from an index scan
3176  */
3177 static void
3178 qo_rewrite_one_like_term (PARSER_CONTEXT * const parser, PT_NODE * const like, PT_NODE * const pattern,
3179  PT_NODE * const escape, bool * const perform_generic_rewrite)
3180 {
3181  int error_code = NO_ERROR;
3182  bool has_escape_char = false;
3183  const char *escape_str = NULL;
3184  const char *pattern_str = NULL;
3185  int pattern_size = 0;
3186  int pattern_length = 0;
3187  bool uses_escaping = false;
3188  int num_logical_chars = 0;
3189  int last_safe_logical_pos = 0;
3190  int num_match_many = 0;
3191  int num_match_one = 0;
3192  DB_VALUE compressed_pattern;
3193  int collation_id;
3194  INTL_CODESET codeset;
3195 
3196  db_make_null (&compressed_pattern);
3197 
3198  *perform_generic_rewrite = false;
3199 
3200  assert (pattern != NULL && parser != NULL);
3201  if (pattern == NULL || parser == NULL)
3202  {
3203  return;
3204  }
3205 
3207 
3208  collation_id = db_get_string_collation (&pattern->info.value.db_value);
3209  codeset = db_get_string_codeset (&pattern->info.value.db_value);
3210 
3211  if (escape != NULL)
3212  {
3213  if (PT_IS_NULL_NODE (escape))
3214  {
3215  has_escape_char = true;
3216  escape_str = "\\";
3217  }
3218  else
3219  {
3220  int esc_char_len = 0;
3221 
3223 
3224  escape_str = (const char *) escape->info.value.data_value.str->bytes;
3225  intl_char_count ((unsigned char *) escape_str, escape->info.value.data_value.str->length, codeset,
3226  &esc_char_len);
3227  if (esc_char_len != 1)
3228  {
3230  goto error_exit;
3231  }
3232  has_escape_char = true;
3233  }
3234  }
3236  {
3237  assert (escape == NULL);
3239  has_escape_char = true;
3240  escape_str = "\\";
3241  }
3242  else
3243  {
3244  has_escape_char = false;
3245  escape_str = NULL;
3246  }
3247 
3248  error_code =
3249  db_compress_like_pattern (&pattern->info.value.db_value, &compressed_pattern, has_escape_char, escape_str);
3250  if (error_code != NO_ERROR)
3251  {
3252  PT_INTERNAL_ERROR (parser, "db_compress_like_pattern");
3253  goto error_exit;
3254  }
3255 
3256  pattern->info.value.data_value.str =
3257  pt_append_bytes (parser, NULL, db_get_string (&compressed_pattern), db_get_string_size (&compressed_pattern));
3258  pattern_str = (char *) pattern->info.value.data_value.str->bytes;
3259  pattern_size = pattern->info.value.data_value.str->length;
3260  intl_char_count ((unsigned char *) pattern_str, pattern_size, codeset, &pattern_length);
3261  PT_NODE_PRINT_VALUE_TO_TEXT (parser, pattern);
3262 
3263  error_code =
3264  db_get_info_for_like_optimization (&compressed_pattern, has_escape_char, escape_str, &num_logical_chars,
3265  &last_safe_logical_pos, &num_match_many, &num_match_one);
3266  if (error_code != NO_ERROR)
3267  {
3268  PT_INTERNAL_ERROR (parser, "db_get_info_for_like_optimization");
3269  goto error_exit;
3270  }
3271 
3272  assert (pattern_length >= num_logical_chars);
3273  uses_escaping = (num_logical_chars != pattern_length);
3274 
3275  if (num_match_many == 0 && num_match_one == 0)
3276  {
3277  /* The pattern does not contain wildcards. */
3278 
3279  if (uses_escaping)
3280  {
3281  /* TODO also support this scenario by eliminating the no longer needed escape characters. When this is
3282  * implemented, we will no longer need to perform the generic rewrite. Rewriting to PT_EQ will result in
3283  * faster execution, so this specific rewrite is preferable. */
3284  *perform_generic_rewrite = true;
3285  goto fast_exit;
3286  }
3287 
3288  if (escape != NULL)
3289  {
3290  pt_free_escape_char (parser, like, pattern, escape);
3291  }
3292 
3293  if (pattern_length == 0)
3294  {
3295  /* Rewrite this term as equal predicate. */
3296  like->info.expr.op = PT_EQ;
3297  }
3298  else if (pattern_str[pattern_size - 1] == ' ')
3299  {
3300  /* If the rightmost character in the pattern is a space we cannot rewrite this term. */
3301  /* TODO It is not clear why this case is not handled. Clarify this issue and improve the comment. It is
3302  * possible that the index ordering of strings with trailing spaces is inconsistent with LIKE comparison
3303  * semantics. Another issue is that the successor of the space character should be the character with the
3304  * code 1 (as space is sorted before any other character) and character code 1 is (incorrectly) used as a
3305  * dummy escape character in qstr_eval_like when there is no other escape character given. */
3306  if (last_safe_logical_pos >= 0)
3307  {
3308  /* We can perform the generic rewrite as the string contains non-space characters. */
3309  *perform_generic_rewrite = true;
3310  }
3311  }
3312  else
3313  {
3314  /* Rewrite this term as equal predicate. */
3315  like->info.expr.op = PT_EQ;
3316  }
3317  goto fast_exit;
3318  }
3319 
3320  if (pattern_length == 1 && num_match_many == 1)
3321  {
3322  /* LIKE '%' predicate that matches any non-null string. */
3323  assert (num_logical_chars == 1);
3324  assert (pattern_str[0] == LIKE_WILDCARD_MATCH_MANY && pattern_str[1] == 0);
3325 
3326  /* We change the node to a IS NOT NULL node. */
3327  parser_free_tree (parser, like->info.expr.arg2);
3328  like->info.expr.arg2 = NULL;
3329  like->info.expr.op = PT_IS_NOT_NULL;
3330  goto fast_exit;
3331  }
3332 
3333  if (num_match_many == 1 && num_match_one == 0 && last_safe_logical_pos >= 0
3334  && last_safe_logical_pos == num_logical_chars - 2)
3335  {
3336  PT_NODE *lower = NULL;
3337  PT_NODE *upper = NULL;
3338  PT_NODE *between_and = NULL;
3339 
3340  assert (pattern_length >= 2 && pattern_str[pattern_size - 1] == LIKE_WILDCARD_MATCH_MANY);
3341 
3342  /* do not rewrite for collations with LIKE disabled optimization */
3343  if (!(lang_get_collation (collation_id)->options.allow_like_rewrite))
3344  {
3345  *perform_generic_rewrite = true;
3346  goto fast_exit;
3347  }
3348 
3349  between_and = pt_expression_2 (parser, PT_BETWEEN_GE_LT, NULL, NULL);
3350  if (between_and == NULL)
3351  {
3352  PT_INTERNAL_ERROR (parser, "allocate new node");
3353  goto error_exit;
3354  }
3355 
3356  between_and->type_enum = PT_TYPE_LOGICAL;
3357  between_and->info.expr.location = like->info.expr.location;
3358 
3359  lower =
3360  qo_find_like_rewrite_bound (parser, pattern, &compressed_pattern, has_escape_char, escape_str, true,
3361  last_safe_logical_pos);
3362  if (lower == NULL)
3363  {
3364  parser_free_tree (parser, between_and);
3365  between_and = NULL;
3366  goto error_exit;
3367  }
3368 
3369  between_and->info.expr.arg1 = lower;
3370 
3371  upper =
3372  qo_find_like_rewrite_bound (parser, pattern, &compressed_pattern, has_escape_char, escape_str, false,
3373  last_safe_logical_pos);
3374  if (upper == NULL)
3375  {
3376  parser_free_tree (parser, between_and);
3377  between_and = NULL;
3378  goto error_exit;
3379  }
3380 
3381  between_and->info.expr.arg2 = upper;
3382 
3383  /* We replace the LIKE node with a BETWEEN node. */
3384  like->info.expr.op = PT_BETWEEN;
3385  parser_free_tree (parser, like->info.expr.arg2);
3386  like->info.expr.arg2 = between_and;
3387  }
3388  else if (last_safe_logical_pos >= 0)
3389  {
3390  *perform_generic_rewrite = true;
3391  }
3392 
3393 fast_exit:
3394  db_value_clear (&compressed_pattern);
3395 
3396  return;
3397 
3398 error_exit:
3399  db_value_clear (&compressed_pattern);
3400 
3401  return;
3402 }
3403 
3404 static PT_NODE *
3405 qo_allocate_like_bound_for_index_scan (PARSER_CONTEXT * const parser, PT_NODE * const like, PT_NODE * const pattern,
3406  PT_NODE * const escape, const bool allocate_lower_bound)
3407 {
3408  PT_NODE *bound = NULL;
3409  PT_NODE *expr_pattern = NULL;
3410  PT_NODE *expr_escape = NULL;
3411 
3412  bound = pt_expression_2 (parser, allocate_lower_bound ? PT_LIKE_LOWER_BOUND : PT_LIKE_UPPER_BOUND, NULL, NULL);
3413  if (bound == NULL)
3414  {
3415  PT_INTERNAL_ERROR (parser, "allocate new node");
3416  goto error_exit;
3417  }
3418  bound->info.expr.location = like->info.expr.location;
3419 
3420  bound->type_enum = pattern->type_enum;
3421 
3422  expr_pattern = parser_copy_tree (parser, pattern);
3423  if (expr_pattern == NULL)
3424  {
3425  PT_INTERNAL_ERROR (parser, "allocate new node");
3426  goto error_exit;
3427  }
3428 
3429  bound->info.expr.arg1 = expr_pattern;
3430 
3432  {
3434  expr_escape = pt_make_string_value (parser, "\\");
3435  if (expr_escape == NULL)
3436  {
3437  PT_INTERNAL_ERROR (parser, "allocate new node");
3438  goto error_exit;
3439  }
3440  }
3441  else if (escape != NULL)
3442  {
3443  if (PT_IS_NULL_NODE (escape))
3444  {
3445  expr_escape = pt_make_string_value (parser, "\\");
3446  if (expr_escape == NULL)
3447  {
3448  PT_INTERNAL_ERROR (parser, "allocate new node");
3449  goto error_exit;
3450  }
3451  }
3452  else
3453  {
3454  expr_escape = parser_copy_tree (parser, escape);
3455  if (expr_escape == NULL)
3456  {
3457  PT_INTERNAL_ERROR (parser, "allocate new node");
3458  goto error_exit;
3459  }
3460  }
3461  }
3462  else
3463  {
3464  expr_escape = NULL;
3465  }
3466 
3467  bound->info.expr.arg2 = expr_escape;
3468 
3469  /* copy data type */
3470  assert (bound->data_type == NULL);
3471  bound->data_type = parser_copy_tree (parser, pattern->data_type);
3472 
3473  return bound;
3474 
3475 error_exit:
3476  if (bound != NULL)
3477  {
3478  parser_free_tree (parser, bound);
3479  }
3480  return NULL;
3481 }
3482 
3483 /*
3484  * qo_rewrite_like_for_index_scan ()
3485  * parser(in):
3486  * like(in):
3487  * pattern(in):
3488  * escape(in):
3489  *
3490  * Note: See the notes of the db_get_info_for_like_optimization function for
3491  * details on what rewrites can be performed. This function will always
3492  * rewrite to form 3.1.
3493  */
3494 static PT_NODE *
3495 qo_rewrite_like_for_index_scan (PARSER_CONTEXT * const parser, PT_NODE * like, PT_NODE * const pattern,
3496  PT_NODE * const escape)
3497 {
3498  PT_NODE *between = NULL;
3499  PT_NODE *between_and = NULL;
3500  PT_NODE *lower = NULL;
3501  PT_NODE *upper = NULL;
3502  PT_NODE *match_col = NULL;
3503  PT_NODE *like_save = NULL;
3504 
3505  between = pt_expression_1 (parser, PT_BETWEEN, NULL);
3506  if (between == NULL)
3507  {
3508  PT_INTERNAL_ERROR (parser, "allocate new node");
3509  goto error_exit;
3510  }
3511 
3512  between->type_enum = PT_TYPE_LOGICAL;
3513  between->info.expr.location = like->info.expr.location;
3514 
3515  match_col = parser_copy_tree (parser, like->info.expr.arg1);
3516  if (match_col == NULL)
3517  {
3518  PT_INTERNAL_ERROR (parser, "allocate new node");
3519  goto error_exit;
3520  }
3521 
3522  between->info.expr.arg1 = match_col;
3523 
3524  between_and = pt_expression_2 (parser, PT_BETWEEN_GE_LT, NULL, NULL);
3525  if (between_and == NULL)
3526  {
3527  PT_INTERNAL_ERROR (parser, "allocate new node");
3528  goto error_exit;
3529  }
3530 
3531  between->info.expr.arg2 = between_and;
3532 
3533  between_and->type_enum = PT_TYPE_LOGICAL;
3534  between_and->info.expr.location = like->info.expr.location;
3535 
3536  lower = qo_allocate_like_bound_for_index_scan (parser, like, pattern, escape, true);
3537  if (lower == NULL)
3538  {
3539  PT_INTERNAL_ERROR (parser, "allocate new node");
3540  goto error_exit;
3541  }
3542 
3543  between_and->info.expr.arg1 = lower;
3544 
3545  upper = qo_allocate_like_bound_for_index_scan (parser, like, pattern, escape, false);
3546  if (upper == NULL)
3547  {
3548  PT_INTERNAL_ERROR (parser, "allocate new node");
3549  goto error_exit;
3550  }
3551 
3552  between_and->info.expr.arg2 = upper;
3553 
3554  between->next = like->next;
3555  like->next = between;
3556 
3557  /* fold range bounds : this will allow auto-parametrization */
3558  like_save = parser_copy_tree_list (parser, like);
3559  if (like_save == NULL)
3560  {
3561  PT_INTERNAL_ERROR (parser, "allocate new node");
3562  goto error_exit;
3563  }
3564 
3565  /* if success, use like_save. Otherwise, keep like. */
3566  like_save = pt_semantic_type (parser, like_save, NULL);
3567 
3568  if (like_save == NULL || er_errid () != NO_ERROR || pt_has_error (parser))
3569  {
3570  like->next = between->next;
3571  between->next = NULL;
3572 
3573  /* clear error */
3574  if (er_errid () != NO_ERROR)
3575  {
3576  er_clear ();
3577  }
3578 
3579  if (pt_has_error (parser))
3580  {
3581  pt_reset_error (parser);
3582  }
3583  goto error_exit;
3584  }
3585 
3586  /* success: use like_save. */
3587  return like_save;
3588 
3589 error_exit:
3590  if (between != NULL)
3591  {
3592  parser_free_tree (parser, between);
3593  between = NULL;
3594  }
3595 
3596  if (like_save != NULL)
3597  {
3598  parser_free_tree (parser, like_save);
3599  }
3600 
3601  return like;
3602 }
3603 
3604 /*
3605  * qo_check_like_expression_pre - Checks to see if an expression is safe to
3606  * use in the LIKE rewrite optimization
3607  * performed by qo_rewrite_like_for_index_scan
3608  *
3609  * return:
3610  * parser(in):
3611  * node(in):
3612  * arg(in/out): A pointer to a bool value that represents whether the
3613  * expression is safe for the rewrite.
3614  * continue_walk(in/out):
3615  *
3616  * Note: Expressions are first filtered by the pt_is_pseudo_const function.
3617  * However, in addition to what that function considers a "constant"
3618  * for index scans, we also include PT_NAME and PT_DOT nodes and query
3619  * nodes. Some of them might be pseudo-constant and usable during the
3620  * index scan, but since we have no easy way to tell we prefer to
3621  * exclude them.
3622  */
3623 static PT_NODE *
3624 qo_check_like_expression_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
3625 {
3626  bool *const like_expression_not_safe = (bool *) arg;
3627 
3628  if (node == NULL)
3629  {
3630  return node;
3631  }
3632 
3633  if (PT_IS_QUERY (node) || PT_IS_NAME_NODE (node) || PT_IS_DOT_NODE (node))
3634  {
3635  *like_expression_not_safe = true;
3636  *continue_walk = PT_STOP_WALK;
3637  return node;
3638  }
3639 
3640  return node;
3641 }
3642 
3643 /*
3644  * qo_rewrite_like_terms ()
3645  * return:
3646  * parser(in):
3647  * cnf_list(in):
3648  */
3649 static void
3651 {
3652  PT_NODE *cnf_node = NULL;
3653  /* prev node in list which linked by next pointer. */
3654  PT_NODE *prev = NULL;
3655  /* prev node in list which linked by or_next pointer. */
3656  PT_NODE *or_prev = NULL;
3657 
3658  for (cnf_node = *cnf_list; cnf_node != NULL; cnf_node = cnf_node->next)
3659  {
3660  PT_NODE *crt_expr = NULL;
3661 
3662  or_prev = NULL;
3663  for (crt_expr = cnf_node; crt_expr != NULL; crt_expr = crt_expr->or_next)
3664  {
3665  PT_NODE *compared_expr = NULL;
3666  PT_NODE *pattern = NULL;
3667  PT_NODE *escape = NULL;
3668  PT_NODE *arg2 = NULL;
3669  bool perform_generic_rewrite = false;
3670  PT_TYPE_ENUM pattern_type, escape_type = PT_TYPE_NONE;
3671 
3672  if (!PT_IS_EXPR_NODE_WITH_OPERATOR (crt_expr, PT_LIKE))
3673  {
3674  /* TODO Investigate optimizing PT_NOT_LIKE expressions also. */
3675  continue;
3676  }
3677 
3678  compared_expr = pt_get_first_arg_ignore_prior (crt_expr);
3679  if (!pt_is_attr (compared_expr) && !pt_is_function_index_expr (parser, compared_expr, false))
3680  {
3681  /* LHS is not an attribute or an expression supported as function index so it cannot currently have an
3682  * index. The transformation could still be useful as it might provide faster execution time in some
3683  * scenarios. */
3684  continue;
3685  }
3686 
3687  arg2 = crt_expr->info.expr.arg2;
3689  {
3690  /* TODO LIKE handling might be easier if the parser saved the escape sequence in arg3 of the PT_LIKE
3691  * node. */
3692  pattern = arg2->info.expr.arg1;
3693  escape = arg2->info.expr.arg2;
3694  assert (escape != NULL);
3695  }
3696  else
3697  {
3698  pattern = arg2;
3699  escape = NULL;
3700  }
3701 
3702  pattern_type = pattern->type_enum;
3703 
3704  if (pattern_type == PT_TYPE_MAYBE && pattern->expected_domain)
3705  {
3706  pattern_type = pt_db_to_type_enum (TP_DOMAIN_TYPE (pattern->expected_domain));
3707  }
3708 
3709  if (escape != NULL)
3710  {
3711  escape_type = escape->type_enum;
3712  if (escape_type == PT_TYPE_MAYBE && escape->expected_domain)
3713  {
3714  escape_type = pt_db_to_type_enum (TP_DOMAIN_TYPE (escape->expected_domain));
3715  }
3716  }
3717 
3718  if (PT_IS_NATIONAL_CHAR_STRING_TYPE (pattern_type)
3719  || (escape != NULL && PT_IS_NATIONAL_CHAR_STRING_TYPE (escape_type)))
3720  {
3721  /* We disable LIKE optimizations on national character strings until the internationalization support in
3722  * CUBRID is better. The optimization logic for national character strings should be the same as the
3723  * current logic, but the existing functions would need to be extended to support correctly iterating
3724  * through national character strings. */
3725  continue;
3726  }
3727 
3728  if (pt_is_ascii_string_value_node (pattern)
3729  && (escape == NULL || PT_IS_NULL_NODE (escape) || pt_is_ascii_string_value_node (escape)))
3730  {
3731  qo_rewrite_one_like_term (parser, crt_expr, pattern, escape, &perform_generic_rewrite);
3732  if (!perform_generic_rewrite)
3733  {
3734  continue;
3735  }
3736  }
3737  if (crt_expr == cnf_node && crt_expr->or_next == NULL)
3738  {
3739  /* The LIKE predicate in CNF is not chained in an OR list, so we can easily split it into several
3740  * predicates chained with AND. Supporting the case: col LIKE expr1 OR predicate would make it difficult
3741  * to rewrite the query because we need to preserve the CNF. */
3742  /* TODO We should check that the column is indexed. Otherwise it might not be worth the effort to do this
3743  * rewrite. */
3744  if (pt_is_pseudo_const (pattern)
3745  && (escape == NULL || PT_IS_NULL_NODE (escape) || pt_is_pseudo_const (escape)))
3746  {
3747  bool like_expression_not_safe = false;
3748 
3749  (void *) parser_walk_tree (parser, pattern, qo_check_like_expression_pre, &like_expression_not_safe,
3750  NULL, NULL);
3751  if (like_expression_not_safe)
3752  {
3753  continue;
3754  }
3755  (void *) parser_walk_tree (parser, escape, qo_check_like_expression_pre, &like_expression_not_safe,
3756  NULL, NULL);
3757  if (like_expression_not_safe)
3758  {
3759  continue;
3760  }
3761  crt_expr = qo_rewrite_like_for_index_scan (parser, crt_expr, pattern, escape);
3762  /* rebuild link list. */
3763  if (or_prev != NULL)
3764  {
3765  or_prev->or_next = crt_expr;
3766  }
3767  else if (prev != NULL)
3768  {
3769  /* The first node in cnf_node */
3770  prev->next = crt_expr;
3771  cnf_node = crt_expr;
3772  }
3773  else
3774  {
3775  /* The first node in cnf_list */
3776  *cnf_list = crt_expr;
3777  cnf_node = crt_expr;
3778  }
3779 
3780 
3781  }
3782  }
3783  or_prev = crt_expr;
3784  }
3785  prev = cnf_node;
3786  }
3787 }
3788 
3789 /*
3790  * qo_set_value_to_range_list () -
3791  * return:
3792  * parser(in):
3793  * node(in):
3794  */
3795 static PT_NODE *
3797 {
3798  PT_NODE *set_val, *list, *last, *range;
3799 
3800  list = last = NULL;
3801  if (node->node_type == PT_VALUE)
3802  {
3803  set_val = node->info.value.data_value.set;
3804  }
3805  else if (node->node_type == PT_FUNCTION)
3806  {
3807  set_val = node->info.function.arg_list;
3808  }
3809  else if (node->node_type == PT_NAME && !PT_IS_COLLECTION_TYPE (node->type_enum))
3810  {
3811  set_val = node;
3812  }
3813  else
3814  {
3815  set_val = NULL;
3816  }
3817 
3818  while (set_val)
3819  {
3820  range = parser_new_node (parser, PT_EXPR);
3821  if (!range)
3822  goto error;
3823  range->type_enum = PT_TYPE_LOGICAL;
3824  range->info.expr.op = PT_BETWEEN_EQ_NA;
3825  range->info.expr.arg1 = parser_copy_tree (parser, set_val);
3826  range->info.expr.arg2 = NULL;
3827  range->info.expr.location = set_val->info.expr.location;
3828 #if defined(CUBRID_DEBUG)
3829  range->next = NULL;
3830  range->or_next = NULL;
3831 #endif /* CUBRID_DEBUG */
3832  if (last)
3833  {
3834  last->or_next = range;
3835  }
3836  else
3837  {
3838  list = range;
3839  }
3840  last = range;
3841  set_val = set_val->next;
3842  }
3843 
3844  return list;
3845 
3846 error:
3847  if (list)
3848  parser_free_tree (parser, list);
3849  return NULL;
3850 }
3851 
3852 
3853 /*
3854  * qo_convert_to_range_helper () -
3855  * return:
3856  * parser(in):
3857  * node(in):
3858  */
3859 static void
3861 {
3862  PT_NODE *between_and, *sibling, *last, *prev, *in_arg2;
3863  PT_OP_TYPE op_type;
3864  PT_NODE *node_prior = NULL;
3865  PT_NODE *sibling_prior = NULL;
3866 
3867  assert (PT_IS_EXPR_NODE (node));
3868  node_prior = pt_get_first_arg_ignore_prior (node);
3869 
3870  assert (node_prior != NULL);
3871  if (node_prior == NULL)
3872  {
3873  return;
3874  }
3875 
3876  /* convert the given node to RANGE node */
3877 
3878  /* construct BETWEEN_AND node as arg2(RHS) of RANGE node */
3879  op_type = node->info.expr.op;
3880  switch (op_type)
3881  {
3882  case PT_EQ:
3883  between_and = parser_new_node (parser, PT_EXPR);
3884  if (!between_and)
3885  {
3886  return; /* error; stop converting */
3887  }
3888  between_and->type_enum = PT_TYPE_LOGICAL;
3889  between_and->info.expr.op = PT_BETWEEN_EQ_NA;
3890  between_and->info.expr.arg1 = node->info.expr.arg2;
3891  between_and->info.expr.arg2 = NULL;
3892  between_and->info.expr.location = node->info.expr.location;
3893 #if defined(CUBRID_DEBUG)
3894  between_and->next = NULL;
3895  between_and->or_next = NULL;
3896 #endif /* CUBRID_DEBUG */
3897  break;
3898  case PT_GT:
3899  case PT_GE:
3900  case PT_LT:
3901  case PT_LE:
3902  between_and = parser_new_node (parser, PT_EXPR);
3903  if (!between_and)
3904  {
3905  return; /* error; stop converting */
3906  }
3907  between_and->type_enum = PT_TYPE_LOGICAL;
3908  if (op_type == PT_GT)
3909  {
3910  between_and->info.expr.op = PT_BETWEEN_GT_INF;
3911  }
3912  else if (op_type == PT_GE)
3913  {
3914  between_and->info.expr.op = PT_BETWEEN_GE_INF;
3915  }
3916  else if (op_type == PT_LT)
3917  {
3918  between_and->info.expr.op = PT_BETWEEN_INF_LT;
3919  }
3920  else
3921  {
3922  between_and->info.expr.op = PT_BETWEEN_INF_LE;
3923  }
3924 
3925  between_and->info.expr.arg1 = node->info.expr.arg2;
3926  between_and->info.expr.arg2 = NULL;
3927  between_and->info.expr.location = node->info.expr.location;
3928 #if defined(CUBRID_DEBUG)
3929  between_and->next = NULL;
3930  between_and->or_next = NULL;
3931 #endif
3932  break;
3933  case PT_BETWEEN:
3934  between_and = node->info.expr.arg2;
3935  assert (between_and->node_type == PT_EXPR);
3936  /* replace PT_BETWEEN_AND with PT_BETWEEN_GE_LE */
3937  if (between_and->info.expr.op == PT_BETWEEN_AND)
3938  {
3939  between_and->info.expr.op = PT_BETWEEN_GE_LE;
3940  }
3941  break;
3942  case PT_IS_IN:
3943  in_arg2 = node->info.expr.arg2;
3945  || !PT_IS_COLLECTION_TYPE (in_arg2->type_enum))
3946  {
3947  /* subquery cannot be converted to RANGE */
3948  return;
3949  }
3950  between_and = qo_set_value_to_range_list (parser, in_arg2);
3951  if (!between_and)
3952  {
3953  return; /* error; stop converting */
3954  }
3955  /* free the converted set value node, which is the operand of IN */
3956  parser_free_tree (parser, in_arg2);
3957  break;
3958  case PT_RANGE:
3959  /* already converted. do nothing */
3960  return;
3961  default:
3962  /* unsupported operator; only PT_EQ, PT_GT, PT_GE, PT_LT, PT_LE, and PT_BETWEEN can be converted to RANGE */
3963  return; /* error; stop converting */
3964  }
3965 #if 0
3966  between_and->next = between_and->or_next = NULL;
3967 #endif
3968  /* change the node to RANGE */
3969  node->info.expr.op = PT_RANGE;
3970  node->info.expr.arg2 = last = between_and;
3971  while (last->or_next)
3972  {
3973  last = last->or_next;
3974  }
3975 
3976 
3977  /* link all nodes in the list whose LHS is the same attribute with the RANGE node */
3978 
3979  /* search DNF list from the next to the node and keep track of the pointer to previous node */
3980  prev = node;
3981  while ((sibling = prev->or_next))
3982  {
3983  if (sibling->node_type != PT_EXPR)
3984  {
3985  /* sibling is not an expression node */
3986  prev = prev->or_next;
3987  continue;
3988  }
3989 
3990  sibling_prior = pt_get_first_arg_ignore_prior (sibling);
3991  if (PT_IS_EXPR_WITH_PRIOR_ARG (sibling))
3992  {
3993  if (!PT_IS_EXPR_WITH_PRIOR_ARG (node))
3994  {
3995  /* sibling has prior, node hasn't */
3996  prev = prev->or_next;
3997  continue;
3998  }
3999  }
4000  else
4001  {
4002  if (PT_IS_EXPR_WITH_PRIOR_ARG (node))
4003  {
4004  /* sibling hasn't prior, node has */
4005  prev = prev->or_next;
4006  continue;
4007  }
4008  }
4009  /* if node had prior check that sibling also contains prior and vice-versa */
4010 
4011  if (!pt_is_attr (sibling_prior) && !pt_is_instnum (sibling_prior))
4012  {
4013  /* LHS is not an attribute */
4014  prev = prev->or_next;
4015  continue;
4016  }
4017 
4018  if ((node_prior->node_type != sibling_prior->node_type)
4019  || (pt_is_attr (node_prior) && pt_is_attr (sibling_prior)
4020  && pt_check_path_eq (parser, node_prior, sibling_prior)))
4021  {
4022  /* pt_check_path_eq() return non-zero if two are different */
4023  prev = prev->or_next;
4024  continue;
4025  }
4026 
4027  /* found a node of the same attribute */
4028 
4029  /* construct BETWEEN_AND node as the tail of RANGE node's range list */
4030  op_type = sibling->info.expr.op;
4031  switch (op_type)
4032  {
4033  case PT_EQ:
4034  between_and = parser_new_node (parser, PT_EXPR);
4035  if (!between_and)
4036  {
4037  return; /* error; stop converting */
4038  }
4039  between_and->type_enum = PT_TYPE_LOGICAL;
4040  between_and->info.expr.op = PT_BETWEEN_EQ_NA;
4041  between_and->info.expr.arg1 = sibling->info.expr.arg2;
4042  between_and->info.expr.arg2 = NULL;
4043  between_and->info.expr.location = sibling->info.expr.location;
4044 #if defined(CUBRID_DEBUG)
4045  between_and->next = NULL;
4046  between_and->or_next = NULL;
4047 #endif /* CUBRID_DEBUG */
4048  break;
4049  case PT_GT:
4050  case PT_GE:
4051  case PT_LT:
4052  case PT_LE:
4053  between_and = parser_new_node (parser, PT_EXPR);
4054  if (!between_and)
4055  {
4056  return; /* error; stop converting */
4057  }
4058  between_and->type_enum = PT_TYPE_LOGICAL;
4059  if (op_type == PT_GT)
4060  {
4061  between_and->info.expr.op = PT_BETWEEN_GT_INF;
4062  }
4063  else if (op_type == PT_GE)
4064  {
4065  between_and->info.expr.op = PT_BETWEEN_GE_INF;
4066  }
4067  else if (op_type == PT_LT)
4068  {
4069  between_and->info.expr.op = PT_BETWEEN_INF_LT;
4070  }
4071  else
4072  {
4073  between_and->info.expr.op = PT_BETWEEN_INF_LE;
4074  }
4075  between_and->info.expr.arg1 = sibling->info.expr.arg2;
4076  between_and->info.expr.arg2 = NULL;
4077  between_and->info.expr.location = sibling->info.expr.location;
4078 #if defined(CUBRID_DEBUG)
4079  between_and->next = NULL;
4080  between_and->or_next = NULL;
4081 #endif
4082  break;
4083  case PT_BETWEEN:
4084  between_and = sibling->info.expr.arg2;
4085  assert (between_and->node_type == PT_EXPR);
4086  /* replace PT_BETWEEN_AND with PT_BETWEEN_GE_LE */
4087  if (between_and->info.expr.op == PT_BETWEEN_AND)
4088  {
4089  between_and->info.expr.op = PT_BETWEEN_GE_LE;
4090  }
4091  break;
4092  case PT_IS_IN:
4093  in_arg2 = sibling->info.expr.arg2;
4094  if (PT_IS_COLLECTION_TYPE (sibling->type_enum) || PT_IS_QUERY_NODE_TYPE (in_arg2->node_type)
4095  || !PT_IS_COLLECTION_TYPE (in_arg2->type_enum))
4096  {
4097  /* subquery cannot be converted to RANGE */
4098  prev = prev->or_next;
4099  continue;
4100  }
4101  between_and = qo_set_value_to_range_list (parser, in_arg2);
4102  if (!between_and)
4103  {
4104  prev = prev->or_next;
4105  continue;
4106  }
4107  /* free the converted set value node, which is the operand of IN */
4108  parser_free_tree (parser, in_arg2);
4109  break;
4110  default:
4111  /* unsupported operator; continue to next node */
4112  prev = prev->or_next;
4113  continue;
4114  } /* switch (op_type) */
4115 #if 0
4116  between_and->next = between_and->or_next = NULL;
4117 #endif
4118  /* append to the range list */
4119  last->or_next = between_and;
4120  last = between_and;
4121  while (last->or_next)
4122  {
4123  last = last->or_next;
4124  }
4125 
4126  /* delete the node and its arg1(LHS), and adjust linked list */
4127  prev->or_next = sibling->or_next;
4128  sibling->next = sibling->or_next = NULL;
4129  sibling->info.expr.arg2 = NULL; /* parser_free_tree() will handle 'arg1' */
4130  parser_free_tree (parser, sibling);
4131  }
4132 }
4133 
4134 /*
4135  * qo_compare_dbvalue_with_optype () - compare two DB_VALUEs specified
4136  * by range operator
4137  * return:
4138  * val1(in):
4139  * op1(in):
4140  * val2(in):
4141  * op2(in):
4142  */
4145 {
4147 
4148  switch (op1)
4149  {
4150  case PT_EQ:
4151  case PT_GE:
4152  case PT_GT:
4153  case PT_LT:
4154  case PT_LE:
4155  case PT_GT_INF:
4156  case PT_LT_INF:
4157  break;
4158  default:
4159  return CompResultError;
4160  }
4161  switch (op2)
4162  {
4163  case PT_EQ:
4164  case PT_GE:
4165  case PT_GT:
4166  case PT_LT:
4167  case PT_LE:
4168  case PT_GT_INF:
4169  case PT_LT_INF:
4170  break;
4171  default:
4172  return CompResultError;
4173  }
4174 
4175  if (op1 == PT_GT_INF) /* val1 is -INF */
4176  {
4177  return (op1 == op2) ? CompResultEqual : CompResultLess;
4178  }
4179  if (op1 == PT_LT_INF) /* val1 is +INF */
4180  {
4181  return (op1 == op2) ? CompResultEqual : CompResultGreater;
4182  }
4183  if (op2 == PT_GT_INF) /* val2 is -INF */
4184  {
4185  return (op2 == op1) ? CompResultEqual : CompResultGreater;
4186  }
4187  if (op2 == PT_LT_INF) /* va2 is +INF */
4188  {
4189  return (op2 == op1) ? CompResultEqual : CompResultLess;
4190  }
4191 
4192  rc = tp_value_compare (val1, val2, 1, 1);
4193  if (rc == DB_EQ)
4194  {
4195  /* (val1, op1) == (val2, op2) */
4196  if (op1 == op2)
4197  {
4198  return CompResultEqual;
4199  }
4200  if (op1 == PT_EQ || op1 == PT_GE || op1 == PT_LE)
4201  {
4202  if (op2 == PT_EQ || op2 == PT_GE || op2 == PT_LE)
4203  {
4204  return CompResultEqual;
4205  }
4206  return (op2 == PT_GT) ? CompResultLessAdj : CompResultGreaterAdj;
4207  }
4208  if (op1 == PT_GT)
4209  {
4210  if (op2 == PT_EQ || op2 == PT_GE || op2 == PT_LE)
4211  {
4212  return CompResultGreaterAdj;
4213  }
4214  return (op2 == PT_LT) ? CompResultGreater : CompResultEqual;
4215  }
4216  if (op1 == PT_LT)
4217  {
4218  if (op2 == PT_EQ || op2 == PT_GE || op2 == PT_LE)
4219  {
4220  return CompResultLessAdj;
4221  }
4222  return (op2 == PT_GT) ? CompResultLess : CompResultEqual;
4223  }
4224  }
4225  else if (rc == DB_LT)
4226  {
4227  /* (val1, op1) < (val2, op2) */
4228  return CompResultLess;
4229  }
4230  else if (rc == DB_GT)
4231  {
4232  /* (val1, op1) > (val2, op2) */
4233  return CompResultGreater;
4234  }
4235 
4236  /* tp_value_compare() returned error? */
4237  return CompResultError;
4238 }
4239 
4240 /*
4241  * qo_range_optype_rank () -
4242  * return:
4243  * op(in):
4244  * description:
4245  * a, x = 1
4246  * b, x < 1
4247  * c, x <= 1
4248  * apparently, the rank: a < b < c
4249  */
4250 static int
4252 {
4253  switch (op)
4254  {
4255  case PT_EQ:
4256  return 1;
4257  case PT_GT:
4258  case PT_LT:
4259  return 2;
4260  case PT_GE:
4261  case PT_LE:
4262  return 3;
4263  case PT_GT_INF:
4264  case PT_LT_INF:
4265  return 4;
4266  default:
4267  assert (false);
4268  return 1;
4269  }
4270  return 1;
4271 }
4272 
4273 /*
4274  * qo_merge_range_helper () -
4275  * return: valid, always false or always true
4276  * parser(in):
4277  * node(in):
4278  */
4281 {
4282  PT_NODE *range, *sibling, *current, *prev = NULL;
4283  PT_OP_TYPE r_op, r_lop, r_uop, s_op, s_lop, s_uop;
4284  DB_VALUE *r_lv, *r_uv, *s_lv, *s_uv;
4285  bool r_lv_copied = false, r_uv_copied = false;
4286  COMP_DBVALUE_WITH_OPTYPE_RESULT cmp1, cmp2, cmp3, cmp4, cmp5, cmp6;
4287  bool need_to_determine_upper_bound;
4288 
4289  int r_rank;
4290  int s_rank;
4291 
4292  if (node->info.expr.arg2->or_next == NULL)
4293  {
4294  /* one range spec; nothing to merge */
4295  return DNF_RANGE_VALID;
4296  }
4297 
4298  r_lv = r_uv = s_lv = s_uv = NULL;
4299  current = NULL;
4300  range = node->info.expr.arg2;
4301  prev = NULL;
4302  while (range)
4303  {
4304  if (!pt_is_const_not_hostvar (range->info.expr.arg1)
4305  || (range->info.expr.arg2 && !pt_is_const_not_hostvar (range->info.expr.arg2)))
4306  {
4307  /* not constant; cannot be merged */
4308  prev = range;
4309  range = range->or_next;
4310  continue;
4311  }
4312 
4313  r_op = range->info.expr.op;
4314  if (pt_between_to_comp_op (r_op, &r_lop, &r_uop) != 0)
4315  {
4316  /* something wrong; continue to next range spec */
4317  prev = range;
4318  range = range->or_next;
4319  continue;
4320  }
4321 
4322  /* search DNF list from the next to the node and keep track of the pointer to previous node */
4323  current = range;
4324  while ((sibling = current->or_next))
4325  {
4326  if (!pt_is_const_not_hostvar (sibling->info.expr.arg1)
4327  || (sibling->info.expr.arg2 && !pt_is_const_not_hostvar (sibling->info.expr.arg2)))
4328  {
4329  /* not constant; cannot be merged */
4330  current = current->or_next;
4331  continue;
4332  }
4333 
4334  s_op = sibling->info.expr.op;
4335  if (pt_between_to_comp_op (s_op, &s_lop, &s_uop) != 0)
4336  {
4337  /* something wrong; continue to next range spec */
4338  current = current->or_next;
4339  continue;
4340  }
4341 
4342  if (r_lop == PT_GT_INF)
4343  {
4344  /* PT_BETWEEN_INF_LE or PT_BETWEEN_INF_LT */
4345  if (r_lv_copied && r_lv)
4346  {
4347  pr_free_value (r_lv);
4348  r_lv_copied = false;
4349  }
4350  if (r_uv_copied && r_uv)
4351  {
4352  pr_free_value (r_uv);
4353  r_uv_copied = false;
4354  }
4355  r_lv = NULL;
4356  r_uv = pt_value_to_db (parser, range->info.expr.arg1);
4357  }
4358  else if (r_uop == PT_LT_INF)
4359  {
4360  /* PT_BETWEEN_GE_INF or PT_BETWEEN_GT_INF */
4361  if (r_lv_copied && r_lv)
4362  {
4363  pr_free_value (r_lv);
4364  r_lv_copied = false;
4365  }
4366  if (r_uv_copied && r_uv)
4367  {
4368  pr_free_value (r_uv);
4369  r_uv_copied = false;
4370  }
4371  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
4372  r_uv = NULL;
4373  }
4374  else if (r_lop == PT_EQ)
4375  {
4376  /* PT_BETWEEN_EQ_NA */
4377  if (r_lv_copied && r_lv)
4378  {
4379  pr_free_value (r_lv);
4380  r_lv_copied = false;
4381  }
4382  if (r_uv_copied && r_uv)
4383  {
4384  pr_free_value (r_uv);
4385  r_uv_copied = false;
4386  }
4387  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
4388  r_uv = r_lv;
4389  }
4390  else
4391  {
4392  /* PT_BETWEEN_GE_LE, PT_BETWEEN_GE_LT, PT_BETWEEN_GT_LE, or PT_BETWEEN_GT_LT */
4393  if (r_lv_copied && r_lv)
4394  {
4395  pr_free_value (r_lv);
4396  r_lv_copied = false;
4397  }
4398  if (r_uv_copied && r_uv)
4399  {
4400  pr_free_value (r_uv);
4401  r_uv_copied = false;
4402  }
4403  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
4404  r_uv = pt_value_to_db (parser, range->info.expr.arg2);
4405  }
4406 
4407  if (s_lop == PT_GT_INF)
4408  {
4409  /* PT_BETWEEN_INF_LE or PT_BETWEEN_INF_LT */
4410  s_lv = NULL;
4411  s_uv = pt_value_to_db (parser, sibling->info.expr.arg1);
4412  }
4413  else if (s_uop == PT_LT_INF)
4414  {
4415  /* PT_BETWEEN_GE_INF or PT_BETWEEN_GT_INF */
4416  s_lv = pt_value_to_db (parser, sibling->info.expr.arg1);
4417  s_uv = NULL;
4418  }
4419  else if (s_lop == PT_EQ)
4420  {
4421  /* PT_BETWEEN_EQ_NA */
4422  s_lv = pt_value_to_db (parser, sibling->info.expr.arg1);
4423  s_uv = s_lv;
4424  }
4425  else
4426  {
4427  /* PT_BETWEEN_GE_LE, PT_BETWEEN_GE_LT, PT_BETWEEN_GT_LE, or PT_BETWEEN_GT_LT */
4428  s_lv = pt_value_to_db (parser, sibling->info.expr.arg1);
4429  s_uv = pt_value_to_db (parser, sibling->info.expr.arg2);
4430  }
4431 
4433  /* check if the two range specs are mergable */
4434  cmp1 = qo_compare_dbvalue_with_optype (r_lv, r_lop, s_lv, s_lop);
4435  cmp2 = qo_compare_dbvalue_with_optype (r_lv, r_lop, s_uv, s_uop);
4436  cmp3 = qo_compare_dbvalue_with_optype (r_uv, r_uop, s_lv, s_lop);
4437  cmp4 = qo_compare_dbvalue_with_optype (r_uv, r_uop, s_uv, s_uop);
4438 
4439  /* make more compare to detect something like "a>1 or a between 1 and 0" */
4440  cmp5 = qo_compare_dbvalue_with_optype (r_lv, r_lop, r_uv, r_uop);
4441  cmp6 = qo_compare_dbvalue_with_optype (s_lv, s_lop, s_uv, s_uop);
4442 
4443  if (cmp1 == CompResultError || cmp2 == CompResultError || cmp3 == CompResultError || cmp4 == CompResultError)
4444  {
4445  /* somthine wrong; continue to next range spec */
4446  current = current->or_next;
4447  continue;
4448  }
4449  if (((cmp1 == CompResultLess || cmp1 == CompResultGreater) && cmp1 == cmp2 && cmp1 == cmp3 && cmp1 == cmp4)
4450  || cmp5 == CompResultGreater || cmp6 == CompResultGreater)
4451  {
4452  /* they are disjoint; continue to next range spec */
4453  current = current->or_next;
4454  continue;
4455  }
4456 
4457  /* merge the two range specs */
4458  /* swap arg1 and arg2 if op type is INF_LT or INF_LE to make easy the following merge algorithm */
4459  if (r_op == PT_BETWEEN_INF_LT || r_op == PT_BETWEEN_INF_LE)
4460  {
4461  range->info.expr.arg2 = range->info.expr.arg1;
4462  range->info.expr.arg1 = NULL;
4463  }
4464  if (s_op == PT_BETWEEN_INF_LT || s_op == PT_BETWEEN_INF_LE)
4465  {
4466  sibling->info.expr.arg2 = sibling->info.expr.arg1;
4467  sibling->info.expr.arg1 = NULL;
4468  }
4469  /* determine the lower bound of the merged range spec */
4470  need_to_determine_upper_bound = true;
4471  if (cmp1 == CompResultGreaterAdj || cmp1 == CompResultGreater)
4472  {
4473  parser_free_tree (parser, range->info.expr.arg1);
4474  if (s_op == PT_BETWEEN_EQ_NA)
4475  {
4476  range->info.expr.arg1 = parser_copy_tree (parser, sibling->info.expr.arg1);
4477  }
4478  else
4479  {
4480  range->info.expr.arg1 = sibling->info.expr.arg1;
4481  }
4482  r_lop = s_lop;
4483  if (r_lv_copied && r_lv)
4484  {
4485  pr_free_value (r_lv);
4486  r_lv_copied = false;
4487  }
4488  if (s_lv)
4489  {
4490  r_lv = pr_copy_value (s_lv);
4491  r_lv_copied = true;
4492  }
4493  else
4494  {
4495  r_lv = s_lv;
4496  }
4497 
4498  sibling->info.expr.arg1 = NULL;
4499  if (r_op == PT_BETWEEN_EQ_NA)
4500  { /* PT_BETWEEN_EQ_NA */
4501  parser_free_tree (parser, range->info.expr.arg2);
4502  if (s_op == PT_BETWEEN_EQ_NA)
4503  {
4504  range->info.expr.arg2 = parser_copy_tree (parser, sibling->info.expr.arg1);
4505  }
4506  else
4507  {
4508  range->info.expr.arg2 = sibling->info.expr.arg2;
4509  }
4510  sibling->info.expr.arg2 = NULL;
4511  r_uop = PT_LE;
4512  need_to_determine_upper_bound = false;
4513  }
4514 
4515  if (r_lop == PT_EQ)
4516  { /* PT_BETWEEN_EQ_NA */
4517  r_lop = PT_GE;
4518  }
4519  }
4520  else if (cmp1 == CompResultEqual)
4521  {
4522  /* There are two groups to reach here. 1. Both operators are identical(EQ, GE, LE, GT_INF, LT_INF) 2.
4523  * non-identical operators combination among (EQ, GE, LE). GE for (EQ-GE), GE of (GE-EQ), LE for
4524  * (EQ-LE), LE for (LE-EQ) */
4525  r_rank = qo_range_optype_rank (r_lop);
4526  s_rank = qo_range_optype_rank (s_lop);
4527 
4528  if (r_rank < s_rank)
4529  {
4530  r_lop = s_lop;
4531  }
4532  }
4533 
4534  /* determine the upper bound of the merged range spec */
4535  if (cmp4 == CompResultLess || cmp4 == CompResultLessAdj)
4536  {
4537  if (need_to_determine_upper_bound == true)
4538  {
4539  parser_free_tree (parser, range->info.expr.arg2);
4540  if (s_op == PT_BETWEEN_EQ_NA)
4541  {
4542  range->info.expr.arg2 = parser_copy_tree (parser, sibling->info.expr.arg1);
4543  }
4544  else
4545  {
4546  range->info.expr.arg2 = sibling->info.expr.arg2;
4547  }
4548  sibling->info.expr.arg2 = NULL;
4549  }
4550  r_uop = s_uop;
4551  if (r_uv_copied && r_uv)
4552  {
4553  pr_free_value (r_uv);
4554  r_uv_copied = false;
4555  }
4556  if (s_uv)
4557  {
4558  r_uv = pr_copy_value (s_uv);
4559  r_uv_copied = true;
4560  }
4561  else
4562  {
4563  r_uv = s_uv;
4564  }
4565 
4566  if (r_uop == PT_EQ)
4567  { /* PT_BETWEEN_EQ_NA */
4568  r_uop = PT_LE;
4569  }
4570  }
4571  else if (cmp4 == CompResultEqual)
4572  {
4573  /* There are two groups to reach here. 1. Both operators are identical(EQ, GE, LE, GT_INF, LT_INF) 2.
4574  * non-identical operators combination among (EQ, GE, LE). GE for (EQ-GE), GE of (GE-EQ), LE for
4575  * (EQ-LE), LE for (LE-EQ) */
4576  r_rank = qo_range_optype_rank (r_uop);
4577  s_rank = qo_range_optype_rank (s_uop);
4578 
4579  if (r_rank < s_rank)
4580  {
4581  r_uop = s_uop;
4582  }
4583  }
4584 
4585  /* determine the new range type */
4586  if (pt_comp_to_between_op (r_lop, r_uop, PT_RANGE_MERGE, &r_op) != 0)
4587  {
4588  /* the merge result is unbound range spec, INF_INF; this means that this RANGE node is always true and
4589  * meaningless */
4590  return DNF_RANGE_ALWAYS_TRUE;
4591  }
4592  /* check if the range is invalid, that is, lower bound is greater than upper bound */
4593  cmp1 = qo_compare_dbvalue_with_optype (r_lv, r_lop, r_uv, r_uop);
4594  if (cmp1 == CompResultGreaterAdj || cmp1 == CompResultGreater)
4595  {
4596  /* this is always false */
4597  r_op = (PT_OP_TYPE) 0;
4598  }
4599  else if (cmp1 == CompResultEqual)
4600  {
4601  if (r_op == PT_BETWEEN_GE_LE)
4602  { /* convert to PT_EQ */
4603  r_lop = r_uop = PT_EQ;
4604 
4605  r_op = PT_BETWEEN_EQ_NA;
4606  parser_free_tree (parser, range->info.expr.arg2);
4607  range->info.expr.arg2 = NULL;
4608  }
4609  }
4610 
4611  range->info.expr.op = r_op;
4612  /* recover arg1 and arg2 for the type of INF_LT and INF_LE */
4613  if (r_op == PT_BETWEEN_INF_LT || r_op == PT_BETWEEN_INF_LE)
4614  {
4615  range->info.expr.arg1 = range->info.expr.arg2;
4616  range->info.expr.arg2 = NULL;
4617  }
4618  /* no need to recover the sibling because it is to be deleted */
4619 
4620  /* delete the sibling node and adjust linked list */
4621  current->or_next = sibling->or_next;
4622  sibling->next = sibling->or_next = NULL;
4623  parser_free_tree (parser, sibling);
4624 
4625  if (r_op == 0)
4626  {
4627  /* We determined that this range is always false. If we successfully merged all ranges in this DNF and
4628  * the final result is false, we can return false. If we haven't reached the end yet or we found disjoint
4629  * ranges along the way, we need to remove this node from the DNF. */
4630  if (prev == NULL && range->or_next == NULL)
4631  {
4632  return DNF_RANGE_ALWAYS_FALSE;
4633  }
4634  current = range->or_next;
4635  range->or_next = NULL;
4636  parser_free_tree (parser, range);
4637  range = current;
4638  if (prev == NULL)
4639  {
4640  /* first node */
4641  node->info.expr.arg2 = range;
4642  range = NULL;
4643  }
4644  else
4645  {
4646  prev->or_next = range;
4647  /* go to next node */
4648  range = prev;
4649  }
4650  /* no sense in handling siblings since current range was invalidated */
4651  break;
4652  }
4653 
4654  /* with merged range, search DNF list from the next to the node and keep track of the pointer to previous
4655  * node */
4656  current = range;
4657  }
4658  if (range == NULL)
4659  {
4660  range = node->info.expr.arg2;
4661  }
4662  else
4663  {
4664  prev = range;
4665  range = range->or_next;
4666  }
4667  }
4668 
4669  if (r_lv_copied && r_lv)
4670  {
4671  pr_free_value (r_lv);
4672  }
4673  if (r_uv_copied && r_uv)
4674  {
4675  pr_free_value (r_uv);
4676  }
4677 
4678  for (range = node->info.expr.arg2; range; range = range->or_next)
4679  {
4680  if (range->info.expr.op == PT_BETWEEN_EQ_NA && range->info.expr.arg2 != NULL)
4681  {
4682  parser_free_tree (parser, range->info.expr.arg2);
4683  range->info.expr.arg2 = NULL;
4684  }
4685  }
4686  return DNF_RANGE_VALID;
4687 }
4688 
4689 /*
4690  * qo_convert_to_range () - Convert comparison term to RANGE term
4691  * return:
4692  * parser(in):
4693  * wherep(in): pointer to WHERE list
4694  *
4695  * Note:
4696  * examples:
4697  * 1. WHERE a<=20 AND a=>10 --> WHERE a RANGE(10 GE_LE 20)
4698  * 2. WHERE a<10 --> WHERE a RANGE(10 INF_LT)
4699  * 3. WHERE a>=20 --> WHERE a RANGE(20 GE_INF)
4700  * 4. WHERE a<10 OR a>=20 --> WHERE a RANGE(10 INF_LT, 20 GE_INF)
4701  */
4702 static void
4704 {
4705  PT_NODE *cnf_node, *dnf_node, *cnf_prev, *dnf_prev;
4706  PT_NODE *arg1_prior, *func_arg;
4707  DNF_MERGE_RANGE_RESULT result;
4708  int is_attr;
4709  bool is_all_constant;
4710 
4711  /* traverse CNF list and keep track of the pointer to previous node */
4712  cnf_prev = NULL;
4713  while ((cnf_node = (cnf_prev ? cnf_prev->next : *wherep)))
4714  {
4715 
4716  /* traverse DNF list and keep track of the pointer to previous node */
4717  dnf_prev = NULL;
4718  while ((dnf_node = (dnf_prev ? dnf_prev->or_next : cnf_node)))
4719  {
4720  if (dnf_node->node_type != PT_EXPR)
4721  {
4722  /* dnf_node is not an expression node */
4723  dnf_prev = dnf_prev ? dnf_prev->or_next : dnf_node;
4724  continue;
4725  }
4726 
4727  arg1_prior = pt_get_first_arg_ignore_prior (dnf_node);
4728 
4729  is_attr = true;
4730  is_all_constant = true;
4731  if (pt_is_multi_col_term (arg1_prior))
4732  {
4733  /* multi_col_term can convert to range if arg1 is (attr,func_idx_expr,constant) */
4734  func_arg = arg1_prior->info.function.arg_list;
4735  for ( /* none */ ; func_arg; func_arg = func_arg->next)
4736  {
4737  if (!pt_is_attr (func_arg) && !pt_is_function_index_expression (func_arg) && !pt_is_const (func_arg))
4738  {
4739  is_attr = false;
4740  break;
4741  }
4742  else if (!pt_is_const (func_arg))
4743  {
4744  is_all_constant = false;
4745  }
4746  }
4747  /* if multi_col_term's columns are all constant value then NOT convert to range for constant folding */
4748  if (is_all_constant)
4749  {
4750  is_attr = false;
4751  }
4752  }
4753  else
4754  {
4755  is_attr = pt_is_attr (arg1_prior);
4756  }
4757 
4758  if (!is_attr && !pt_is_instnum (arg1_prior))
4759  {
4760  /* LHS is not an attribute */
4761  dnf_prev = dnf_prev ? dnf_prev->or_next : dnf_node;
4762  continue;
4763  }
4764 
4765  if (dnf_node == cnf_node && dnf_node->or_next == NULL && dnf_node->info.expr.op == PT_EQ
4766  && !pt_is_instnum (arg1_prior))
4767  {
4768  /* do not convert one predicate '=' term to RANGE */
4769  dnf_prev = dnf_prev ? dnf_prev->or_next : dnf_node;
4770  continue;
4771  }
4772 
4773  switch (dnf_node->info.expr.op)
4774  {
4775  case PT_EQ:
4776  case PT_GT:
4777  case PT_GE:
4778  case PT_LT:
4779  case PT_LE:
4780  case PT_BETWEEN:
4781  case PT_IS_IN:
4782  case PT_RANGE:
4783 
4784  /* should be pure constant in list */
4785  if (dnf_node->info.expr.op == PT_IS_IN && PT_IS_SET_TYPE (dnf_node->info.expr.arg2)
4786  && dnf_node->or_next == NULL)
4787  {
4788  /*
4789  * skip merge in list
4790  * server will eliminate duplicate keys
4791  * this is because merging huge in list takes
4792  * too much time.
4793  */
4794  qo_convert_to_range_helper (parser, dnf_node);
4795  break;
4796  }
4797 
4798  /* convert all comparison nodes in the DNF list which have the same attribute as its LHS into one RANGE
4799  * node containing multi-range spec */
4800  qo_convert_to_range_helper (parser, dnf_node);
4801 
4802  if (dnf_node->info.expr.op == PT_RANGE)
4803  {
4804  /* merge range specs in the RANGE node */
4805  result = qo_merge_range_helper (parser, dnf_node);
4806  if (result == DNF_RANGE_ALWAYS_FALSE)
4807  {
4808  /* An empty range is always false so change it to 0<>0 */
4809  DB_VALUE db_zero;
4810  parser_free_tree (parser, dnf_node->info.expr.arg1);
4811  parser_free_tree (parser, dnf_node->info.expr.arg2);
4812  db_make_int (&db_zero, 0);
4813 
4814  dnf_node->info.expr.arg1 = pt_dbval_to_value (parser, &db_zero);
4815  dnf_node->info.expr.arg2 = pt_dbval_to_value (parser, &db_zero);
4816  dnf_node->info.expr.op = PT_NE;
4817 
4818  }
4819  else if (result == DNF_RANGE_ALWAYS_TRUE)
4820  {
4821  /* change unbound range spec to IS NOT NULL node */
4822  parser_free_tree (parser, dnf_node->info.expr.arg2);
4823  dnf_node->info.expr.arg2 = NULL;
4824  dnf_node->info.expr.op = PT_IS_NOT_NULL;
4825  }
4826  }
4827  break;
4828  default:
4829  break;
4830  }
4831  dnf_prev = dnf_prev ? dnf_prev->or_next : dnf_node;
4832  }
4833  cnf_prev = cnf_prev ? cnf_prev->next : cnf_node;
4834  }
4835 }
4836 
4837 /*
4838  * qo_apply_range_intersection_helper () -
4839  * return:
4840  * parser(in):
4841  * node1(in):
4842  * node2(in):
4843  */
4844 static void
4846 {
4847  PT_NODE *range, *sibling, *prev, *new_range, *temp1, *temp2;
4848  PT_OP_TYPE r_op, r_lop, r_uop, s_op, s_lop, s_uop, new_op, new_lop, new_uop;
4849  DB_VALUE *r_lv, *r_uv, *s_lv, *s_uv, *new_lv, *new_uv;
4850  COMP_DBVALUE_WITH_OPTYPE_RESULT cmp1, cmp2, cmp3, cmp4, new_cmp;
4851  bool dont_remove_sibling = false;
4852  bool include_nonvalue;
4853 
4854  assert (parser != NULL);
4855  if (parser == NULL)
4856  {
4857  return;
4858  }
4859 
4860  /* for each range spec of the node1 */
4861  prev = NULL;
4862  while ((range = (prev ? prev->or_next : node1->info.expr.arg2)))
4863  {
4864  if (!pt_is_const_not_hostvar (range->info.expr.arg1)
4865  || (range->info.expr.arg2 && !pt_is_const_not_hostvar (range->info.expr.arg2)))
4866  {
4867  /* not constant; cannot be merged */
4868  prev = prev ? prev->or_next : range;
4869  dont_remove_sibling = true;
4870  continue;
4871  }
4872 
4873  r_op = range->info.expr.op;
4874  if (pt_between_to_comp_op (r_op, &r_lop, &r_uop) != 0)
4875  {
4876  /* something wrong; continue to next range spec */
4877  prev = prev ? prev->or_next : range;
4878  dont_remove_sibling = true;
4879  continue;
4880  }
4881 
4882  if (r_lop == PT_GT_INF)
4883  {
4884  /* PT_BETWEEN_INF_LE or PT_BETWEEN_INF_LT */
4885  r_lv = NULL;
4886  r_uv = pt_value_to_db (parser, range->info.expr.arg1);
4887  }
4888  else if (r_uop == PT_LT_INF)
4889  {
4890  /* PT_BETWEEN_GE_INF or PT_BETWEEN_GT_INF */
4891  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
4892  r_uv = NULL;
4893  }
4894  else if (r_lop == PT_EQ)
4895  {
4896  /* PT_BETWEEN_EQ_NA */
4897  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
4898  r_uv = r_lv;
4899  }
4900  else
4901  {
4902  /* PT_BETWEEN_GE_LE, PT_BETWEEN_GE_LT, PT_BETWEEN_GT_LE, or PT_BETWEEN_GT_LT */
4903  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
4904  r_uv = pt_value_to_db (parser, range->info.expr.arg2);
4905  }
4906 
4907  if (DB_IS_NULL (r_lv) && DB_IS_NULL (r_uv))
4908  {
4909  /* if both are null, this expr is false. */
4910  prev = prev ? prev->or_next : range;
4911  dont_remove_sibling = true;
4912  continue;
4913  }
4914 
4915  /* for each range spec of the node2 */
4916  include_nonvalue = false;
4917  for (sibling = node2->info.expr.arg2; sibling; sibling = sibling->or_next)
4918  {
4919  if (!pt_is_const_not_hostvar (sibling->info.expr.arg1)
4920  || (sibling->info.expr.arg2 && !pt_is_const_not_hostvar (sibling->info.expr.arg2)))
4921  {
4922  /* not constant; cannot be merged */
4923  include_nonvalue = true;
4924  break;
4925  }
4926  }
4927 
4928  if (include_nonvalue == true)
4929  {
4930  /* there was no application */
4931  prev = prev ? prev->or_next : range;
4932  continue;
4933  }
4934 
4935  new_range = NULL;
4936 
4937  /* for each range spec of the node2 */
4938  for (sibling = node2->info.expr.arg2; sibling; sibling = sibling->or_next)
4939  {
4941  && (sibling->info.expr.arg2 == NULL || pt_is_const_not_hostvar (sibling->info.expr.arg2)));
4942 
4943  s_op = sibling->info.expr.op;
4944  if (pt_between_to_comp_op (s_op, &s_lop, &s_uop) != 0)
4945  {
4946  /* something wrong; continue to next range spec */
4947  continue;
4948  }
4949 
4950  if (s_lop == PT_GT_INF)
4951  {
4952  /* PT_BETWEEN_INF_LE or PT_BETWEEN_INF_LT */
4953  s_lv = NULL;
4954  s_uv = pt_value_to_db (parser, sibling->info.expr.arg1);
4955  }
4956  else if (s_uop == PT_LT_INF)
4957  {
4958  /* PT_BETWEEN_GE_INF or PT_BETWEEN_GT_INF */
4959  s_lv = pt_value_to_db (parser, sibling->info.expr.arg1);
4960  s_uv = NULL;
4961  }
4962  else if (s_lop == PT_EQ)
4963  {
4964  /* PT_BETWEEN_EQ_NA */
4965  s_lv = pt_value_to_db (parser, sibling->info.expr.arg1);
4966  s_uv = s_lv;
4967  }
4968  else
4969  {
4970  /* PT_BETWEEN_GE_LE, PT_BETWEEN_GE_LT, PT_BETWEEN_GT_LE, or PT_BETWEEN_GT_LT */
4971  s_lv = pt_value_to_db (parser, sibling->info.expr.arg1);
4972  s_uv = pt_value_to_db (parser, sibling->info.expr.arg2);
4973  }
4974 
4975  if (DB_IS_NULL (s_lv) && DB_IS_NULL (s_uv))
4976  {
4977  /* if both are null, this expr is false. */
4979  dont_remove_sibling = true;
4980  continue;
4981  }
4982 
4984  /* check if the two range specs are mergable */
4985  cmp1 = qo_compare_dbvalue_with_optype (r_lv, r_lop, s_lv, s_lop);
4986  cmp2 = qo_compare_dbvalue_with_optype (r_lv, r_lop, s_uv, s_uop);
4987  cmp3 = qo_compare_dbvalue_with_optype (r_uv, r_uop, s_lv, s_lop);
4988  cmp4 = qo_compare_dbvalue_with_optype (r_uv, r_uop, s_uv, s_uop);
4989  if (cmp1 == CompResultError || cmp2 == CompResultError || cmp3 == CompResultError || cmp4 == CompResultError)
4990  {
4991  /* somthine wrong; continue to next range spec */
4992  continue;
4993  }
4994  if (!new_range)
4995  {
4996  new_range = range;
4997  }
4998  if (!((cmp1 == CompResultLess || cmp1 == CompResultGreater) && cmp1 == cmp2 && cmp1 == cmp3 && cmp1 == cmp4))
4999  {
5000  /* they are not disjoint; apply intersection to the two range specs */
5001 
5002  /* allocate new range spec node */
5003  temp1 = range->or_next;
5004  range->or_next = NULL;
5005  temp2 = parser_copy_tree (parser, range);
5006  new_op = r_op;
5007  if (r_op == PT_BETWEEN_EQ_NA)
5008  {
5009  parser_free_tree (parser, temp2->info.expr.arg2);
5010  temp2->info.expr.arg2 = parser_copy_tree (parser, temp2->info.expr.arg1);
5011  }
5012  new_lop = r_lop;
5013  new_uop = r_uop;
5014  temp2->or_next = (new_range == range) ? NULL : new_range;
5015  new_range = temp2;
5016  range->or_next = temp1;
5017  /* swap arg1 and arg2 if op type is INF_LT or INF_LE to make easy the following merge algorithm */
5018  if (new_op == PT_BETWEEN_INF_LT || new_op == PT_BETWEEN_INF_LE)
5019  {
5020  new_range->info.expr.arg2 = new_range->info.expr.arg1;
5021  new_range->info.expr.arg1 = NULL;
5022  }
5023  if (s_op == PT_BETWEEN_INF_LT || s_op == PT_BETWEEN_INF_LE)
5024  {
5025  sibling->info.expr.arg2 = sibling->info.expr.arg1;
5026  sibling->info.expr.arg1 = NULL;
5027  }
5028  /* determine the lower bound of the merged range spec */
5029  if (cmp1 == CompResultLess || cmp1 == CompResultLessAdj)
5030  {
5031  parser_free_tree (parser, new_range->info.expr.arg1);
5032  new_range->info.expr.arg1 = parser_copy_tree (parser, sibling->info.expr.arg1);
5033  new_lop = s_lop;
5034  if (cmp3 == CompResultEqual && cmp4 == CompResultEqual)
5035  {
5036  new_uop = PT_EQ;
5037  }
5038  }
5039  /* determine the upper bound of the merged range spec */
5040  if (cmp4 == CompResultGreaterAdj || cmp4 == CompResultGreater)
5041  {
5042  parser_free_tree (parser, new_range->info.expr.arg2);
5043  new_range->info.expr.arg2 = parser_copy_tree (parser, sibling->info.expr.arg2);
5044  new_uop = s_uop;
5045  }
5046  /* determine the new range type */
5047  if (pt_comp_to_between_op (new_lop, new_uop, PT_RANGE_INTERSECTION, &new_op) != 0)
5048  {
5049  /* they are not disjoint; remove empty range */
5050  if (new_range->or_next == NULL)
5051  {
5052  parser_free_tree (parser, new_range);
5053  new_range = range;
5054  }
5055  else
5056  {
5057  temp1 = new_range->or_next;
5058  new_range->or_next = NULL;
5059  parser_free_tree (parser, new_range);
5060  new_range = temp1;
5061  }
5062  }
5063  else
5064  { /* merged range is empty */
5065  new_range->info.expr.op = new_op;
5066  /* check if the new range is valid */
5067  if (new_range->info.expr.arg1 && new_range->info.expr.arg2)
5068  {
5069  if (pt_between_to_comp_op (new_op, &new_lop, &new_uop) != 0)
5070  {
5071  /* must be be impossible; skip and go ahead */
5072  }
5073  else
5074  {
5075  new_lv = pt_value_to_db (parser, new_range->info.expr.arg1);
5076  new_uv = pt_value_to_db (parser, new_range->info.expr.arg2);
5077  new_cmp = qo_compare_dbvalue_with_optype (new_lv, new_lop, new_uv, new_uop);
5078  if (new_cmp == CompResultGreater || new_cmp == CompResultGreaterAdj)
5079  {
5080  /* they are not disjoint; remove empty range */
5081  if (new_range->or_next == NULL)
5082  {
5083  parser_free_tree (parser, new_range);
5084  new_range = range;
5085  }
5086  else
5087  {
5088  temp1 = new_range->or_next;
5089  new_range->or_next = NULL;
5090  parser_free_tree (parser, new_range);
5091  new_range = temp1;
5092  }
5093  }
5094  }
5095  }
5096  } /* merged range is empty */
5097 
5098  /* recover arg1 and arg2 for the type of INF_LT, INF_LE */
5099  if (new_op == PT_BETWEEN_INF_LT || new_op == PT_BETWEEN_INF_LE)
5100  {
5101  if (new_range->info.expr.arg1 == NULL && new_range->info.expr.arg2 != NULL)
5102  {
5103  new_range->info.expr.arg1 = new_range->info.expr.arg2;
5104  new_range->info.expr.arg2 = NULL;
5105  }
5106  }
5107  if (s_op == PT_BETWEEN_INF_LT || s_op == PT_BETWEEN_INF_LE)
5108  {
5109  if (sibling->info.expr.arg1 == NULL && sibling->info.expr.arg2 != NULL)
5110  {
5111  sibling->info.expr.arg1 = sibling->info.expr.arg2;
5112  sibling->info.expr.arg2 = NULL;
5113  }
5114  }
5115  }
5116 
5117  /* mark this sibling node to be deleted */
5119  }
5120 
5121  if (new_range == NULL)
5122  {
5123  /* there was no application */
5124  prev = prev ? prev->or_next : range;
5125  continue;
5126  }
5127 
5128  /* replace the range node with the new_range node */
5129  if (new_range != range)
5130  {
5131  if (prev)
5132  {
5133  prev->or_next = new_range;
5134  }
5135  else
5136  {
5137  node1->info.expr.arg2 = new_range;
5138  }
5139  for (prev = new_range; prev->or_next; prev = prev->or_next)
5140  {
5141  ;
5142  }
5143  prev->or_next = range->or_next;
5144  }
5145  else
5146  {
5147  /* the result is empty range */
5148  if (prev)
5149  {
5150  prev->or_next = range->or_next;
5151  }
5152  else
5153  {
5154  node1->info.expr.arg2 = range->or_next;
5155  }
5156  }
5157  /* range->next == NULL */
5158  range->or_next = NULL;
5159  parser_free_tree (parser, range);
5160  }
5161 
5162 
5163  if (dont_remove_sibling != true)
5164  {
5165  /* remove nodes marked as to be deleted while applying intersction */
5166  prev = NULL;
5167  while ((sibling = (prev ? prev->or_next : node2->info.expr.arg2)))
5168  {
5170  {
5171  if (prev)
5172  {
5173  prev->or_next = sibling->or_next;
5174  }
5175  else
5176  {
5177  node2->info.expr.arg2 = sibling->or_next;
5178  }
5179  /* sibling->next == NULL */
5180  sibling->or_next = NULL;
5181  parser_free_tree (parser, sibling);
5182  }
5183  else
5184  {
5185  prev = prev ? prev->or_next : sibling;
5186  }
5187  }
5188  }
5189 
5190  for (range = node1->info.expr.arg2; range; range = range->or_next)
5191  {
5192  if (range->info.expr.op == PT_BETWEEN_EQ_NA && range->info.expr.arg2 != NULL)
5193  {
5194  parser_free_tree (parser, range->info.expr.arg2);
5195  range->info.expr.arg2 = NULL;
5196  }
5197  }
5198  for (range = node2->info.expr.arg2; range; range = range->or_next)
5199  {
5200  if (range->info.expr.op == PT_BETWEEN_EQ_NA && range->info.expr.arg2 != NULL)
5201  {
5202  parser_free_tree (parser, range->info.expr.arg2);
5203  range->info.expr.arg2 = NULL;
5204  }
5205  }
5206 }
5207 
5208 /*
5209  * qo_apply_range_intersection () - Apply range intersection
5210  * return:
5211  * parser(in):
5212  * wherep(in): pointer to WHERE list
5213  */
5214 static void
5216 {
5217  PT_NODE *node, *sibling, *node_prev, *sibling_prev;
5218  int location;
5219  PT_NODE *arg1_prior, *sibling_prior;
5220 
5221  /* traverse CNF list and keep track of the pointer to previous node */
5222  node_prev = NULL;
5223  while ((node = (node_prev ? node_prev->next : *wherep)))
5224  {
5225  if (node->node_type != PT_EXPR || node->info.expr.op != PT_RANGE || node->or_next != NULL)
5226  {
5227  /* NOTE: Due to implementation complexity, handle one predicate term only. */
5228  /* neither expression node, RANGE node, nor one predicate term */
5229  node_prev = node_prev ? node_prev->next : *wherep;
5230  continue;
5231  }
5232 
5233  arg1_prior = pt_get_first_arg_ignore_prior (node);
5234 
5235  if (!pt_is_attr (arg1_prior) && !pt_is_instnum (arg1_prior))
5236  {
5237  /* LHS is not an attribute */
5238 
5239  node_prev = node_prev ? node_prev->next : *wherep;
5240 
5241  continue;
5242  }
5243 
5244  if (node->next == NULL)
5245  { /* one range spec; nothing to intersect */
5246  PT_NODE *range;
5247  PT_OP_TYPE r_lop, r_uop;
5248  DB_VALUE *r_lv, *r_uv;
5250 
5251  range = node->info.expr.arg2;
5252  if (range->info.expr.arg2 && pt_is_const_not_hostvar (range->info.expr.arg1)
5253  && pt_is_const_not_hostvar (range->info.expr.arg2))
5254  {
5255  /* both constant; check range spec */
5256  if (!pt_between_to_comp_op (range->info.expr.op, &r_lop, &r_uop))
5257  {
5258  r_lv = pt_value_to_db (parser, range->info.expr.arg1);
5259  r_uv = pt_value_to_db (parser, range->info.expr.arg2);
5260  /* check if the range spec is valid */
5261  cmp = qo_compare_dbvalue_with_optype (r_lv, r_lop, r_uv, r_uop);
5262  if (cmp == CompResultGreaterAdj || cmp == CompResultGreater)
5263  {
5264  /* the range is invalid, that is, lower bound is greater than upper bound */
5265  if (range->or_next == NULL)
5266  {
5267  node->info.expr.arg2 = NULL;
5268  }
5269  else
5270  {
5271  node->info.expr.arg2 = range->or_next;
5272  range->or_next = NULL;
5273  }
5274  parser_free_tree (parser, range);
5275  }
5276  else if (cmp == CompResultError)
5277  {
5278  ; /* something wrong; do nothing */
5279  }
5280  }
5281  }
5282  }
5283 
5284  /* search CNF list from the next to the node and keep track of the pointer to previous node */
5285  sibling_prev = node;
5286 
5287  while ((sibling = sibling_prev->next))
5288  {
5289  if (sibling->node_type != PT_EXPR || sibling->info.expr.op != PT_RANGE || sibling->or_next != NULL)
5290  {
5291  /* neither an expression node, RANGE node, nor one predicate term */
5292  sibling_prev = sibling_prev->next;
5293  continue;
5294  }
5295 
5296  sibling_prior = pt_get_first_arg_ignore_prior (sibling);
5297  if (PT_IS_EXPR_WITH_PRIOR_ARG (sibling))
5298  {
5299  if (!PT_IS_EXPR_WITH_PRIOR_ARG (node))
5300  {
5301  /* sibling has prior, node hasn't */
5302  sibling_prev = sibling_prev->next;
5303  continue;
5304  }
5305  }
5306  else
5307  {
5308  if (PT_IS_EXPR_WITH_PRIOR_ARG (node))
5309  {
5310  /* sibling hasn't prior, node has */
5311  sibling_prev = sibling_prev->next;
5312  continue;
5313  }
5314  }
5315  /* if node had prior check that sibling also contains prior and vice-versa */
5316 
5317  if (!pt_is_attr (sibling_prior) && !pt_is_instnum (sibling_prior))
5318  {
5319  /* LHS is not an attribute */
5320  sibling_prev = sibling_prev->next;
5321  continue;
5322  }
5323 
5324  if (sibling->info.expr.location != node->info.expr.location)
5325  {
5326  sibling_prev = sibling_prev->next;
5327  continue;
5328  }
5329 
5330  if ((arg1_prior->node_type != sibling_prior->node_type)
5331  || (pt_is_attr (arg1_prior) && pt_is_attr (sibling_prior)
5332  && pt_check_path_eq (parser, arg1_prior, sibling_prior)))
5333  {
5334  /* pt_check_path_eq() return non-zero if two are different */
5335  sibling_prev = sibling_prev->next;
5336  continue;
5337  }
5338 
5339  /* found a node of the same attribute */
5340 
5341  /* combine each range specs of two RANGE nodes */
5342  qo_apply_range_intersection_helper (parser, node, sibling);
5343 
5344  /* remove the sibling node if its range is empty */
5345  if (sibling->info.expr.arg2 == NULL)
5346  {
5347  sibling_prev->next = sibling->next;
5348  sibling->next = NULL;
5349  /* sibling->or_next == NULL */
5350  parser_free_tree (parser, sibling);
5351  }
5352  else
5353  {
5354  sibling_prev = sibling_prev->next;
5355  }
5356 
5357  if (node->info.expr.arg2 == NULL)
5358  {
5359  break;
5360  }
5361  }
5362 
5363  /* remove the node if its range is empty */
5364  if (node->info.expr.arg2 == NULL)
5365  {
5366  if (node_prev)
5367  {
5368  node_prev->next = node->next;
5369  }
5370  else
5371  {
5372  *wherep = node->next;
5373  }
5374 
5375  node->next = NULL;
5376  location = node->info.expr.location; /* save location */
5377 
5378  /* node->or_next == NULL */
5379  parser_free_tree (parser, node);
5380 
5381  if (location == 0)
5382  {
5383  /* empty conjuctive make whole condition always false */
5384  /* NOTICE: that is valid only when we handle one predicate terms in this function */
5385  parser_free_tree (parser, *wherep);
5386 
5387  /* make a single false node */
5388  node = parser_new_node (parser, PT_VALUE);
5389  if (node == NULL)
5390  {
5391  PT_INTERNAL_ERROR (parser, "allocate new node");
5392  return;
5393  }
5394 
5395  node->type_enum = PT_TYPE_LOGICAL;
5396  node->info.value.data_value.i = 0;
5397  node->info.value.location = location;
5398  (void) pt_value_to_db (parser, node);
5399  *wherep = node;
5400 
5401  return;
5402  }
5403  else
5404  {
5405  PT_NODE *prev, *next;
5406 
5407  /* empty conjunctive is outer join ON condition. remove all nodes which have same location number */
5408  prev = NULL;
5409  node = *wherep;
5410  while (node)
5411  {
5412  if ((node->node_type == PT_EXPR && node->info.expr.location == location)
5413  || (node->node_type == PT_VALUE && node->info.value.location == location))
5414  {
5415  next = node->next;
5416  node->next = NULL;
5417  parser_free_tree (parser, node);
5418  if (prev)
5419  {
5420  prev->next = next;
5421  }
5422  else
5423  {
5424  *wherep = next;
5425  }
5426  node = next;
5427  }
5428  else
5429  {
5430  prev = node;
5431  node = node->next;
5432  }
5433  }
5434 
5435  /* make a single false node and append it to WHERE list */
5436  node = parser_new_node (parser, PT_VALUE);
5437  if (node == NULL)
5438  {
5439  PT_INTERNAL_ERROR (parser, "allocate new node");
5440  return;
5441  }
5442 
5443  node->type_enum = PT_TYPE_LOGICAL;
5444  node->info.value.data_value.i = 0;
5445  node->info.value.location = location;
5446  (void) pt_value_to_db (parser, node);
5447  node->next = *wherep;
5448  *wherep = node;
5449 
5450  /* re-traverse CNF list */
5451  node_prev = node;
5452  }
5453  }
5454  else
5455  {
5456  node_prev = (node_prev) ? node_prev->next : *wherep;
5457  }
5458  }
5459 }
5460 
5461 /*
5462  * qo_rewrite_outerjoin () - Rewrite outer join to inner join
5463  * return: PT_NODE *
5464  * parser(in):
5465  * node(in): SELECT node
5466  * arg(in):
5467  * continue_walk(in):
5468  *
5469  * Note: do parser_walk_tree() pre function
5470  */
5471 static PT_NODE *
5472 qo_rewrite_outerjoin (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
5473 {
5474  PT_NODE *spec, *prev_spec, *expr, *ns, *save_next;
5475  SPEC_ID_INFO info, info_spec;
5476  RESET_LOCATION_INFO locate_info;
5477  bool rewrite_again;
5478 
5479  if (node->node_type != PT_SELECT)
5480  {
5481  return node;
5482  }
5483 
5484  if (node->info.query.q.select.connect_by)
5485  {
5486  /* don't rewrite if the query is hierarchical because conditions in 'where' must be applied after HQ evaluation;
5487  * HQ uses as input the result of joins */
5488  return node;
5489  }
5490 
5491  do
5492  {
5493  rewrite_again = false;
5494  /* traverse spec list */
5495  prev_spec = NULL;
5496  for (spec = node->info.query.q.select.from; spec; prev_spec = spec, spec = spec->next)
5497  {
5498  if (spec->info.spec.join_type == PT_JOIN_LEFT_OUTER
5499  || (spec->info.spec.join_type == PT_JOIN_RIGHT_OUTER && prev_spec))
5500  {
5501  if (spec->info.spec.join_type == PT_JOIN_LEFT_OUTER)
5502  {
5503  info.id = info_spec.id = spec->info.spec.id;
5504  }
5505  else
5506  {
5507  info.id = info_spec.id = prev_spec->info.spec.id;
5508  }
5509 
5510  info_spec.appears = false;
5511  info.nullable = false;
5512 
5513  /* search where list */
5514  for (expr = node->info.query.q.select.where; expr; expr = expr->next)
5515  {
5516  if (expr->node_type == PT_EXPR && expr->info.expr.location == 0 && expr->info.expr.op != PT_IS_NULL
5517  && expr->or_next == NULL && expr->info.expr.op != PT_AND && expr->info.expr.op != PT_OR)
5518  {
5519  save_next = expr->next;
5520  expr->next = NULL;
5521  (void) parser_walk_tree (parser, expr, NULL, NULL, qo_check_nullable_expr_with_spec, &info);
5522  (void) parser_walk_tree (parser, expr, qo_get_name_by_spec_id, &info_spec, NULL, NULL);
5523  expr->next = save_next;
5524 
5525  /* have found a term which makes outer join to inner */
5526  /* there are predicate referenced by spec and all preds are not nullable */
5527  if (info_spec.appears && !info.nullable)
5528  {
5529  rewrite_again = true;
5530  spec->info.spec.join_type = PT_JOIN_INNER;
5531 
5532  locate_info.start = spec->info.spec.location;
5533  locate_info.end = locate_info.start;
5534  (void) parser_walk_tree (parser, node->info.query.q.select.where, qo_reset_location,
5535  &locate_info, NULL, NULL);
5536 
5537  /* rewrite the following connected right outer join to inner join */
5538  for (ns = spec->next; /* traverse next spec */
5539  ns && ns->info.spec.join_type != PT_JOIN_NONE; ns = ns->next)
5540  {
5542  {
5544  locate_info.start = ns->info.spec.location;
5545  locate_info.end = locate_info.start;
5546  (void) parser_walk_tree (parser, node->info.query.q.select.where, qo_reset_location,
5547  &locate_info, NULL, NULL);
5548  }
5549  }
5550  break;
5551  }
5552  }
5553  }
5554  }
5555 
5557  {
5558  /* apply qo_rewrite_outerjoin() to derived table's subquery */
5560  }
5561  }
5562  }
5563  while (rewrite_again);
5564 
5565  *continue_walk = PT_LIST_WALK;
5566 
5567  return node;
5568 }
5569 
5570 /*
5571  * qo_reset_location () -
5572  * return:
5573  * parser(in):
5574  * node(in):
5575  * arg(in):
5576  * continue_walk(in):
5577  */
5578 static PT_NODE *
5579 qo_reset_location (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
5580 {
5581  RESET_LOCATION_INFO *infop = (RESET_LOCATION_INFO *) arg;
5582 
5583  if (node->node_type == PT_EXPR && node->info.expr.location >= infop->start && node->info.expr.location <= infop->end)
5584  {
5585  node->info.expr.location = 0;
5586  }
5587 
5588  if (node->node_type == PT_NAME && node->info.name.location >= infop->start && node->info.name.location <= infop->end)
5589  {
5590  node->info.name.location = 0;
5591  }
5592 
5593  if (node->node_type == PT_VALUE && node->info.value.location >= infop->start
5594  && node->info.value.location <= infop->end)
5595  {
5596  node->info.value.location = 0;
5597  }
5598 
5599  return node;
5600 }
5601 
5602 /*
5603  * qo_rewrite_innerjoin () - Rewrite explicit(ordered) inner join
5604  * to implicit(unordered) inner join
5605  * return: PT_NODE *
5606  * parser(in):
5607  * node(in): SELECT node
5608  * arg(in):
5609  * continue_walk(in):
5610  *
5611  * Note: If join order hint is set, skip and go ahead.
5612  * do parser_walk_tree() pre function
5613  */
5614 static PT_NODE *
5615 qo_rewrite_innerjoin (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
5616 {
5617  PT_NODE *spec, *spec2;
5618  RESET_LOCATION_INFO info; /* spec location reset info */
5619 
5620  if (node->node_type != PT_SELECT)
5621  {
5622  return node;
5623  }
5624 
5625  if (node->info.query.q.select.connect_by)
5626  {
5627  /* don't rewrite if the query is hierarchical because conditions in 'where' must be applied after HQ evaluation;
5628  * HQ uses as input the result of joins */
5629  return node;
5630  }
5631 
5632  if (node->info.query.q.select.hint & PT_HINT_ORDERED)
5633  {
5634  /* join hint: force join left-to-right. skip and go ahead. */
5635  return node;
5636  }
5637 
5638  info.start = 0;
5639  info.end = 0;
5640  info.found_outerjoin = false;
5641 
5642  /* traverse spec list to find disconnected spec list */
5643  for (info.start_spec = spec = node->info.query.q.select.from; spec; spec = spec->next)
5644  {
5645 
5646  switch (spec->info.spec.join_type)
5647  {
5648  case PT_JOIN_LEFT_OUTER:
5649  case PT_JOIN_RIGHT_OUTER:
5650  /* case PT_JOIN_FULL_OUTER: */
5651  info.found_outerjoin = true;
5652  break;
5653  default:
5654  break;
5655  }
5656 
5657  if (spec->info.spec.join_type == PT_JOIN_NONE && info.found_outerjoin == false && info.start < info.end)
5658  {
5659  /* rewrite explicit inner join to implicit inner join */
5660  for (spec2 = info.start_spec; spec2 != spec; spec2 = spec2->next)
5661  {
5662  if (spec2->info.spec.join_type == PT_JOIN_INNER)
5663  {
5664  spec2->info.spec.join_type = PT_JOIN_NONE;
5665  }
5666  }
5667 
5668  /* reset location of spec list */
5669  (void) parser_walk_tree (parser, node->info.query.q.select.where, qo_reset_location, &info, NULL, NULL);
5670 
5671  /* reset start spec, found_outerjoin */
5672  info.start = spec->info.spec.location;
5673  info.start_spec = spec;
5674  info.found_outerjoin = false;
5675  }
5676 
5677  info.end = spec->info.spec.location;
5678 
5680  {
5681  /* apply qo_rewrite_innerjoin() to derived table's subquery */
5683  }
5684  }
5685 
5686  if (info.found_outerjoin == false && info.start < info.end)
5687  {
5688  /* rewrite explicit inner join to implicit inner join */
5689  for (spec2 = info.start_spec; spec2; spec2 = spec2->next)
5690  {
5691  if (spec2->info.spec.join_type == PT_JOIN_INNER)
5692  {
5693  spec2->info.spec.join_type = PT_JOIN_NONE;
5694  }
5695  }
5696 
5697  /* reset location of spec list */
5698  (void) parser_walk_tree (parser, node->info.query.q.select.where, qo_reset_location, &info, NULL, NULL);
5699  }
5700 
5701  *continue_walk = PT_LIST_WALK;
5702 
5703  return node;
5704 }
5705 
5706 /*
5707  * qo_rewrite_hidden_col_as_derived () - Rewrite subquery with ORDER BY
5708  * hidden column as derived one
5709  * return: PT_NODE *
5710  * parser(in):
5711  * node(in): QUERY node
5712  * parent_node(in):
5713  *
5714  * Note: Keep out hidden column from derived select list
5715  */
5716 static PT_NODE *
5718 {
5719  PT_NODE *t_node, *next, *derived;
5720 
5721  switch (node->node_type)
5722  {
5723  case PT_SELECT:
5724  if (node->info.query.order_by)
5725  {
5726  bool remove_order_by = true; /* guessing */
5727 
5728  /* check parent context */
5729  if (parent_node)
5730  {
5731  switch (parent_node->node_type)
5732  {
5733  case PT_FUNCTION:
5734  switch (parent_node->info.function.function_type)
5735  {
5736  case F_TABLE_SEQUENCE:
5737  remove_order_by = false;
5738  break;
5739  default:
5740  break;
5741  }
5742  break;
5743  default:
5744  break;
5745  }
5746  }
5747  else
5748  {
5749  remove_order_by = false;
5750  }
5751 
5752  /* check node context */
5753  if (remove_order_by == true)
5754  {
5755  if (node->info.query.orderby_for)
5756  {
5757  remove_order_by = false;
5758  }
5759  }
5760 
5761  if (remove_order_by == true)
5762  {
5763  for (t_node = node->info.query.q.select.list; t_node; t_node = t_node->next)
5764  {
5765  if (t_node->node_type == PT_EXPR && t_node->info.expr.op == PT_ORDERBY_NUM)
5766  {
5767  remove_order_by = false;
5768  break;
5769  }
5770  }
5771  }
5772 
5773  /* remove unnecessary ORDER BY clause */
5774  if (remove_order_by == true && !node->info.query.q.select.connect_by)
5775  {
5776  parser_free_tree (parser, node->info.query.order_by);
5777  node->info.query.order_by = NULL;
5778 
5779  for (t_node = node->info.query.q.select.list; t_node && t_node->next; t_node = next)
5780  {
5781  next = t_node->next;
5782  if (next->flag.is_hidden_column)
5783  {
5784  parser_free_tree (parser, next);
5785  t_node->next = NULL;
5786  break;
5787  }
5788  }
5789  }
5790  else
5791  {
5792  /* Check whether we can rewrite query as derived. */
5793  bool skip_query_rewrite_as_derived = false;
5794  if (node->info.query.is_subquery == PT_IS_SUBQUERY && node->info.query.order_by != NULL)
5795  {
5796  /* If all nodes in select list are hidden columns, we do not rewrite the query as derived
5797  * since we want to avoid null select list. This will avoid the crash for queries like:
5798  * set @a = 1; SELECT (SELECT @a := @a + 1 FROM db_root ORDER BY @a + 1)
5799  */
5800  skip_query_rewrite_as_derived = true;
5801  for (t_node = node->info.query.q.select.list; t_node; t_node = t_node->next)
5802  {
5803  if (!t_node->flag.is_hidden_column)
5804  {
5805  skip_query_rewrite_as_derived = false;
5806  }
5807  }
5808  }
5809 
5810  if (!skip_query_rewrite_as_derived)
5811  {
5812  for (t_node = node->info.query.q.select.list; t_node; t_node = t_node->next)
5813  {
5814  if (t_node->flag.is_hidden_column)
5815  {
5816  /* make derived query */
5817  derived = mq_rewrite_query_as_derived (parser, node);
5818  if (derived == NULL)
5819  {
5820  break;
5821  }
5822 
5823  PT_NODE_MOVE_NUMBER_OUTERLINK (derived, node);
5824  derived->info.query.q.select.flavor = node->info.query.q.select.flavor;
5825  derived->info.query.is_subquery = node->info.query.is_subquery;
5826 
5827  /* free old composite query */
5828  parser_free_tree (parser, node);
5829  node = derived;
5830  break;
5831  }
5832  }
5833  }
5834  } /* else */
5835  }
5836  break;
5837 
5838  case PT_UNION:
5839  case PT_DIFFERENCE:
5840  case PT_INTERSECTION:
5843  break;
5844  default:
5845  return node;
5846  }
5847 
5848  return node;
5849 }
5850 
5851 /*
5852  * qo_rewrite_index_hints () - Rewrite index hint list, removing useless hints
5853  * return: PT_NODE *
5854  * parser(in):
5855  * node(in): QUERY node
5856  * parent_node(in):
5857  */
5858 static void
5860 {
5861  PT_NODE *using_index = NULL, *hint_node, *prev_node, *next_node;
5862 
5863  bool is_sorted, is_idx_reversed, is_idx_match_nokl, is_hint_masked;
5864 
5865  PT_NODE *hint_none, *root_node;
5866  PT_NODE dummy_hint_local, *dummy_hint;
5867 
5868  switch (statement->node_type)
5869  {
5870  case PT_SELECT:
5871  using_index = statement->info.query.q.select.using_index;
5872  break;
5873  case PT_UPDATE:
5874  using_index = statement->info.update.using_index;
5875  break;
5876  case PT_DELETE:
5877  using_index = statement->info.delete_.using_index;
5878  break;
5879  default:
5880  /* USING index clauses are not allowed for other query types */
5881  assert (false);
5882  return;
5883  }
5884 
5885  if (using_index == NULL)
5886  {
5887  /* no index hints, nothing to do here */
5888  return;
5889  }
5890 
5891  /* Main logic - we can safely assume that pt_check_using_index() has already checked for possible semantic errors or
5892  * incompatible index hints. */
5893 
5894  /* basic rewrite, for USING INDEX NONE */
5895  hint_node = using_index;
5896  prev_node = NULL;
5897  hint_none = NULL;
5898  while (hint_node != NULL)
5899  {
5900  if (hint_node->etc == (void *) PT_IDX_HINT_NONE)
5901  {
5902  hint_none = hint_node;
5903  break;
5904  }
5905  prev_node = (prev_node == NULL) ? hint_node : prev_node->next;
5906  hint_node = hint_node->next;
5907  }
5908 
5909  if (hint_none != NULL)
5910  {
5911  /* keep only the using_index_none hint stored in hint_none */
5912  /* update links and discard the first part of the hint list */
5913  if (prev_node != NULL)
5914  {
5915  prev_node->next = NULL;
5916  parser_free_tree (parser, using_index);
5917  using_index = NULL;
5918  }
5919  /* update links and discard the last part of the hint list */
5920  hint_node = hint_none->next;
5921  if (hint_node != NULL)
5922  {
5923  parser_free_tree (parser, hint_node);
5924  hint_node = NULL;
5925  }
5926  /* update links and keep only the USING INDEX NONE node */
5927  hint_none->next = NULL;
5928  using_index = hint_none;
5929  goto exit;
5930  }
5931 
5932  if (using_index->etc == (void *) PT_IDX_HINT_ALL_EXCEPT)
5933  {
5934  /* find all t.none index hints and mark them for later removal */
5935  /* the first node, when USING INDEX ALL EXCEPT, is a '*', so use this node as a constant list root */
5936  hint_node = using_index;
5937  while (hint_node != NULL && (next_node = hint_node->next) != NULL)
5938  {
5939  if (next_node->info.name.original == NULL && next_node->info.name.resolved != NULL
5940  && strcmp (next_node->info.name.resolved, "*") != 0)
5941  {
5942  /* found a t.none identifier; remove it from the list */
5943  hint_node->next = next_node->next;
5944  next_node->next = NULL;
5945  parser_free_node (parser, next_node);
5946  }
5947  else
5948  {
5949  hint_node = hint_node->next;
5950  }
5951  }
5952 
5953  /* if only the '*' marker node is left in the list, it means that USING INDEX ALL EXCEPT contains only
5954  * t.none-like hints, so it is actually an empty hint list */
5955  if (using_index->next == NULL)
5956  {
5957  parser_free_node (parser, using_index);
5958  using_index = NULL;
5959  goto exit;
5960  }
5961 
5962  root_node = prev_node = using_index;
5963  hint_node = using_index->next;
5964  }
5965  else
5966  {
5967  /* there is no USING INDEX {NONE|ALL EXCEPT ...} in the query; the dummy node is necessary for faster operation;
5968  * use local variable dummy_hint */
5969  dummy_hint = &dummy_hint_local;
5970  dummy_hint->next = using_index;
5971  /* just need something else than PT_IDX_HINT_ALL AEXCEPT, so that this node won't be kept later */
5972  dummy_hint->etc = (void *) PT_IDX_HINT_USE;
5973  root_node = prev_node = dummy_hint;
5974  hint_node = using_index;
5975  }
5976 
5977  /* remove duplicate index hints and sort them; keep the same order for the hints of the same type with keylimit */
5978  /* order: class_none, ignored, forced, used */
5979  is_sorted = false;
5980  while (!is_sorted)
5981  {
5982  prev_node = root_node;
5983  hint_node = prev_node->next;
5984  is_sorted = true;
5985  while ((next_node = hint_node->next) != NULL)
5986  {
5987  is_idx_reversed = false;
5988  is_idx_match_nokl = false;
5989  if (PT_IDX_HINT_ORDER (hint_node) > PT_IDX_HINT_ORDER (next_node))
5990  {
5991  is_idx_reversed = true;
5992  }
5993  else if (hint_node->etc == next_node->etc)
5994  {
5995  /* if hints have the same type, check if they need to be swapped or are identical and one of them needs
5996  * to be removed */
5997  int res_cmp_tbl_names = -1;
5998  /* unless USING INDEX NONE, which is rewritten above, all indexes should have table names already
5999  * resolved */
6000  assert (hint_node->info.name.resolved != NULL && next_node->info.name.resolved != NULL);
6001 
6002  /* compare the tables on which the indexes are defined */
6003  res_cmp_tbl_names =
6004  intl_identifier_casecmp (hint_node->info.name.resolved, next_node->info.name.resolved);
6005 
6006  if (res_cmp_tbl_names == 0)
6007  {
6008  /* also compare index names */
6009  if (hint_node->info.name.original != NULL && next_node->info.name.original != NULL)
6010  {
6011  /* index names can be null if t.none */
6012  int res_cmp_idx_names;
6013 
6014  res_cmp_idx_names =
6015  intl_identifier_casecmp (hint_node->info.name.original, next_node->info.name.original);
6016  if (res_cmp_idx_names == 0)
6017  {
6018  is_idx_match_nokl = true;
6019  }
6020  else
6021  {
6022  is_idx_reversed = (res_cmp_idx_names > 0);
6023  }
6024  }
6025  else
6026  {
6027  /* hints are of the same type, name.original is either NULL or not NULL for both hints */
6028  assert (hint_node->info.name.original == NULL && next_node->info.name.original == NULL);
6029  /* both hints are "same-table.none"; identical */
6030  is_idx_match_nokl = true;
6031  }
6032  }
6033  else
6034  {
6035  is_idx_reversed = (res_cmp_tbl_names > 0);
6036  }
6037 
6038  if (is_idx_match_nokl)
6039  {
6040  /* The same index is used in both hints; examine the keylimit clauses; if search_node does not have
6041  * keylimit, the IF below will skip, and search_node will be deleted */
6042  if (next_node->info.name.indx_key_limit != NULL)
6043  {
6044  /* search_node has keylimit */
6045  if (hint_node->info.name.indx_key_limit != NULL)
6046  {
6047  /* hint_node has keylimit; no action is performed; we want to preserve the order of index
6048  * hints for the same index, with keylimit */
6049  is_idx_reversed = false;
6050  is_idx_match_nokl = false;
6051  }
6052  else
6053  {
6054  /* special case; need to delete hint_node and keep search_node, because this one has
6055  * keylimit; */
6056  assert (!is_idx_reversed);
6057  is_idx_reversed = true;
6058  /* reverse the two nodes so the code below can be reused for this situation */
6059  }
6060  } /* endif (search_node) */
6061  } /* endif (is_idx_match_nokl) */
6062  }
6063 
6064  if (is_idx_reversed)
6065  {
6066  /* Interchange the two hints */
6067  hint_node->next = next_node->next;
6068  next_node->next = hint_node;
6069  prev_node->next = next_node;
6070  is_sorted = false;
6071  /* update hint_node and search_node, for possible delete */
6072  hint_node = prev_node->next;
6073  next_node = hint_node->next;
6074  }
6075 
6076  if (is_idx_match_nokl)
6077  {
6078  /* remove search_node */
6079  hint_node->next = next_node->next;
6080  next_node->next = NULL;
6081  parser_free_node (parser, next_node);
6082  /* node removed, use prev_node and hint_node in next loop */
6083  continue;
6084  }
6085  prev_node = prev_node->next;
6086  hint_node = prev_node->next;
6087  }
6088  }
6089 
6090  /* Find index hints to remove later. At this point, the only index hints that can be found in using_index are
6091  * {USE|FORCE|IGNORE} INDEX and USING INDEX {idx|idx(-)|idx(+)|t.none}... Need to ignore duplicate hints, and hints
6092  * that are masked by applying the hint operation rules. */
6093  hint_node = root_node->next;
6094  while (hint_node != NULL)
6095  {
6096  next_node = hint_node->next;
6097  prev_node = hint_node;
6098  while (next_node != NULL)
6099  {
6100  if (next_node->etc == hint_node->etc)
6101  {
6102  /* same hint type; duplicates were already removed, skip hint */
6103  prev_node = next_node;
6104  next_node = next_node->next;
6105  continue;
6106  }
6107 
6108  /* Main logic for removing redundant/masked index hints */
6109  /* The hint list is now sorted, first by index type, then by table and index name, so the next_node type is
6110  * the same as hint_node or lower in importance (class.none > ignore > force > use), so it is not necessary
6111  * to check next_index hint type */
6112  is_hint_masked = false;
6113 
6114  if ((hint_node->etc == (void *) PT_IDX_HINT_CLASS_NONE
6115  || ((hint_node->etc == (void *) PT_IDX_HINT_IGNORE || hint_node->etc == (void *) PT_IDX_HINT_FORCE)
6116  && (intl_identifier_casecmp (hint_node->info.name.original, next_node->info.name.original) == 0)))
6117  && (intl_identifier_casecmp (hint_node->info.name.resolved, next_node->info.name.resolved) == 0))
6118  {
6119  is_hint_masked = true;
6120  }
6121 
6122  if (is_hint_masked)
6123  {
6124  /* hint search_node is masked; remove it from the hint list */
6125  prev_node->next = next_node->next;
6126  next_node->next = NULL;
6127  parser_free_node (parser, next_node);
6128  next_node = prev_node;
6129  }
6130  prev_node = next_node;
6131  next_node = next_node->next;
6132  }
6133  hint_node = hint_node->next;
6134  }
6135 
6136  /* remove the dummy first node, if any */
6137  if (root_node->etc != (void *) PT_IDX_HINT_ALL_EXCEPT)
6138  {
6139  using_index = root_node->next;
6140  root_node->next = NULL;
6141  }
6142  else
6143  {
6144  using_index = root_node;
6145  }
6146 
6147 exit:
6148  /* Save changes to query node */
6149  switch (statement->node_type)
6150  {
6151  case PT_SELECT:
6152  statement->info.query.q.select.using_index = using_index;
6153  break;
6154  case PT_UPDATE:
6155  statement->info.update.using_index = using_index;
6156  break;
6157  case PT_DELETE:
6158  statement->info.delete_.using_index = using_index;
6159  break;
6160  default:
6161  break;
6162  }
6163 }
6164 
6165 /*
6166  * qo_rewrite_subqueries () - Rewrite uncorrelated subquery to join query
6167  * return: PT_NODE *
6168  * parser(in):
6169  * node(in): SELECT node
6170  * arg(in):
6171  * continue_walk(in):
6172  *
6173  * Note: do parser_walk_tree() pre function
6174  */
6175 static PT_NODE *
6176 qo_rewrite_subqueries (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
6177 {
6178  PT_NODE *cnf_node, *arg1, *arg2, *select_list, *arg2_list;
6179  PT_OP_TYPE op_type;
6180  PT_NODE *new_spec, *new_attr, *new_func;
6181  int *idx = (int *) arg;
6182  bool do_rewrite;
6183  PT_NODE *save_next, *arg1_next, *new_attr_next, *tmp, *arg2_next;
6184  PT_OP_TYPE saved_op_type;
6185 
6186  if (node->node_type != PT_SELECT)
6187  {
6188  return node;
6189  }
6190 
6191  /* traverse CNF list */
6192  for (cnf_node = node->info.query.q.select.where; cnf_node; cnf_node = cnf_node->next)
6193  {
6194 
6195  if (cnf_node->or_next != NULL)
6196  {
6197  continue;
6198  }
6199 
6200  if (cnf_node->node_type != PT_EXPR)
6201  {
6202  continue;
6203  }
6204 
6205  op_type = cnf_node->info.expr.op;
6206  arg1 = cnf_node->info.expr.arg1;
6207  arg2 = cnf_node->info.expr.arg2;
6208 
6209  if (arg1 && arg2
6210  && (op_type == PT_EQ || op_type == PT_IS_IN || op_type == PT_EQ_SOME || op_type == PT_GT_SOME
6211  || op_type == PT_GE_SOME || op_type == PT_LT_SOME || op_type == PT_LE_SOME))
6212  {
6213  /* go ahead */
6214  }
6215  else
6216  {
6217  continue;
6218  }
6219 
6220  select_list = pt_get_select_list (parser, arg2);
6221  if ((op_type == PT_EQ || op_type == PT_IS_IN || op_type == PT_EQ_SOME) && select_list
6222  && PT_IS_COLLECTION_TYPE (arg1->type_enum) && PT_IS_FUNCTION (arg1)
6223  && PT_IS_COLLECTION_TYPE (arg2->type_enum) && (PT_IS_FUNCTION (select_list) || PT_IS_CONST (select_list)))
6224  {
6225  /* collection case : (col1,col2) [in or =] (select col1,col2 ...) */
6226  arg1 = arg1->info.function.arg_list;
6227  if (PT_IS_FUNCTION (select_list))
6228  {
6229  arg2_list = select_list->info.function.arg_list;
6230  }
6231  else
6232  {
6233  arg2_list = select_list->info.value.data_value.set;
6234  }
6235  }
6236  else if (op_type == PT_EQ)
6237  {
6238  /* one column subquery is not rewrited to join with derived table. ex) col1 = (select col1 ... ) */
6239  continue;
6240  }
6241  else
6242  {
6243  arg2_list = arg2;
6244  }
6245 
6246  do_rewrite = false;
6247  select_list = NULL;
6248 
6249  /* should be 'attr op uncorr-subquery', and select list of the subquery should be indexable-column */
6250  for (arg1_next = arg1, arg2_next = arg2_list; arg1_next && arg2_next;
6251  arg1_next = arg1_next->next, arg2_next = arg2_next->next)
6252  {
6254  && (pt_is_attr (arg1_next) || pt_is_function_index_expression (arg1_next)))
6255  {
6256  if (tp_valid_indextype (pt_type_enum_to_db (arg2_next->type_enum)) && !pt_has_analytic (parser, arg2))
6257  {
6258  select_list = pt_get_select_list (parser, arg2);
6259  if (select_list != NULL && arg2->info.query.correlation_level == 0)
6260  {
6262 
6263  /* match 'indexable-attr op indexable-uncorr-subquery' */
6264  do_rewrite = true;
6265  }
6266  else
6267  {
6268  do_rewrite = false;
6269  break;
6270  }
6271  }
6272  else
6273  {
6274  do_rewrite = false;
6275  break;
6276  }
6277  }
6278  else
6279  {
6280  do_rewrite = false;
6281  break;
6282  }
6283  }
6284 
6285  if (do_rewrite)
6286  {
6287  /* rewrite subquery to join with derived table */
6288  switch (op_type)
6289  {
6290  case PT_EQ: /* arg1 = set_func_elements */
6291  case PT_IS_IN: /* arg1 = set_func_elements, attr */
6292  case PT_EQ_SOME: /* arg1 = attr */
6293  if (PT_IS_COLLECTION_TYPE (arg2->type_enum) && select_list
6294  && (PT_IS_FUNCTION (select_list) || PT_IS_CONST (select_list)))
6295  {
6296  /* if arg2 is collection type then select_list is rewrited to multi col */
6297  pt_select_list_to_one_col (parser, arg2, false);
6298  }
6299 
6300  /* make new derived spec and append it to FROM */
6301  if (mq_make_derived_spec (parser, node, arg2, idx, &new_spec, &new_attr) == NULL)
6302  {
6303  return NULL;
6304  }
6305 
6306  /* convert to 'attr op attr' */
6307  cnf_node->info.expr.arg1 = arg1;
6308  arg1 = arg1->next;
6309  cnf_node->info.expr.arg1->next = NULL;
6310 
6311  cnf_node->info.expr.arg2 = new_attr;
6312  saved_op_type = cnf_node->info.expr.op;
6313  cnf_node->info.expr.op = PT_EQ;
6314 
6315  if (new_attr != NULL)
6316  {
6317  new_attr = new_attr->next;
6318  cnf_node->info.expr.arg2->next = NULL;
6319  }
6320 
6321  /* save, cut-off link */
6322  save_next = cnf_node->next;
6323  cnf_node->next = NULL;
6324 
6325  /* create the following 'attr op attr' */
6326  for (tmp = NULL; arg1 && new_attr; arg1 = arg1_next, new_attr = new_attr_next)
6327  {
6328  tmp = parser_new_node (parser, PT_EXPR);
6329  if (tmp == NULL)
6330  {
6331  PT_INTERNAL_ERROR (parser, "allocate new node");
6332  return NULL;
6333  }
6334 
6335  /* save, cut-off link */
6336  arg1_next = arg1->next;
6337  arg1->next = NULL;
6338  new_attr_next = new_attr->next;
6339  new_attr->next = NULL;
6340 
6341  tmp->info.expr.arg1 = arg1;
6342  tmp->info.expr.arg2 = new_attr;
6343  tmp->info.expr.op = PT_EQ;
6344 
6345  cnf_node = parser_append_node (tmp, cnf_node);
6346  }
6347 
6348  if (tmp)
6349  { /* move to the last cnf */
6350  cnf_node = tmp;
6351  }
6352  cnf_node->next = save_next; /* restore link */
6353 
6354  /* apply qo_rewrite_subqueries() to derived table's subquery */
6355  (void) parser_walk_tree (parser, new_spec->info.spec.derived_table, qo_rewrite_subqueries, idx, NULL,
6356  NULL);
6357  break;
6358 
6359  case PT_GT_SOME: /* arg1 = attr */
6360  case PT_GE_SOME: /* arg1 = attr */
6361  case PT_LT_SOME: /* arg1 = attr */
6362  case PT_LE_SOME: /* arg1 = attr */
6363  if (arg2->node_type == PT_UNION || arg2->node_type == PT_INTERSECTION || arg2->node_type == PT_DIFFERENCE
6364  || pt_has_aggregate (parser, arg2) || arg2->info.query.orderby_for)
6365  {
6366  PT_NODE *rewritten = NULL;
6367 
6368  /* if it is composite query, rewrite to simple query */
6369  rewritten = mq_rewrite_query_as_derived (parser, arg2);
6370  if (rewritten == NULL)
6371  {
6372  return NULL;
6373  }
6374  else
6375  {
6376  /* fix list */
6377  PT_NODE_MOVE_NUMBER_OUTERLINK (rewritten, arg2);
6378  arg2 = rewritten;
6379  }
6380 
6381  /* set as uncorrelated subquery */
6384  arg2->info.query.correlation_level = 0;
6385 
6386  /* free old composite query */
6387  parser_free_tree (parser, cnf_node->info.expr.arg2);
6388  cnf_node->info.expr.arg2 = arg2;
6389  }
6390 
6391  /* make new derived spec and append it to FROM */
6392  if (mq_make_derived_spec (parser, node, arg2, idx, &new_spec, &new_attr) == NULL)
6393  {
6394  return NULL;
6395  }
6396 
6397  /* apply qo_rewrite_subqueries() to derived table's subquery */
6398  (void) parser_walk_tree (parser, new_spec->info.spec.derived_table, qo_rewrite_subqueries, idx, NULL,
6399  NULL);
6400 
6401  select_list = pt_get_select_list (parser, arg2);
6402  if (select_list == NULL)
6403  {
6404  return NULL;
6405  }
6406 
6407  /* convert select list of subquery to MIN()/MAX() */
6408  new_func = parser_new_node (parser, PT_FUNCTION);
6409  if (new_func == NULL)
6410  {
6411  PT_INTERNAL_ERROR (parser, "allocate new node");
6412  return NULL;
6413  }
6414 
6415  new_func->info.function.function_type =
6416  ((op_type == PT_GT_SOME || op_type == PT_GE_SOME) ? PT_MIN : PT_MAX);
6417  new_func->info.function.all_or_distinct = PT_ALL;
6418  new_func->info.function.arg_list = select_list;
6419  new_func->type_enum = select_list->type_enum;
6420  new_func->data_type = parser_copy_tree (parser, select_list->data_type);
6421  arg2->info.query.q.select.list = new_func;
6422  /* mark as agg select */
6424 
6425  /* convert to 'attr > new_attr' */
6426  cnf_node->info.expr.arg2 = new_attr;
6427  if (op_type == PT_GT_SOME)
6428  {
6429  cnf_node->info.expr.op = PT_GT;
6430  }
6431  else if (op_type == PT_GE_SOME)
6432  {
6433  cnf_node->info.expr.op = PT_GE;
6434  }
6435  else if (op_type == PT_LT_SOME)
6436  {
6437  cnf_node->info.expr.op = PT_LT;
6438  }
6439  else
6440  {
6441  cnf_node->info.expr.op = PT_LE;
6442  }
6443  break;
6444 
6445  default:
6446  break;
6447  }
6448  }
6449  } /* for (cnf_node = ...) */
6450 
6451  *continue_walk = PT_LIST_WALK;
6452 
6453  return node;
6454 }
6455 
6456 /*
6457  * qo_is_partition_attr () -
6458  * return:
6459  * node(in):
6460  */
6461 static int
6463 {
6464  if (node == NULL)
6465  {
6466  return 0;
6467  }
6468 
6469  node = pt_get_end_path_node (node);
6470 
6471  if (node->node_type == PT_NAME && node->info.name.meta_class == PT_NORMAL && node->info.name.spec_id)
6472  {
6473  if (node->info.name.partition)
6474  {
6475  return 1;
6476  }
6477  }
6478 
6479  return 0;
6480 }
6481 
6482 /*
6483  * qo_do_auto_parameterize () - Convert value to host variable (input marker)
6484  * return:
6485  * parser(in):
6486  * where(in): pointer to WHERE list
6487  *
6488  * Note:
6489  * examples:
6490  * WHERE a=10 AND b<20 --> WHERE a=? AND b<? w/ input host var 10, 20
6491  *
6492  */
6493 void
6495 {
6496  PT_NODE *cnf_node, *dnf_node, *between_and, *range;
6497  PT_NODE *node_prior;
6498 
6499  /* traverse CNF list */
6500  for (cnf_node = where; cnf_node; cnf_node = cnf_node->next)
6501  {
6502 
6503  /* traverse DNF list */
6504  for (dnf_node = cnf_node; dnf_node; dnf_node = dnf_node->or_next)
6505  {
6506  if (dnf_node->node_type != PT_EXPR)
6507  {
6508  /* dnf_node is not an expression node */
6509  continue;
6510  }
6511 
6513  {
6514  /* copy_pull term from select list of derived table do NOT auto_parameterize */
6515  /* because the query rewrite step is performed in the XASL generation of DELETE and UPDATE. */
6516  /* to_do: remove rewriting aptr in the XASL generation of DEL,UPD (pt_to_delete_xasl) */
6517  continue;
6518  }
6519 
6520  node_prior = pt_get_first_arg_ignore_prior (dnf_node);
6521 
6522  if (!pt_is_attr (node_prior) && !pt_is_instnum (node_prior) && !pt_is_orderbynum (node_prior))
6523  {
6524  /* neither LHS is an attribute, inst_num, nor orderby_num */
6525  continue;
6526  }
6527 
6528  switch (dnf_node->info.expr.op)
6529  {
6530  case PT_EQ:
6531  case PT_GT:
6532  case PT_GE:
6533  case PT_LT:
6534  case PT_LE:
6535  case PT_LIKE:
6536  case PT_ASSIGN:
6537  if (pt_is_const_not_hostvar (dnf_node->info.expr.arg2) && !PT_IS_NULL_NODE (dnf_node->info.expr.arg2))
6538  {
6539  dnf_node->info.expr.arg2 = pt_rewrite_to_auto_param (parser, dnf_node->info.expr.arg2);
6540  }
6541  break;
6542  case PT_BETWEEN:
6543  between_and = dnf_node->info.expr.arg2;
6544  assert (between_and->node_type == PT_EXPR);
6545  if (pt_is_const_not_hostvar (between_and->info.expr.arg1)
6546  && !PT_IS_NULL_NODE (between_and->info.expr.arg1))
6547  {
6548  between_and->info.expr.arg1 = pt_rewrite_to_auto_param (parser, between_and->info.expr.arg1);
6549  }
6550  if (pt_is_const_not_hostvar (between_and->info.expr.arg2)
6551  && !PT_IS_NULL_NODE (between_and->info.expr.arg2))
6552  {
6553  between_and->info.expr.arg2 = pt_rewrite_to_auto_param (parser, between_and->info.expr.arg2);
6554  }
6555  break;
6556  case PT_RANGE:
6557  for (range = dnf_node->info.expr.arg2; range; range = range->or_next)
6558  {
6561  {
6562  range->info.expr.arg1 = pt_rewrite_to_auto_param (parser, range->info.expr.arg1);
6563  }
6566  {
6567  range->info.expr.arg2 = pt_rewrite_to_auto_param (parser, range->info.expr.arg2);
6568  }
6569  }
6570  break;
6571  default:
6572  /* Is any other expression type possible to be auto-parameterized? */
6573  break;
6574  }
6575  }
6576  }
6577 
6578 }
6579 
6580 /*
6581  * qo_can_generate_single_table_connect_by () - checks a SELECT ... CONNECT BY
6582  * query for single-table
6583  * optimizations
6584  * return: whether single-table optimization can be performed
6585  * parser(in): parser environment
6586  * node(in): SELECT ... CONNECT BY query
6587  * Note: The single-table optimizations (potentially using indexes for table
6588  * access in START WITH and CONNECT BY predicates) can be performed if
6589  * the query does not involve joins or partitioned tables.
6590  */
6591 static bool
6593 {
6594  int level = 0;
6595  PT_NODE *name = NULL;
6596  PT_NODE *spec = NULL;
6597  PT_NODE *select = NULL;
6598 
6599  assert (node->node_type == PT_SELECT && node->info.query.q.select.connect_by != NULL);
6600 
6601  spec = node->info.query.q.select.from;
6602 
6603  if (node->info.query.q.select.where || spec->next)
6604  {
6605  /* joins */
6606  return false;
6607  }
6608 
6609  select = node->info.query.q.select.list;
6610 
6611  while (select != NULL)
6612  {
6613  if (select->node_type == PT_METHOD_CALL)
6614  {
6615  /* method call can be rewritten as subquery later. */
6616  return false;
6617  }
6618  select = select->next;
6619  }
6620 
6622  if (!OPTIMIZATION_ENABLED (level))
6623  {
6624  return false;
6625  }
6626 
6627  assert (spec->next == NULL);
6628  if (spec->node_type != PT_SPEC)
6629  {
6630  assert (false);
6631  return false;
6632  }
6633 
6634  if (spec->info.spec.only_all != PT_ONLY)
6635  {
6636  /* class hierarchy */
6637  return false;
6638  }
6639 
6640  name = spec->info.spec.entity_name;
6641  if (name == NULL)
6642  {
6643  return false;
6644  }
6645  assert (name->node_type == PT_NAME);
6646  if (name == NULL || name->node_type != PT_NAME)
6647  {
6648  assert (false);
6649  return false;
6650  }
6651 
6652  if (sm_is_partitioned_class (name->info.name.db_object) > 0)
6653  {
6654  return false;
6655  }
6656  return true;
6657 }
6658 
6659 
6660 /*
6661  * qo_move_on_clause_of_explicit_join_to_where_clause () - move on clause of explicit join to where clause
6662  * return: void
6663  * parser(in): parser environment
6664  * fromp(in/out): &from of SELECT, &spec of UPDATE/DELETE
6665  * wherep(in/out): &where of SELECT/UPDATE/DELETE
6666  *
6667  * NOTE: It moves on clause of explicit join for SELECT/UPDATE/DELETE to where clase for temporary purpose.
6668  * qo_optimize_queries_post will restore them after several optimizations, for instance, range merge/intersection,
6669  * auto-parameterization.
6670  *
6671  */
6672 static void
6674 {
6675  PT_NODE *t_node, *spec;
6676 
6677  t_node = *wherep;
6678  while (t_node != NULL && t_node->next != NULL)
6679  {
6680  t_node = t_node->next;
6681  }
6682 
6683  for (spec = *fromp; spec != NULL; spec = spec->next)
6684  {
6685  if (spec->node_type == PT_SPEC && spec->info.spec.on_cond != NULL)
6686  {
6687  if (t_node == NULL)
6688  {
6689  t_node = *wherep = spec->info.spec.on_cond;
6690  }
6691  else
6692  {
6693  t_node->next = spec->info.spec.on_cond;
6694  }
6695 
6696  spec->info.spec.on_cond = NULL;
6697 
6698  while (t_node->next != NULL)
6699  {
6700  t_node = t_node->next;
6701  }
6702  }
6703  }
6704 }
6705 
6706 /*
6707  * qo_optimize_queries () - checks all subqueries for rewrite optimizations
6708  * return: PT_NODE *
6709  * parser(in): parser environment
6710  * node(in): possible query
6711  * arg(in):
6712  * continue_walk(in):
6713  */
6714 static PT_NODE *
6715 qo_optimize_queries (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk)
6716 {
6717  int level, seqno = 0;
6718  PT_NODE *next, *pred, **wherep, **havingp, *dummy;
6719  PT_NODE *spec, *derived_table;
6720  PT_NODE **startwithp, **connectbyp, **aftercbfilterp;
6721  PT_NODE *limit, *derived;
6722  PT_NODE **merge_upd_wherep, **merge_ins_wherep, **merge_del_wherep;
6723  PT_NODE **orderby_for_p;
6724  PT_NODE **show_argp;
6725  bool call_auto_parameterize = false;
6726 
6727  dummy = NULL;
6728  wherep = havingp = startwithp = connectbyp = aftercbfilterp = &dummy;
6729  merge_upd_wherep = merge_ins_wherep = merge_del_wherep = &dummy;
6730  orderby_for_p = &dummy;
6731  show_argp = &dummy;
6732 
6733  switch (node->node_type)
6734  {
6735  case PT_SELECT:
6736  /* HQ sub-query might be optimized twice in UPDATE statement because UPDATE statement internally creates SELECT
6737  * statement to get targets to update. We should check whether it was already single-table-optimized. Here is an
6738  * example: CREATE TABLE t(p INT, c INT, x INT); INSERT INTO t VALUES(1, 11, 0), (1, 12, 0), (2, 21, 0); UPDATE t
6739  * SET x=0 WHERE c IN (SELECT c FROM t START WITH p=1 CONNECT BY PRIOR c=p); */
6740  if (node->info.query.q.select.connect_by != NULL
6742  {
6743  PT_NODE *join_part = NULL;
6744  PT_NODE *after_connectby_filter_part = NULL;
6745 
6746  /* We need to separate the join predicates before we perform rewriting and optimizations so that they don't
6747  * get mixed up with the filtering predicates (to be applied after connect by). */
6748  pt_split_join_preds (parser, node->info.query.q.select.where, &join_part, &after_connectby_filter_part);
6749 
6750  node->info.query.q.select.where = join_part;
6752  node->info.query.q.select.after_cb_filter = after_connectby_filter_part;
6753 
6754  /* if we have no joins prepare for using heap scans/index scans for start with list and connect by processing */
6755  if (qo_can_generate_single_table_connect_by (parser, node))
6756  {
6757  node->info.query.q.select.where = node->info.query.q.select.start_with;
6758  node->info.query.q.select.start_with = NULL;
6759  node->info.query.q.select.single_table_opt = 1;
6760  }
6761  }
6762 
6763  /* Put all join conditions together with WHERE clause for rewrite optimization. But we can distinguish a join
6764  * condition from each other and from WHERE clause by location information that were marked at 'pt_bind_names()'.
6765  * We'll recover the parse tree of join conditions using the location information in shortly. */
6767  &node->info.query.q.select.where);
6768 
6769  wherep = &node->info.query.q.select.where;
6770  havingp = &node->info.query.q.select.having;
6771  if (node->info.query.q.select.start_with)
6772  {
6773  startwithp = &node->info.query.q.select.start_with;
6774  }
6775  if (node->info.query.q.select.connect_by)
6776  {
6777  connectbyp = &node->info.query.q.select.connect_by;
6778  }
6779  if (node->info.query.q.select.after_cb_filter)
6780  {
6781  aftercbfilterp = &node->info.query.q.select.after_cb_filter;
6782  }
6783  spec = node->info.query.q.select.from;
6784  if (spec != NULL && spec->info.spec.derived_table_type == PT_IS_SHOWSTMT
6785  && (derived_table = spec->info.spec.derived_table) != NULL && derived_table->node_type == PT_SHOWSTMT)
6786  {
6787  show_argp = &derived_table->info.showstmt.show_args;
6788  }
6789  orderby_for_p = &node->info.query.orderby_for;
6790  qo_rewrite_index_hints (parser, node);
6791  break;
6792 
6793  case PT_UPDATE:
6795  &node->info.update.search_cond);
6796 
6797  wherep = &node->info.update.search_cond;
6798  orderby_for_p = &node->info.update.orderby_for;
6799  qo_rewrite_index_hints (parser, node);
6800  break;
6801 
6802  case PT_DELETE:
6804  &node->info.delete_.search_cond);
6805 
6806  wherep = &node->info.delete_.search_cond;
6807  qo_rewrite_index_hints (parser, node);
6808  break;
6809 
6810  case PT_INSERT:
6811  {
6812  PT_NODE *const subquery_ptr = pt_get_subquery_of_insert_select (node);
6813 
6814  if (subquery_ptr == NULL || subquery_ptr->node_type != PT_SELECT)
6815  {
6816  return node;
6817  }
6818  wherep = &subquery_ptr->info.query.q.select.where;
6819  }
6820  break;
6821 
6822  case PT_MERGE:
6823  wherep = &node->info.merge.search_cond;
6824  merge_upd_wherep = &node->info.merge.update.search_cond;
6825  merge_ins_wherep = &node->info.merge.insert.search_cond;
6826  merge_del_wherep = &node->info.merge.update.del_search_cond;
6827  break;
6828 
6829  case PT_UNION:
6830  case PT_DIFFERENCE:
6831  case PT_INTERSECTION:
6834 
6835  /* If LIMIT clause is specified without ORDER BY clause, we will rewrite the UNION query as derived. For example,
6836  * (SELECT ...) UNION (SELECT ...) LIMIT 10 will be rewritten to: SELECT * FROM ((SELECT ...) UNION (SELECT ...))
6837  * T WHERE INST_NUM() <= 10 */
6838  if (node->info.query.limit && node->info.query.flag.rewrite_limit)
6839  {
6840  limit = pt_limit_to_numbering_expr (parser, node->info.query.limit, PT_INST_NUM, false);
6841  if (limit != NULL)
6842  {
6843  PT_NODE *limit_node;
6844  bool single_tuple_bak;
6845 
6846  node->info.query.flag.rewrite_limit = 0;
6847 
6848  /* to move limit clause to derived */
6849  limit_node = node->info.query.limit;
6850  node->info.query.limit = NULL;
6851 
6852  /* to move single tuple to derived */
6853  single_tuple_bak = node->info.query.flag.single_tuple;
6854  node->info.query.flag.single_tuple = false;
6855 
6856  derived = mq_rewrite_query_as_derived (parser, node);
6857  if (derived != NULL)
6858  {
6859  PT_NODE_MOVE_NUMBER_OUTERLINK (derived, node);
6860 
6861  assert (derived->info.query.q.select.where == NULL);
6862  derived->info.query.q.select.where = limit;
6863 
6864  wherep = &derived->info.query.q.select.where;
6865 
6866  node = derived;
6867  }
6868  node->info.query.flag.single_tuple = single_tuple_bak;
6869  node->info.query.limit = limit_node;
6870  }
6871  }
6872 
6873  orderby_for_p = &node->info.query.orderby_for;
6874  break;
6875 
6876  case PT_EXPR:
6877  switch (node->info.expr.op)
6878  {
6879  case PT_EQ:
6880  case PT_NE:
6881  case PT_NULLSAFE_EQ:
6882  node->info.expr.arg1 = qo_rewrite_hidden_col_as_derived (parser, node->info.expr.arg1, node);
6883  /* fall through */
6884 
6885  /* keep out hidden column subquery from UPDATE assignment */
6886  case PT_ASSIGN:
6887  /* quantified comparisons */
6888  case PT_GE_SOME:
6889  case PT_GT_SOME:
6890  case PT_LT_SOME:
6891  case PT_LE_SOME:
6892  case PT_GE_ALL:
6893  case PT_GT_ALL:
6894  case PT_LT_ALL:
6895  case PT_LE_ALL:
6896  /* quantified equality comparisons */
6897  case PT_EQ_SOME:
6898  case PT_NE_SOME:
6899  case PT_EQ_ALL:
6900  case PT_NE_ALL:
6901  case PT_IS_IN:
6902  case PT_IS_NOT_IN:
6903  node->info.expr.arg2 = qo_rewrite_hidden_col_as_derived (parser, node->info.expr.arg2, node);
6904  break;
6905  default:
6906  break;
6907  }
6908  /* no WHERE clause */
6909  return node;
6910 
6911  case PT_FUNCTION:
6912  switch (node->info.function.function_type)
6913  {
6914  case F_TABLE_SET:
6915  case F_TABLE_MULTISET:
6916  case F_TABLE_SEQUENCE:
6918  break;
6919  default:
6920  break;
6921  }
6922  /* no WHERE clause */
6923  return node;
6924 
6925  default:
6926  /* no WHERE clause */
6927  return node;
6928  }
6929 
6930  if (node->node_type == PT_SELECT)
6931  {
6932  /* analyze paths for possible optimizations */
6933  node->info.query.q.select.from =
6935  node->info.query.q.select.where);
6936  }
6937 
6939  if (OPTIMIZATION_ENABLED (level))
6940  {
6941 
6942  if (node->node_type == PT_SELECT)
6943  {
6944  int continue_walk;
6945  int idx = 0;
6946 
6947  /* rewrite uncorrelated subquery to join query */
6948  qo_rewrite_subqueries (parser, node, &idx, &continue_walk);
6949  }
6950 
6951  /* rewrite optimization on WHERE, HAVING clause */
6952 
6953  if (!*wherep && !*havingp && !*aftercbfilterp && !*startwithp && !*connectbyp && !*merge_upd_wherep
6954  && !*merge_ins_wherep && !*merge_del_wherep && !*orderby_for_p && !*show_argp)
6955  {
6956  if (node->node_type != PT_SELECT)
6957  {
6958  return node;
6959  }
6960  else
6961  {
6962  /* check for group by, order by */
6963  if (node->info.query.q.select.group_by == NULL && node->info.query.order_by == NULL)
6964  {
6965  return node;
6966  } /* else - go ahead */
6967  }
6968  }
6969 
6970  /* convert to CNF and tag taggable terms */
6971  if (*wherep)
6972  {
6973  *wherep = pt_cnf (parser, *wherep);
6974  }
6975  if (*havingp)
6976  {
6977  *havingp = pt_cnf (parser, *havingp);
6978  }
6979  if (*startwithp)
6980  {
6981  *startwithp = pt_cnf (parser, *startwithp);
6982  }
6983  if (*connectbyp)
6984  {
6985  *connectbyp = pt_cnf (parser, *connectbyp);
6986  }
6987  if (*aftercbfilterp)
6988  {
6989  *aftercbfilterp = pt_cnf (parser, *aftercbfilterp);
6990  }
6991  if (*merge_upd_wherep)
6992  {
6993  *merge_upd_wherep = pt_cnf (parser, *merge_upd_wherep);
6994  }
6995  if (*merge_ins_wherep)
6996  {
6997  *merge_ins_wherep = pt_cnf (parser, *merge_ins_wherep);
6998  }
6999  if (*merge_del_wherep)
7000  {
7001  *merge_del_wherep = pt_cnf (parser, *merge_del_wherep);
7002  }
7003  if (*orderby_for_p)
7004  {
7005  *orderby_for_p = pt_cnf (parser, *orderby_for_p);
7006  }
7007 
7008  /* in HAVING clause with GROUP BY, move non-aggregate terms to WHERE clause */
7009  if (PT_IS_SELECT (node) && node->info.query.q.select.group_by && *havingp)
7010  {
7011  PT_NODE *prev, *cnf, *next;
7012  PT_NON_GROUPBY_COL_INFO col_info;
7013  PT_AGG_FIND_INFO info;
7014  int has_pseudocolumn;
7015  bool can_move;
7016 
7017  col_info.groupby = node->info.query.q.select.group_by;
7018 
7019  prev = NULL; /* init */
7020  for (cnf = *havingp; cnf; cnf = next)
7021  {
7022  next = cnf->next; /* save and cut-off link */
7023  cnf->next = NULL;
7024 
7025  col_info.has_non_groupby_col = false; /* on the supposition */
7026  (void) parser_walk_tree (parser, cnf, pt_has_non_groupby_column_node, &col_info, NULL, NULL);
7027  can_move = (col_info.has_non_groupby_col == false);
7028 
7029  if (can_move)
7030  {
7031  /* init agg info */
7032  info.stop_on_subquery = false;
7033  info.out_of_context_count = 0;
7034  info.base_count = 0;
7035  info.select_stack = pt_pointer_stack_push (parser, NULL, node);
7036 
7037  /* search for aggregate of this select */
7038  (void) parser_walk_tree (parser, cnf, pt_find_aggregate_functions_pre, &info,
7040  can_move = (info.base_count == 0);
7041 
7042  /* cleanup */
7043  info.select_stack = pt_pointer_stack_pop (parser, info.select_stack, NULL);
7044  }
7045 
7046  /* Note: Do not move the cnf node if it contains a pseudo-column! */
7047  if (can_move)
7048  {
7049  has_pseudocolumn = 0;
7050  (void) parser_walk_tree (parser, cnf, pt_is_pseudocolumn_node, &has_pseudocolumn, NULL, NULL);
7051  if (has_pseudocolumn)
7052  {
7053  can_move = false;
7054  }
7055  }
7056 
7057  /* Not found aggregate function in cnf node and no ROLLUP clause. So, move it from HAVING clause to WHERE
7058  * clause. */
7059  if (can_move && !node->info.query.q.select.group_by->flag.with_rollup)
7060  {
7061  /* delete cnf node from HAVING clause */
7062  if (!prev)
7063  { /* very the first node */
7064  *havingp = next;
7065  }
7066  else
7067  {
7068  prev->next = next;
7069  }
7070 
7071  /* add cnf node to WHERE clause */
7072  *wherep = parser_append_node (*wherep, cnf);
7073  }
7074  else
7075  { /* do nothing and go ahead */
7076  cnf->next = next; /* restore link */
7077  prev = cnf; /* save previous */
7078  }
7079  }
7080  }
7081 
7082  /* reduce equality terms */
7083  if (*wherep)
7084  {
7085  qo_reduce_equality_terms (parser, node, wherep);
7086  }
7087  if (*havingp)
7088  {
7089  qo_reduce_equality_terms (parser, node, havingp);
7090  }
7091 
7092  /* we don't reduce equality terms for startwith and connectby. This optimization for every A after a statement
7093  * like A = 5, replaced the column with the scalar 5. If the column is in an ORDER BY clause, the sorting may not
7094  * occur on column A because it's always 5. This behavior is incorrect when running a hierarchical query because
7095  * there may be a A = 5 in the START WITH part or CONNECT BY part but the ORDER BY on A should sort all elements
7096  * from all levels, column A being different. */
7097  if (*aftercbfilterp)
7098  {
7099  qo_reduce_equality_terms (parser, node, aftercbfilterp);
7100  }
7101  if (*merge_upd_wherep)
7102  {
7103  qo_reduce_equality_terms (parser, node, merge_upd_wherep);
7104  }
7105  if (*merge_ins_wherep)
7106  {
7107  qo_reduce_equality_terms (parser, node, merge_ins_wherep);
7108  }
7109  if (*merge_del_wherep)
7110  {
7111  qo_reduce_equality_terms (parser, node, merge_del_wherep);
7112  }
7113 
7114  /* convert terms of the form 'const op attr' to 'attr op const' */
7115  if (*wherep)
7116  {
7117  qo_converse_sarg_terms (parser, *wherep);
7118  }
7119  if (*havingp)
7120  {
7121  qo_converse_sarg_terms (parser, *havingp);
7122  }
7123  if (*startwithp)
7124  {
7125  qo_converse_sarg_terms (parser, *startwithp);
7126  }
7127  if (*connectbyp)
7128  {
7129  qo_converse_sarg_terms (parser, *connectbyp);
7130  }
7131  if (*aftercbfilterp)
7132  {
7133  qo_converse_sarg_terms (parser, *aftercbfilterp);
7134  }
7135  if (*merge_upd_wherep)
7136  {
7137  qo_converse_sarg_terms (parser, *merge_upd_wherep);
7138  }
7139  if (*merge_ins_wherep)
7140  {
7141  qo_converse_sarg_terms (parser, *merge_ins_wherep);
7142  }
7143  if (*merge_del_wherep)
7144  {
7145  qo_converse_sarg_terms (parser, *merge_del_wherep);
7146  }
7147 
7148  /* reduce a pair of comparison terms into one BETWEEN term */
7149  if (*wherep)
7150  {
7151  qo_reduce_comp_pair_terms (parser, wherep);
7152  }
7153  if (*havingp)
7154  {
7155  qo_reduce_comp_pair_terms (parser, havingp);
7156  }
7157  if (*startwithp)
7158  {
7159  qo_reduce_comp_pair_terms (parser, startwithp);
7160  }
7161  if (*connectbyp)
7162  {
7163  qo_reduce_comp_pair_terms (parser, connectbyp);
7164  }
7165  if (*aftercbfilterp)
7166  {
7167  qo_reduce_comp_pair_terms (parser, aftercbfilterp);
7168  }
7169  if (*merge_upd_wherep)
7170  {
7171  qo_reduce_comp_pair_terms (parser, merge_upd_wherep);
7172  }
7173  if (*merge_ins_wherep)
7174  {
7175  qo_reduce_comp_pair_terms (parser, merge_ins_wherep);
7176  }
7177  if (*merge_del_wherep)
7178  {
7179  qo_reduce_comp_pair_terms (parser, merge_del_wherep);
7180  }
7181 
7182  /* convert a leftmost LIKE term to a BETWEEN (GE_LT) term */
7183  if (*wherep)
7184  {
7185  qo_rewrite_like_terms (parser, wherep);
7186  }
7187  if (*havingp)
7188  {
7189  qo_rewrite_like_terms (parser, havingp);
7190  }
7191  if (*startwithp)
7192  {
7193  qo_rewrite_like_terms (parser, startwithp);
7194  }
7195  if (*connectbyp)
7196  {
7197  qo_rewrite_like_terms (parser, connectbyp);
7198  }
7199  if (*aftercbfilterp)
7200  {
7201  qo_rewrite_like_terms (parser, aftercbfilterp);
7202  }
7203  if (*merge_upd_wherep)
7204  {
7205  qo_rewrite_like_terms (parser, merge_upd_wherep);
7206  }
7207  if (*merge_ins_wherep)
7208  {
7209  qo_rewrite_like_terms (parser, merge_ins_wherep);
7210  }
7211  if (*merge_del_wherep)
7212  {
7213  qo_rewrite_like_terms (parser, merge_del_wherep);
7214  }
7215 
7216  /* convert comparison terms to RANGE */
7217  if (*wherep)
7218  {
7219  qo_convert_to_range (parser, wherep);
7220  }
7221  if (*havingp)
7222  {
7223  qo_convert_to_range (parser, havingp);
7224  }
7225  if (*startwithp)
7226  {
7227  qo_convert_to_range (parser, startwithp);
7228  }
7229  if (*connectbyp)
7230  {
7231  qo_convert_to_range (parser, connectbyp);
7232  }
7233  if (*aftercbfilterp)
7234  {
7235  qo_convert_to_range (parser, aftercbfilterp);
7236  }
7237  if (*merge_upd_wherep)
7238  {
7239  qo_convert_to_range (parser, merge_upd_wherep);
7240  }
7241  if (*merge_ins_wherep)
7242  {
7243  qo_convert_to_range (parser, merge_ins_wherep);
7244  }
7245  if (*merge_del_wherep)
7246  {
7247  qo_convert_to_range (parser, merge_del_wherep);
7248  }
7249 
7250  /* narrow search range by applying range intersection */
7251  if (*wherep)
7252  {
7253  qo_apply_range_intersection (parser, wherep);
7254  }
7255  if (*havingp)
7256  {
7257  qo_apply_range_intersection (parser, havingp);
7258  }
7259  if (*startwithp)
7260  {
7261  qo_apply_range_intersection (parser, startwithp);
7262  }
7263  if (*connectbyp)
7264  {
7265  qo_apply_range_intersection (parser, connectbyp);
7266  }
7267  if (*aftercbfilterp)
7268  {
7269  qo_apply_range_intersection (parser, aftercbfilterp);
7270  }
7271  if (*merge_upd_wherep)
7272  {
7273  qo_apply_range_intersection (parser, merge_upd_wherep);
7274  }
7275  if (*merge_ins_wherep)
7276  {
7277  qo_apply_range_intersection (parser, merge_ins_wherep);
7278  }
7279  if (*merge_del_wherep)
7280  {
7281  qo_apply_range_intersection (parser, merge_del_wherep);
7282  }
7283 
7284  /* remove meaningless IS NULL/IS NOT NULL terms */
7285  if (*wherep)
7286  {
7287  qo_fold_is_and_not_null (parser, wherep);
7288  }
7289  if (*havingp)
7290  {
7291  qo_fold_is_and_not_null (parser, havingp);
7292  }
7293  if (*startwithp)
7294  {
7295  qo_fold_is_and_not_null (parser, startwithp);
7296  }
7297  if (*connectbyp)
7298  {
7299  qo_fold_is_and_not_null (parser, connectbyp);
7300  }
7301  if (*aftercbfilterp)
7302  {
7303  qo_fold_is_and_not_null (parser, aftercbfilterp);
7304  }
7305  if (*merge_upd_wherep)
7306  {
7307  qo_fold_is_and_not_null (parser, merge_upd_wherep);
7308  }
7309  if (*merge_ins_wherep)
7310  {
7311  qo_fold_is_and_not_null (parser, merge_ins_wherep);
7312  }
7313  if (*merge_del_wherep)
7314  {
7315  qo_fold_is_and_not_null (parser, merge_del_wherep);
7316  }
7317 
7318  if (node->node_type == PT_SELECT)
7319  {
7320  int continue_walk;
7321 
7322  /* rewrite outer join to inner join */
7323  qo_rewrite_outerjoin (parser, node, NULL, &continue_walk);
7324 
7325  /* rewrite explicit inner join to implicit inner join */
7326  qo_rewrite_innerjoin (parser, node, NULL, &continue_walk);
7327 
7328  pred = qo_get_next_oid_pred (*wherep);
7329  if (pred)
7330  {
7331  while (pred)
7332  {
7333  next = pred->next;
7334  node = qo_rewrite_oid_equality (parser, node, pred, &seqno);
7335  assert_release (node != NULL);
7336  if (node == NULL)
7337  {
7338  return NULL;
7339  }
7340 
7341  pred = qo_get_next_oid_pred (next);
7342  } /* while (pred) */
7343 
7344  /* re-analyze paths for possible optimizations */
7345  node->info.query.q.select.from =
7348  } /* if (pred) */
7349 
7350  if (qo_reduce_order_by (parser, node) != NO_ERROR)
7351  {
7352  return node; /* give up */
7353  }
7354  }
7355 
7356  /* auto-parameterization is safe when it is done as the last step of rewrite optimization */
7359  {
7360  call_auto_parameterize = true;
7361  }
7362  }
7363 
7364  /* auto-parameterize convert value in expression to host variable (input marker) */
7365  if (*wherep && (call_auto_parameterize || (*wherep)->flag.force_auto_parameterize))
7366  {
7367  qo_do_auto_parameterize (parser, *wherep);
7368  }
7369 
7370  if (*havingp && call_auto_parameterize)
7371  {
7372  qo_do_auto_parameterize (parser, *havingp);
7373  }
7374 
7375  if (*startwithp && call_auto_parameterize)
7376  {
7377  qo_do_auto_parameterize (parser, *startwithp);
7378  }
7379 
7380  if (*connectbyp && call_auto_parameterize)
7381  {
7382  qo_do_auto_parameterize (parser, *connectbyp);
7383  }
7384 
7385  if (*aftercbfilterp && call_auto_parameterize)
7386  {
7387  qo_do_auto_parameterize (parser, *aftercbfilterp);
7388  }
7389 
7390  if (*merge_upd_wherep && (call_auto_parameterize || (*merge_upd_wherep)->flag.force_auto_parameterize))
7391  {
7392  qo_do_auto_parameterize (parser, *merge_upd_wherep);
7393  }
7394 
7395  if (*merge_ins_wherep && call_auto_parameterize)
7396  {
7397  qo_do_auto_parameterize (parser, *merge_ins_wherep);
7398  }
7399 
7400  if (*merge_del_wherep && call_auto_parameterize)
7401  {
7402  qo_do_auto_parameterize (parser, *merge_del_wherep);
7403  }
7404 
7405  if (*orderby_for_p && call_auto_parameterize)
7406  {
7407  qo_do_auto_parameterize (parser, *orderby_for_p);
7408  }
7409 
7410  if (node->node_type == PT_UPDATE && call_auto_parameterize)
7411  {
7413  }
7414 
7415  if (pt_is_const_not_hostvar (*show_argp))
7416  {
7417  PT_NODE *p = *show_argp;
7418  PT_NODE *result_list = NULL;
7419  PT_NODE *one_rewrited;
7420  PT_NODE *save;
7421 
7422  while (p)
7423  {
7424  save = p->next;
7425  p->next = NULL;
7426  one_rewrited = pt_rewrite_to_auto_param (parser, p);
7427  p = save;
7428 
7429  result_list = parser_append_node (one_rewrited, result_list);
7430  }
7431  *show_argp = result_list;
7432  }
7433 
7434  /* auto parameterize for limit clause */
7435  if (PT_IS_QUERY_NODE_TYPE (node->node_type) || node->node_type == PT_UPDATE || node->node_type == PT_DELETE)
7436  {
7437  qo_do_auto_parameterize_limit_clause (parser, node);
7438 
7439  /* auto parameterize for keylimit clause */
7440  if (node->node_type == PT_SELECT || node->node_type == PT_UPDATE || node->node_type == PT_DELETE)
7441  {
7443  }
7444  }
7445 
7446  if (node->node_type == PT_SELECT)
7447  {
7448  if (node->info.query.is_subquery == PT_IS_SUBQUERY)
7449  {
7450  if (node->info.query.flag.single_tuple == 1)
7451  {
7452  node = qo_rewrite_hidden_col_as_derived (parser, node, NULL);
7453  }
7454  }
7455  }
7456 
7457  return node;
7458 }
7459 
7460 static void
7462 {
7463  PT_NODE *limit_offsetp, *limit_row_countp;
7464  PT_NODE *new_limit_offsetp, *new_limit_row_countp;
7465 
7466  if (node == NULL)
7467  {
7468  return;
7469  }
7470 
7471  limit_offsetp = NULL;
7472  limit_row_countp = NULL;
7473 
7474  switch (node->node_type)
7475  {
7476  case PT_UNION:
7477  case PT_DIFFERENCE:
7478  case PT_INTERSECTION:
7479  case PT_SELECT:
7480  if (node->info.query.limit == NULL)
7481  {
7482  return;
7483  }
7484 
7485  if (node->info.query.limit->next != NULL)
7486  {
7487  limit_offsetp = node->info.query.limit;
7488  limit_row_countp = node->info.query.limit->next;
7489  limit_offsetp->next = NULL; /* cut */
7490  }
7491  else
7492  {
7493  limit_offsetp = NULL;
7494  limit_row_countp = node->info.query.limit;
7495  }
7496  break;
7497 
7498  case PT_UPDATE:
7499  if (node->info.update.limit == NULL)
7500  {
7501  return;
7502  }
7503 
7504  if (node->info.update.limit->next != NULL)
7505  {
7506  limit_offsetp = node->info.update.limit;
7507  limit_row_countp = node->info.update.limit->next;
7508  limit_offsetp->next = NULL; /* cut */
7509  }
7510  else
7511  {
7512  limit_offsetp = NULL;
7513  limit_row_countp = node->info.update.limit;
7514  }
7515  break;
7516 
7517  case PT_DELETE:
7518  if (node->info.delete_.limit == NULL)
7519  {
7520  return;
7521  }
7522 
7523  if (node->info.delete_.limit->next != NULL)
7524  {
7525  limit_offsetp = node->info.delete_.limit;
7526  limit_row_countp = node->info.delete_.limit->next;
7527  limit_offsetp->next = NULL; /* cut */
7528  }
7529  else
7530  {
7531  limit_offsetp = NULL;
7532  limit_row_countp = node->info.delete_.limit;
7533  }
7534  break;
7535 
7536  default:
7537  return;
7538  }
7539 
7540  new_limit_offsetp = limit_offsetp;
7541  if (limit_offsetp != NULL && !PT_IS_NULL_NODE (limit_offsetp))
7542  {
7543  if (pt_is_const_not_hostvar (limit_offsetp))
7544  {
7545  new_limit_offsetp = pt_rewrite_to_auto_param (parser, limit_offsetp);
7546  }
7547 #if 0
7548  else if (PT_IS_EXPR_NODE (limit_offsetp))
7549  {
7550  /* We may optimize to auto parameterize expressions in limit clause. However, I don't think it is practical.
7551  * Full constant expressions, e.g, (0+2) is folded as constant and eventually parameterized as a hostvar.
7552  * Expressions which include a const would be mixed use of a constant and a hostvar, e.g, (0+?).
7553  * If you really want to optimize this case too, you can add a function to parameterize an expression node.
7554  */
7555  }
7556 #endif
7557  }
7558 
7559  new_limit_row_countp = limit_row_countp;
7560  if (limit_row_countp != NULL && !PT_IS_NULL_NODE (limit_row_countp))
7561  {
7562  if (pt_is_const_not_hostvar (limit_row_countp))
7563  {
7564  new_limit_row_countp = pt_rewrite_to_auto_param (parser, limit_row_countp);
7565  }
7566 #if 0
7567  else if (PT_IS_EXPR_NODE (limit_row_countp))
7568  {
7569  /* We may optimize to auto parameterize expressions in limit clause. However, I don't think it is practical.
7570  * Full constant expressions, e.g, (0+2) is folded as constant and eventually parameterized as a hostvar.
7571  * Expressions which include a const would be mixed use of a constant and a hostvar, e.g, (0+?).
7572  * If you really want to optimize this case too, you can add a function to parameterize an expression node.
7573  */
7574  }
7575 #endif
7576  }
7577 
7578  switch (node->node_type)
7579  {
7580  case PT_UPDATE:
7581  if (limit_offsetp != NULL)
7582  {
7583  node->info.update.limit = new_limit_offsetp;
7584  node->info.update.limit->next = new_limit_row_countp;
7585  }
7586  else
7587  {
7588  node->info.update.limit = new_limit_row_countp;
7589  node->info.update.limit->next = NULL;
7590  }
7591  break;
7592  case PT_DELETE:
7593  if (limit_offsetp != NULL)
7594  {
7595  node->info.delete_.limit = new_limit_offsetp;
7596  node->info.delete_.limit->next = new_limit_row_countp;
7597  }
7598  else
7599  {
7600  node->info.delete_.limit = new_limit_row_countp;
7601  node->info.delete_.limit->next = NULL;
7602  }
7603  break;
7604  default:
7605  if (limit_offsetp != NULL)
7606  {
7607  node->info.query.limit = new_limit_offsetp;
7608  node->info.query.limit->next = new_limit_row_countp;
7609  }
7610  else
7611  {
7612  node->info.query.limit = new_limit_row_countp;
7613  node->info.query.limit->next = NULL;
7614  }
7615  break;
7616  }
7617 }
7618 
7619 static void
7621 {
7622  PT_NODE *using_index = NULL;
7623  PT_NODE *key_limit_lower_boundp, *key_limit_upper_boundp;
7624 
7625  if (node == NULL)
7626  {
7627  return;
7628  }
7629 
7630  switch (node->node_type)
7631  {
7632  case PT_SELECT:
7633  using_index = node->info.query.q.select.using_index;
7634  break;
7635 
7636  case PT_UPDATE:
7637  using_index = node->info.update.using_index;
7638  break;
7639 
7640  case PT_DELETE:
7641  using_index = node->info.delete_.using_index;
7642  break;
7643 
7644  default:
7645  return;
7646  }
7647 
7648  while (using_index != NULL)
7649  {
7650  /* it may include keylimit clause */
7651 
7652  key_limit_lower_boundp = key_limit_upper_boundp = NULL;
7653 
7654  if (using_index->info.name.indx_key_limit != NULL)
7655  {
7656  key_limit_upper_boundp = using_index->info.name.indx_key_limit;
7657  key_limit_lower_boundp = using_index->info.name.indx_key_limit->next;
7658 
7659  using_index->info.name.indx_key_limit->next = NULL;
7660  }
7661 
7662  if (key_limit_upper_boundp != NULL)
7663  {
7664  if (pt_is_const_not_hostvar (key_limit_upper_boundp) && !PT_IS_NULL_NODE (key_limit_upper_boundp))
7665  {
7666  using_index->info.name.indx_key_limit = pt_rewrite_to_auto_param (parser, key_limit_upper_boundp);
7667  }
7668  else
7669  {
7670  using_index->info.name.indx_key_limit = key_limit_upper_boundp;
7671  }
7672  }
7673 
7674  if (key_limit_lower_boundp != NULL)
7675  {
7676  if (pt_is_const_not_hostvar (key_limit_lower_boundp) && !PT_IS_NULL_NODE (key_limit_lower_boundp))
7677  {
7678  using_index->info.name.indx_key_limit->next = pt_rewrite_to_auto_param (parser, key_limit_lower_boundp);
7679  }
7680  else
7681  {
7682  using_index->info.name.indx_key_limit->next = key_limit_lower_boundp;
7683  }
7684  }
7685 
7686  using_index = using_index->next;
7687  }
7688 }
7689 
7690 /*
7691  * qo_optimize_queries_post () -
7692  * return:
7693  * parser(in):
7694  * tree(in):
7695  * arg(in):
7696  * continue_walk(in):
7697  * NOTE: see qo_move_on_clause_of_explicit_join_to_where_clause
7698  */
7699 static PT_NODE *
7700 qo_optimize_queries_post (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *continue_walk)
7701 {
7702  PT_NODE *node, *prev, *next, *spec;
7703  PT_NODE **fromp, **wherep;
7704  short location;
7705 
7706  switch (tree->node_type)
7707  {
7708  case PT_SELECT:
7709  fromp = &tree->info.query.q.select.from;
7710  wherep = &tree->info.query.q.select.where;
7711  break;
7712  case PT_UPDATE:
7713  fromp = &tree->info.update.spec;
7714  wherep = &tree->info.update.search_cond;
7715  break;
7716  case PT_DELETE:
7717  fromp = &tree->info.delete_.spec;
7718  wherep = &tree->info.delete_.search_cond;
7719  break;
7720  default:
7721  fromp = NULL;
7722  wherep = NULL;
7723  break;
7724  }
7725 
7726  if (wherep != NULL)
7727  {
7728  assert (fromp != NULL);
7729 
7730  prev = NULL;
7731  for (node = *wherep; node != NULL; node = next)
7732  {
7733  next = node->next;
7734  node->next = NULL;
7735 
7736  if (node->node_type == PT_EXPR)
7737  {
7738  location = node->info.expr.location;
7739  }
7740  else if (node->node_type == PT_VALUE)
7741  {
7742  location = node->info.value.location;
7743  }
7744  else
7745  {
7746  location = -1;
7747  }
7748 
7749  if (location > 0)
7750  {
7751  for (spec = *fromp; spec && spec->info.spec.location != location; spec = spec->next)
7752  ; /* nop */
7753 
7754  if (spec != NULL)
7755  {
7756  if (spec->info.spec.join_type == PT_JOIN_LEFT_OUTER
7758  {
7759  node->next = spec->info.spec.on_cond;
7760  spec->info.spec.on_cond = node;
7761 
7762  if (prev != NULL)
7763  {
7764  prev->next = next;
7765  }
7766  else
7767  {
7768  *wherep = next;
7769  }
7770  }
7771  else
7772  { /* already converted to inner join */
7773  /* clear on cond location */
7774  if (node->node_type == PT_EXPR)
7775  {
7776  node->info.expr.location = 0;
7777  }
7778  else if (node->node_type == PT_VALUE)
7779  {
7780  node->info.value.location = 0;
7781  }
7782 
7783  /* Here - at the last stage of query optimize, remove copy-pushed term */
7785  {
7786  parser_free_tree (parser, node);
7787 
7788  if (prev != NULL)
7789  {
7790  prev->next = next;
7791  }
7792  else
7793  {
7794  *wherep = next;
7795  }
7796  }
7797  else
7798  {
7799  prev = node;
7800  node->next = next;
7801  }
7802  }
7803  }
7804  else
7805  {
7806  /* might be impossible might be outer join error */
7807  PT_ERRORf (parser, node, "check outer join syntax at '%s'", pt_short_print (parser, node));
7808 
7809  prev = node;
7810  node->next = next;
7811  }
7812  }
7813  else
7814  {
7815  /* Here - at the last stage of query optimize, remove copy-pushed term */
7817  {
7818  parser_free_tree (parser, node);
7819 
7820  if (prev != NULL)
7821  {
7822  prev->next = next;
7823  }
7824  else
7825  {
7826  *wherep = next;
7827  }
7828  }
7829  else
7830  {
7831  prev = node;
7832  node->next = next;
7833  }
7834  }
7835  }
7836  }
7837 
7838  return tree;
7839 }
7840 
7841 /*
7842  * mq_optimize () - optimize statements by a variety of rewrites
7843  * return: void
7844  * parser(in): parser environment
7845  * statement(in): select tree to optimize
7846  *
7847  * Note: rewrite only if optimization is enabled
7848  */
7849 PT_NODE *
7850 mq_optimize (PARSER_CONTEXT * parser, PT_NODE * statement)
7851 {
7853 }
DNF_MERGE_RANGE_RESULT
Definition: query_rewrite.c:80
#define PT_EXPR_INFO_DO_NOT_AUTOPARAM
Definition: parse_tree.h:2235
static void qo_convert_to_range_helper(PARSER_CONTEXT *parser, PT_NODE *node)
static void qo_fold_is_and_not_null(PARSER_CONTEXT *parser, PT_NODE **wherep)
#define pt_is_expr_node(n)
Definition: parse_tree.h:261
PT_NODE * pt_name(PARSER_CONTEXT *parser_ptr, const char *name)
PT_NODE * order_by
Definition: parse_tree.h:2769
int db_compress_like_pattern(const DB_VALUE *const pattern, DB_VALUE *compressed_pattern, const bool has_escape_char, const char *escape_str)
PT_NODE * next
Definition: parse_tree.h:3447
PT_NAME_INFO name
Definition: parse_tree.h:3318
QFILE_TUPLE_VALUE_POSITION pos_descr
Definition: parse_tree.h:2829
#define PT_EXPR_INFO_COPYPUSH
Definition: parse_tree.h:2220
#define PT_IS_QUERY(n)
Definition: parse_tree.h:296
unsigned with_rollup
Definition: parse_tree.h:3472
PT_NODE * arg_list
Definition: parse_tree.h:2258
int db_get_info_for_like_optimization(const DB_VALUE *const pattern, const bool has_escape_char, const char *escape_str, int *const num_logical_chars, int *const last_safe_logical_pos, int *const num_match_many, int *const num_match_one)
#define NO_ERROR
Definition: error_code.h:46
PT_UNION_INFO union_
Definition: parse_tree.h:2782
static PT_NODE * qo_search_comp_pair_term(PARSER_CONTEXT *parser, PT_NODE *start)
static PT_NODE * qo_convert_attref_to_dotexpr_pre(PARSER_CONTEXT *parser, PT_NODE *spec, void *arg, int *continue_walk)
#define LANG_SYS_COLLATION
PT_NODE * pt_find_order_value_in_list(PARSER_CONTEXT *parser, const PT_NODE *sort_value, const PT_NODE *order_list)
PT_UPDATE_INFO update
Definition: parse_tree.h:3353
PT_MERGE_INFO merge
Definition: parse_tree.h:3315
UINTPTR id
Definition: parse_tree.h:2144
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
PT_NODE * pt_check_orderbynum_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define PT_IS_CHAR_STRING_TYPE(t)
Definition: parse_tree.h:164
PT_STATEMENT_INFO info
Definition: parse_tree.h:3487
TP_DOMAIN * expected_domain
Definition: parse_tree.h:3452
#define PT_ERRORm(parser, node, setNo, msgNo)
Definition: parse_tree.h:63
PT_NODE * show_args
Definition: parse_tree.h:2816
PT_NODE * using_index
Definition: parse_tree.h:2693
void qo_get_optimization_param(void *, QO_PARAM,...)
Definition: query_graph.c:269
PT_NODE * assignment
Definition: parse_tree.h:2861
static PT_NODE * qo_rewrite_hidden_col_as_derived(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *parent_node)
short location
Definition: parse_tree.h:2577
int pt_comp_to_between_op(PT_OP_TYPE left, PT_OP_TYPE right, PT_COMP_TO_BETWEEN_OP_CODE_TYPE code, PT_OP_TYPE *between)
static PT_NODE * qo_allocate_like_bound_for_index_scan(PARSER_CONTEXT *const parser, PT_NODE *const like, PT_NODE *const pattern, PT_NODE *const escape, const bool allocate_lower_bound)
static PT_NODE * qo_find_like_rewrite_bound(PARSER_CONTEXT *const parser, PT_NODE *const pattern, DB_VALUE *const pattern_str, const bool has_escape_char, const char *escape_str, const bool compute_lower_bound, const int last_safe_logical_pos)
PT_MISC_TYPE
Definition: parse_tree.h:983
#define MSGCAT_SEMANTIC_OUT_OF_MEMORY
int db_get_string_collation(const DB_VALUE *value)
PT_MISC_TYPE all_or_distinct
Definition: parse_tree.h:2260
short location
Definition: parse_tree.h:2152
#define PT_EXPR_INFO_SET_FLAG(e, f)
Definition: parse_tree.h:2239
PT_NODE * search_cond
Definition: parse_tree.h:2925
PT_SPEC_INFO spec
Definition: parse_tree.h:3346
#define ER_QSTR_INVALID_ESCAPE_SEQUENCE
Definition: error_code.h:748
static void qo_reduce_equality_terms(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE **wherep)
PT_NODE * pt_get_select_list(PARSER_CONTEXT *parser, PT_NODE *query)
Definition: query_result.c:404
PT_NODE * arg2
Definition: parse_tree.h:2664
int coll_modifier
Definition: parse_tree.h:2089
int correlation_level
Definition: parse_tree.h:2745
void pt_reset_error(PARSER_CONTEXT *parser)
enum pt_type_enum PT_TYPE_ENUM
Definition: parse_tree.h:962
#define assert_release(e)
Definition: error_manager.h:96
PT_NODE * spec
Definition: parse_tree.h:2859
PT_NODE * pt_expression_1(PARSER_CONTEXT *parser_ptr, PT_OP_TYPE op, PT_NODE *arg1)
PT_EXPR_INFO expr
Definition: parse_tree.h:3299
PT_NODE * mq_rewrite_query_as_derived(PARSER_CONTEXT *parser, PT_NODE *query)
int db_value_compare(const DB_VALUE *value1, const DB_VALUE *value2)
Definition: db_macro.c:1855
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2552
PT_TYPE_ENUM pt_db_to_type_enum(const DB_TYPE t)
Definition: parse_dbi.c:2595
struct pt_query_info::@123 flag
PT_NODE * pt_get_end_path_node(PT_NODE *node)
PT_NODE * s_point_list
Definition: query_rewrite.c:66
PT_NODE * new_spec
Definition: query_rewrite.c:57
static PT_NODE * qo_rewrite_like_for_index_scan(PARSER_CONTEXT *const parser, PT_NODE *like, PT_NODE *const pattern, PT_NODE *const escape)
PT_NODE * pt_expression_2(PARSER_CONTEXT *parser_ptr, PT_OP_TYPE op, PT_NODE *arg1, PT_NODE *arg2)
PARSER_VARCHAR * pt_append_bytes(const PARSER_CONTEXT *parser, PARSER_VARCHAR *old_string, const char *new_tail, const int new_tail_length)
Definition: parse_tree.c:1014
static void qo_rewrite_index_hints(PARSER_CONTEXT *parser, PT_NODE *statement)
union pt_query_info::@124 q
PT_NODE * path_entities
Definition: parse_tree.h:2138
static void qo_do_auto_parameterize_limit_clause(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE * pt_has_non_groupby_column_node(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
struct pt_merge_info::@125 update
#define PT_IS_DOT_NODE(n)
Definition: parse_tree.h:302
bool pt_false_search_condition(PARSER_CONTEXT *parser, const PT_NODE *statement)
#define PT_IS_NULL_NODE(e)
Definition: parse_tree.h:122
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
void pt_select_list_to_one_col(PARSER_CONTEXT *parser, PT_NODE *node, bool do_one)
int er_errid(void)
#define PT_NAME_INFO_IS_FLAGED(e, f)
Definition: parse_tree.h:2574
PT_NODE * indx_key_limit
Definition: parse_tree.h:2579
#define pt_is_orderbynum(n)
Definition: parse_tree.h:278
PT_NODE * data_type
Definition: parse_tree.h:3453
unsigned single_table_opt
Definition: parse_tree.h:2711
#define PT_IS_OID_NAME(n)
Definition: parse_tree.h:323
#define pt_is_instnum(n)
Definition: parse_tree.h:277
static void qo_move_on_clause_of_explicit_join_to_where_clause(PARSER_CONTEXT *parser, PT_NODE **fromp, PT_NODE **wherep)
PT_DOT_INFO dot
Definition: parse_tree.h:3287
PT_NODE * arg2
Definition: parse_tree.h:2086
PT_NODE * pt_wrap_with_cast_op(PARSER_CONTEXT *parser, PT_NODE *arg, PT_TYPE_ENUM new_type, int p, int s, PT_NODE *desired_dt)
static PT_NODE * qo_collect_name_spec(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define MSGCAT_SEMANTIC_CANT_COERCE_TO
FUNC_TYPE function_type
Definition: parse_tree.h:2259
PT_TYPE_ENUM type_enum
Definition: parse_tree.h:3457
static PT_NODE * qo_set_value_to_range_list(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE * or_next
Definition: parse_tree.h:3448
const char * mq_generate_name(PARSER_CONTEXT *parser, const char *root, int *version)
DB_TYPE pt_type_enum_to_db(const PT_TYPE_ENUM t)
Definition: parse_dbi.c:2314
void pt_init_node(PT_NODE *node, PT_NODE_TYPE node_type)
unsigned char bytes[1]
Definition: parse_tree.h:3431
PT_NODE * mq_regenerate_if_ambiguous(PARSER_CONTEXT *parser, PT_NODE *spec, PT_NODE *statement, PT_NODE *from)
PT_NODE * limit
Definition: parse_tree.h:2773
bool pt_is_symmetric_op(PT_OP_TYPE op)
PT_MISC_TYPE derived_table_type
Definition: parse_tree.h:2147
PT_NODE * arg1
Definition: parse_tree.h:2663
void qo_do_auto_parameterize(PARSER_CONTEXT *parser, PT_NODE *where)
#define PT_NODE_PRINT_VALUE_TO_TEXT(p, n)
Definition: parse_tree.h:597
#define PT_IS_SELECT(n)
Definition: parse_tree.h:284
int pr_free_value(DB_VALUE *value)
PT_OP_TYPE pt_converse_op(PT_OP_TYPE op)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
PT_NODE * arg2
Definition: parse_tree.h:2198
LANG_COLLATION * lang_get_collation(const int coll_id)
PT_NODE * del_search_cond
Definition: parse_tree.h:2930
static void qo_apply_range_intersection_helper(PARSER_CONTEXT *parser, PT_NODE *node1, PT_NODE *node2)
PT_FUNCTION_INFO function
Definition: parse_tree.h:3301
#define CAST_POINTER_TO_NODE(p)
Definition: parse_tree.h:607
DB_OBJECT * db_object
Definition: parse_tree.h:2546
static int qo_is_cast_attr(PT_NODE *expr)
static void pt_free_escape_char(PARSER_CONTEXT *const parser, PT_NODE *const like, PT_NODE *const pattern, PT_NODE *const escape)
#define LIKE_WILDCARD_MATCH_MANY
#define PT_ERRORmf2(parser, node, setNo, msgNo, arg1, arg2)
Definition: parse_tree.h:65
#define assert(x)
static int qo_is_oid_const(PT_NODE *node)
#define PT_IS_CONST_NOT_HOSTVAR(n)
Definition: parse_tree.h:370
#define PT_IS_QUERY_NODE_TYPE(x)
Definition: parse_tree.h:115
static PT_NODE * qo_replace_spec_name_with_null(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
int prm_get_integer_value(PARAM_ID prm_id)
PT_MISC_TYPE asc_or_desc
Definition: parse_tree.h:2830
PT_NODE * pt_rewrite_to_auto_param(PARSER_CONTEXT *parser, PT_NODE *value)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
DB_VALUE db_value
Definition: parse_tree.h:3059
const char * pt_show_type_enum(PT_TYPE_ENUM t)
PT_NODE * on_cond
Definition: parse_tree.h:2149
#define PT_GET_COLLATION_MODIFIER(p)
Definition: parse_tree.h:619
short tag_click_counter
Definition: parse_tree.h:2088
static int qo_reduce_order_by(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE * pt_check_orderbynum_post(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
COMP_DBVALUE_WITH_OPTYPE_RESULT
Definition: query_rewrite.c:70
bool pt_is_pseudo_const(PT_NODE *expr)
Definition: query_graph.c:3655
PT_DATA_VALUE data_value
Definition: parse_tree.h:3058
PT_NODE * flat_entity_list
Definition: parse_tree.h:2140
PT_NODE * top_node
Definition: parse_tree.h:1707
PT_MISC_TYPE all_distinct
Definition: parse_tree.h:2746
bool pt_has_analytic(PARSER_CONTEXT *parser, PT_NODE *node)
int sm_is_partitioned_class(MOP op)
const char * original
Definition: parse_tree.h:2544
PT_NODE * using_index
Definition: parse_tree.h:2064
#define PT_IS_PARAMETERIZED_TYPE(t)
Definition: parse_tree.h:229
PT_HINT_ENUM hint
Definition: parse_tree.h:2707
int intl_identifier_casecmp(const char *str1, const char *str2)
PT_NODE * pt_make_string_value(PARSER_CONTEXT *parser, const char *value_string)
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
PT_NODE_TYPE node_type
Definition: parse_tree.h:3439
#define PT_IS_NATIONAL_CHAR_STRING_TYPE(t)
Definition: parse_tree.h:156
PT_NODE * parser_copy_tree(PARSER_CONTEXT *parser, const PT_NODE *tree)
#define PT_IS_VALUE_QUERY(n)
Definition: parse_tree.h:476
PT_NODE * pt_semantic_type(PARSER_CONTEXT *parser, PT_NODE *tree, SEMANTIC_CHK_INFO *sc_info)
static DNF_MERGE_RANGE_RESULT qo_merge_range_helper(PARSER_CONTEXT *parser, PT_NODE *node)
#define OPTIMIZATION_ENABLED(level)
Definition: optimizer.h:83
PT_SHOWSTMT_INFO showstmt
Definition: parse_tree.h:3342
PT_NODE * having
Definition: parse_tree.h:2692
PT_NODE * from
Definition: parse_tree.h:2686
#define PT_SELECT_INFO_HAS_AGG
Definition: parse_tree.h:2717
#define PT_NAME_INFO_CONSTANT
Definition: parse_tree.h:2562
#define PT_IS_CONST(n)
Definition: parse_tree.h:364
int db_string_put_cs_and_collation(DB_VALUE *value, const int codeset, const int collation_id)
Definition: db_macro.c:4164
PT_NODE * mq_optimize(PARSER_CONTEXT *parser, PT_NODE *statement)
UINTPTR spec_id
Definition: parse_tree.h:2543
#define PT_IS_VALUE_NODE(n)
Definition: parse_tree.h:330
PT_NODE * pt_remove_from_list(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *list)
PT_NODE * limit
Definition: parse_tree.h:2072
#define TP_DOMAIN_TYPE(dom)
PT_DATA_TYPE_INFO data_type
Definition: parse_tree.h:3284
#define MSGCAT_SEMANTIC_SORT_DIR_CONFLICT
static void qo_do_auto_parameterize_keylimit_clause(PARSER_CONTEXT *parser, PT_NODE *node)
static void qo_converse_sarg_terms(PARSER_CONTEXT *parser, PT_NODE *where)
PARSER_VARCHAR * str
Definition: parse_tree.h:3036
DB_VALUE * pr_copy_value(DB_VALUE *value)
SP_PARSER_CTX * parser
static PT_NODE * qo_construct_new_set(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE * arg1
Definition: parse_tree.h:2197
unsigned rewrite_limit
Definition: parse_tree.h:2766
#define NULL
Definition: freelistheap.h:34
PT_NODE * pt_pointer_stack_pop(PARSER_CONTEXT *parser, PT_NODE *stack, PT_NODE **node)
PT_NODE * as_attr_list
Definition: parse_tree.h:2136
#define pt_is_const_not_hostvar(n)
Definition: parse_tree.h:274
int tp_valid_indextype(DB_TYPE type)
bool pt_is_const_expr_node(PT_NODE *node)
PT_NODE * referenced_attrs
Definition: parse_tree.h:2137
PT_MISC_TYPE is_subquery
Definition: parse_tree.h:2747
PT_NODE * pt_limit_to_numbering_expr(PARSER_CONTEXT *parser, PT_NODE *limit, PT_OP_TYPE num_op, bool is_gby_num)
static PT_NODE * qo_collect_name_spec_post(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static int qo_reduce_order_by_for(PARSER_CONTEXT *parser, PT_NODE *node)
#define pt_is_multi_col_term(n)
Definition: parse_tree.h:263
TP_DOMAIN * tp_domain_cache(TP_DOMAIN *transient)
#define PT_EXPR_INFO_TRANSITIVE
Definition: parse_tree.h:2217
PT_NODE * mq_make_derived_spec(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *subquery, int *idx, PT_NODE **spec_ptr, PT_NODE **attr_list_ptr)
static PT_NODE * qo_get_name_by_spec_id(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static void qo_convert_to_range(PARSER_CONTEXT *parser, PT_NODE **wherep)
int pt_check_path_eq(PARSER_CONTEXT *parser, const PT_NODE *p, const PT_NODE *q)
#define PT_IS_COLLECTION_TYPE(t)
Definition: parse_tree.h:143
PT_NODE * pt_is_pseudocolumn_node(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
static bool qo_can_generate_single_table_connect_by(PARSER_CONTEXT *parser, PT_NODE *node)
static void qo_rewrite_like_terms(PARSER_CONTEXT *parser, PT_NODE **cnf_list)
PT_NODE * arg1
Definition: parse_tree.h:2085
PT_NODE * where
Definition: parse_tree.h:2687
PT_QUERY_INFO query
Definition: parse_tree.h:3325
static void qo_rewrite_one_like_term(PARSER_CONTEXT *const parser, PT_NODE *const like, PT_NODE *const pattern, PT_NODE *const escape, bool *const perform_generic_rewrite)
short location
Definition: parse_tree.h:2243
static int qo_range_optype_rank(PT_OP_TYPE op)
bool pt_has_aggregate(PARSER_CONTEXT *parser, PT_NODE *node)
PT_NODE * qo_check_nullable_expr(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define cmp
Definition: mprec.h:351
int pr_clear_value(DB_VALUE *value)
static PT_NODE * qo_rewrite_subqueries(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define PT_IDX_HINT_ORDER(hint_node)
Definition: parse_tree.h:2607
static PT_NODE * qo_optimize_queries(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
PT_NODE * set
Definition: parse_tree.h:3047
PT_NODE * pt_get_first_arg_ignore_prior(PT_NODE *node)
int pt_between_to_comp_op(PT_OP_TYPE between, PT_OP_TYPE *left, PT_OP_TYPE *right)
PT_NODE * parser_append_node(PT_NODE *node, PT_NODE *list)
char * pt_short_print(PARSER_CONTEXT *parser, const PT_NODE *node)
int pt_is_function_index_expression(PT_NODE *node)
#define TP_IS_CHAR_TYPE(typeid)
PT_NODE * orderby_for
Definition: parse_tree.h:2876
PT_NODE * parser_new_node(PARSER_CONTEXT *parser, PT_NODE_TYPE node_type)
static void error(const char *msg)
Definition: gencat.c:331
#define PT_NODE_MOVE_NUMBER_OUTERLINK(t, s)
Definition: parse_tree.h:572
void parser_free_node(const PARSER_CONTEXT *parser, PT_NODE *node)
Definition: parse_tree.c:869
static int rc
Definition: serial.c:50
static int qo_is_partition_attr(PT_NODE *node)
short tag_click_counter
Definition: parse_tree.h:2578
short db_value_is_initialized
Definition: parse_tree.h:3060
#define MSGCAT_SET_ERROR
PT_SORT_SPEC_INFO sort_spec
Definition: parse_tree.h:3343
#define ARG_FILE_LINE
Definition: error_manager.h:44
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 DB_MAX_LITERAL_PRECISION
Definition: query_rewrite.c:43
static PT_NODE * qo_get_next_oid_pred(PT_NODE *pred)
#define MSGCAT_SET_PARSER_SEMANTIC
SM_PARTITION * partition
Definition: parse_tree.h:2549
PT_NODE * using_index
Definition: parse_tree.h:2863
static PT_NODE * qo_convert_attref_to_dotexpr(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
struct pt_merge_info::@126 insert
#define PT_IS_EXPR_NODE(n)
Definition: parse_tree.h:305
#define PT_IS_CONST_INPUT_HOSTVAR(n)
Definition: parse_tree.h:375
PT_NODE * pt_find_aggregate_functions_pre(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
static PT_NODE * qo_check_like_expression_pre(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
PT_NODE * pt_point(PARSER_CONTEXT *parser, const PT_NODE *in_tree)
bool pt_is_function_index_expr(PARSER_CONTEXT *parser, PT_NODE *expr, bool report_error)
PT_OP_TYPE
Definition: parse_tree.h:1320
#define PT_SELECT_INFO_SET_FLAG(s, f)
Definition: parse_tree.h:2737
PT_NODE * connect_by
Definition: parse_tree.h:2689
static PT_NODE * qo_analyze_path_join(PARSER_CONTEXT *parser, PT_NODE *path_spec, void *arg, int *continue_walk)
unsigned single_tuple
Definition: parse_tree.h:2760
#define PT_IS_FUNCTION(n)
Definition: parse_tree.h:311
enum intl_codeset INTL_CODESET
Definition: intl_support.h:190
int intl_char_count(const unsigned char *src, int length_in_bytes, INTL_CODESET src_codeset, int *char_count)
Definition: intl_support.c:983
PT_NODE * search_cond
Definition: parse_tree.h:2063
PT_NODE * pt_pointer_stack_push(PARSER_CONTEXT *parser, PT_NODE *stack, PT_NODE *node)
bool prm_get_bool_value(PARAM_ID prm_id)
PT_NODE * start_with
Definition: parse_tree.h:2690
static PT_NODE * qo_analyze_path_join_pre(PARSER_CONTEXT *parser, PT_NODE *spec, void *arg, int *continue_walk)
int db_get_string_size(const DB_VALUE *value)
int pt_is_attr(PT_NODE *node)
static bool pt_is_ascii_string_value_node(const PT_NODE *const node)
bool pt_sort_spec_cover(PT_NODE *cur_list, PT_NODE *new_list)
PT_NODE * after_cb_filter
Definition: parse_tree.h:2691
PT_MISC_TYPE only_all
Definition: parse_tree.h:2145
#define PT_EXPR_INFO_ORDERBYNUM_C
Definition: parse_tree.h:2213
PT_MISC_TYPE meta_class
Definition: parse_tree.h:2146
void er_clear(void)
unsigned cannot_prepare
Definition: parse_tree.h:3462
PT_DELETE_INFO delete_
Definition: parse_tree.h:3285
PT_NODE * limit
Definition: parse_tree.h:2874
static PT_NODE * qo_reset_location(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
#define TP_FLOATING_PRECISION_VALUE
void * etc
Definition: parse_tree.h:3450
PT_NODE * pt_get_subquery_of_insert_select(const PT_NODE *insert_statement)
PT_NODE * error_msgs
Definition: parse_tree.h:3550
PT_NODE * spec
Definition: parse_tree.h:2061
int i
Definition: dynamic_load.c:954
PT_VALUE_INFO value
Definition: parse_tree.h:3358
int pt_length_of_select_list(PT_NODE *list, int hidden_col)
int db_make_null(DB_VALUE *value)
PT_NODE * select_stack
Definition: parse_tree.h:3386
PT_NODE * list
Definition: parse_tree.h:2685
#define DB_IS_NULL(value)
Definition: dbtype.h:63
static void qo_reduce_comp_pair_terms(PARSER_CONTEXT *parser, PT_NODE **wherep)
PT_OP_TYPE op
Definition: parse_tree.h:2200
PT_NODE * pt_lambda_with_arg(PARSER_CONTEXT *parser, PT_NODE *tree_with_names, PT_NODE *name_node, PT_NODE *corresponding_tree, bool loc_check, int type, bool dont_replace)
static int qo_is_reduceable_const(PT_NODE *expr)
PT_NODE * path_conjuncts
Definition: parse_tree.h:2139
PT_NODE * pt_find_aggregate_functions_post(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
#define PT_IS_SET_TYPE(n)
Definition: parse_tree.h:336
PT_NODE * orderby_for
Definition: parse_tree.h:2770
static PT_NODE * qo_make_new_derived_tblspec(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *pred, int *seqno)
#define PT_INTERNAL_ERROR(parser, what)
Definition: parse_tree.h:112
int db_value_clear(DB_VALUE *value)
Definition: db_macro.c:1588
int db_make_int(DB_VALUE *value, const int num)
PT_NODE * pt_cnf(PARSER_CONTEXT *parser, PT_NODE *node)
Definition: cnf.c:941
static void qo_apply_range_intersection(PARSER_CONTEXT *parser, PT_NODE **wherep)
#define pt_has_error(parser)
Definition: parser.h:507
static PT_MISC_TYPE qo_find_best_path_type(PT_NODE *spec)
#define PT_IS_EXPR_NODE_WITH_OPERATOR(n, op_type)
Definition: parse_tree.h:464
const char * resolved
Definition: parse_tree.h:2545
SORT_NULLS pt_to_null_ordering(PT_NODE *sort_spec)
PT_NODE * mq_reset_ids_in_statement(PARSER_CONTEXT *parser, PT_NODE *statement)
static COMP_DBVALUE_WITH_OPTYPE_RESULT qo_compare_dbvalue_with_optype(DB_VALUE *val1, PT_OP_TYPE op1, DB_VALUE *val2, PT_OP_TYPE op2)
#define PT_HAS_COLLATION(t)
Definition: parse_tree.h:243
#define PT_EXPR_INFO_EMPTY_RANGE
Definition: parse_tree.h:2208
#define PT_EXPR_INFO_CLEAR_FLAG(e, f)
Definition: parse_tree.h:2240
PT_NODE * pt_dbval_to_value(PARSER_CONTEXT *parser, const DB_VALUE *val)
Definition: parse_dbi.c:574
static PT_NODE * qo_rewrite_innerjoin(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
DB_VALUE_COMPARE_RESULT
Definition: dbtype_def.h:199
int pt_length_of_list(const PT_NODE *list)
struct parser_node::@132 flag
PT_NODE * entity_name
Definition: parse_tree.h:2130
void pt_split_join_preds(PARSER_CONTEXT *parser, PT_NODE *predicates, PT_NODE **join_part, PT_NODE **after_cb_filter)
PT_NODE * mq_set_references(PARSER_CONTEXT *parser, PT_NODE *statement, PT_NODE *spec)
PT_SELECT_INFO select
Definition: parse_tree.h:2781
DB_VALUE * pt_value_to_db(PARSER_CONTEXT *parser, PT_NODE *value)
Definition: parse_dbi.c:1088
static PT_NODE * qo_optimize_queries_post(PARSER_CONTEXT *parser, PT_NODE *tree, void *arg, int *continue_walk)
#define pt_is_const(n)
Definition: parse_tree.h:271
TP_DOMAIN_STATUS tp_value_cast_force(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain, bool implicit_coercion)
#define PT_EXPR_INFO_INSTNUM_C
Definition: parse_tree.h:2209
PT_NODE * parser_walk_tree(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE_WALK_FUNCTION pre_function, void *pre_argument, PT_NODE_WALK_FUNCTION post_function, void *post_argument)
#define PT_EXPR_INFO_IS_FLAGED(e, f)
Definition: parse_tree.h:2238
#define PT_ERRORf(parser, node, msg, arg1)
Definition: parse_tree.h:57
#define PT_IS_NAME_NODE(n)
Definition: parse_tree.h:320
int db_get_string_codeset(const DB_VALUE *value)
PT_NODE * parser_copy_tree_list(PARSER_CONTEXT *parser, PT_NODE *tree)
static PT_NODE * qo_rewrite_outerjoin(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)
static PT_NODE * qo_rewrite_oid_equality(PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *pred, int *seqno)
const char ** p
Definition: dynamic_load.c:945
int db_get_like_optimization_bounds(const DB_VALUE *const pattern, DB_VALUE *bound, const bool has_escape_char, const char *escape_str, const bool compute_lower_bound, const int last_safe_logical_pos)
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
#define PT_ERRORmf(parser, node, setNo, msgNo, arg1)
Definition: parse_tree.h:64
unsigned is_hidden_column
Definition: parse_tree.h:3470
int pt_check_class_eq(PARSER_CONTEXT *parser, PT_NODE *p, PT_NODE *q)
#define PT_IS_EXPR_WITH_PRIOR_ARG(x)
Definition: parse_tree.h:467
PT_JOIN_TYPE join_type
Definition: parse_tree.h:2151
#define PT_EXPR_INFO_CAST_COLL_MODIFIER
Definition: parse_tree.h:2231
PT_NODE * old_spec
Definition: query_rewrite.c:56
PT_NODE * derived_table
Definition: parse_tree.h:2134
PT_NODE * search_cond
Definition: parse_tree.h:2862
PT_NODE * range_var
Definition: parse_tree.h:2135
static bool qo_check_condition_yields_null(PARSER_CONTEXT *parser, PT_NODE *path_spec, PT_NODE *query_where)
PT_NODE * qo_check_nullable_expr_with_spec(PARSER_CONTEXT *parser, PT_NODE *node, void *arg, int *continue_walk)