CUBRID Engine  latest
scan_manager.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  * scan_manager.c - scan management routines
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 #include "jansson.h"
31 
32 #include "error_manager.h"
33 #include "heap_file.h"
34 #include "fetch.h"
35 #include "list_file.h"
36 #include "set_scan.h"
37 #include "system_parameter.h"
38 #include "btree_load.h"
39 #include "perf_monitor.h"
40 #include "query_manager.h"
41 #include "query_evaluator.h"
42 #include "query_opfunc.h"
43 #include "query_reevaluation.hpp"
44 #include "regu_var.hpp"
45 #include "locator_sr.h"
46 #include "log_lsa.hpp"
47 #include "object_primitive.h"
48 #include "object_representation.h"
49 #include "dbtype.h"
50 #include "xasl_predicate.hpp"
51 #include "xasl.h"
52 
53 #if !defined(SERVER_MODE)
54 #define pthread_mutex_init(a, b)
55 #define pthread_mutex_destroy(a)
56 #define pthread_mutex_lock(a) 0
57 #define pthread_mutex_unlock(a)
58 static int rv;
59 #endif
60 
61 /* this macro is used to make sure that heap file identifier is initialized
62  * properly that heap file scan routines will work properly.
63  */
64 #define UT_CAST_TO_NULL_HEAP_OID(hfidp,oidp) \
65  do \
66  { \
67  (oidp)->pageid = NULL_PAGEID; \
68  (oidp)->volid = (hfidp)->vfid.volid; \
69  (oidp)->slotid = NULL_SLOTID; \
70  } \
71  while (0)
72 
73 #define GET_NTH_OID(oid_setp, n) ((OID *)((OID *)(oid_setp) + (n)))
74 
75 /* ISS_RANGE_DETAILS stores information about the two ranges we use
76  * interchangeably in Index Skip Scan mode: along with the real range, we
77  * use a "fake" one to obtain the next value for the index's first column.
78  *
79  * ISS_RANGE_DETAILS tries to completely encapsulate one of these ranges, so
80  * that whenever the need arises, we can "swap" them. */
83 {
84  int key_cnt;
88  int part_key_desc; /* last partial key domain is descending */
89 };
90 
91 typedef int QPROC_KEY_VAL_FU (KEY_VAL_RANGE * key_vals, int key_cnt);
92 typedef SCAN_CODE (*QP_SCAN_FUNC) (THREAD_ENTRY * thread_p, SCAN_ID * s_id);
93 
94 typedef enum
95 {
99 } ROP_TYPE;
100 
102 {
106 } rop_range_table[] =
107 {
108  {
109  ROP_NA, ROP_EQ, NA_NA},
110  {
111  ROP_GE, ROP_LE, GE_LE},
112  {
113  ROP_GE, ROP_LT, GE_LT},
114  {
115  ROP_GT, ROP_LE, GT_LE},
116  {
117  ROP_GT, ROP_LT, GT_LT},
118  {
120  {
122  {
124  {
126  {
128 };
129 
130 static const int rop_range_table_size = sizeof (rop_range_table) / sizeof (struct rop_range_struct);
131 
132 #if defined(SERVER_MODE)
133 static pthread_mutex_t scan_Iscan_oid_buf_list_mutex = PTHREAD_MUTEX_INITIALIZER;
134 #endif
135 
138 
139 #define SCAN_ISCAN_OID_BUF_LIST_DEFAULT_SIZE 10
140 
141 static void scan_init_scan_pred (SCAN_PRED * scan_pred_p, regu_variable_list_node * regu_list, PRED_EXPR * pred_expr,
142  PR_EVAL_FNC pr_eval_fnc);
143 static void scan_init_scan_attrs (SCAN_ATTRS * scan_attrs_p, int num_attrs, ATTR_ID * attr_ids,
144  HEAP_CACHE_ATTRINFO * attr_cache);
145 static int scan_init_indx_coverage (THREAD_ENTRY * thread_p, int coverage_enabled, valptr_list_node * output_val_list,
146  regu_variable_list_node * regu_val_list, VAL_DESCR * vd, QUERY_ID query_id,
147  int max_key_len, int func_index_col_id, INDX_COV * indx_cov);
148 static int scan_alloc_oid_list (BTREE_ISCAN_OID_LIST ** oid_list_p);
149 static int scan_alloc_iscan_oid_buf_list (BTREE_ISCAN_OID_LIST ** oid_list);
150 static void scan_free_iscan_oid_buf_list (BTREE_ISCAN_OID_LIST * oid_list);
151 static void rop_to_range (RANGE * range, ROP_TYPE left, ROP_TYPE right);
152 static void range_to_rop (ROP_TYPE * left, ROP_TYPE * rightk, RANGE range);
153 static ROP_TYPE compare_val_op (DB_VALUE * val1, ROP_TYPE op1, DB_VALUE * val2, ROP_TYPE op2, int num_index_term);
154 static int key_val_compare (const void *p1, const void *p2);
155 static int eliminate_duplicated_keys (KEY_VAL_RANGE * key_vals, int key_cnt);
156 static int merge_key_ranges (KEY_VAL_RANGE * key_vals, int key_cnt);
157 static int reverse_key_list (KEY_VAL_RANGE * key_vals, int key_cnt);
158 static int check_key_vals (KEY_VAL_RANGE * key_vals, int key_cnt, QPROC_KEY_VAL_FU * chk_fn);
159 static int scan_dbvals_to_midxkey (THREAD_ENTRY * thread_p, DB_VALUE * retval, bool * indexal,
160  TP_DOMAIN * btree_domainp, int num_term, REGU_VARIABLE * func, VAL_DESCR * vd,
161  int key_minmax, bool is_iss, DB_VALUE * fetched_values);
163  INDX_SCAN_ID * iscan_id, TP_DOMAIN * btree_domainp, VAL_DESCR * vd);
164 static int scan_get_index_oidset (THREAD_ENTRY * thread_p, SCAN_ID * s_id, DB_BIGINT * key_limit_upper,
165  DB_BIGINT * key_limit_lower);
166 static void scan_init_scan_id (SCAN_ID * scan_id, bool force_select_lock, SCAN_OPERATION_TYPE scan_op_type, int fixed,
167  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval,
168  val_list_node * val_list, VAL_DESCR * vd);
169 static int scan_init_index_key_limit (THREAD_ENTRY * thread_p, INDX_SCAN_ID * isidp, KEY_INFO * key_infop,
170  VAL_DESCR * vd);
171 static SCAN_CODE scan_next_scan_local (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
172 static SCAN_CODE scan_next_heap_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
173 static SCAN_CODE scan_next_heap_page_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
174 static SCAN_CODE scan_next_class_attr_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
175 static SCAN_CODE scan_next_index_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
176 static SCAN_CODE scan_next_index_key_info_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
177 static SCAN_CODE scan_next_index_node_info_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
178 static SCAN_CODE scan_next_index_lookup_heap (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, INDX_SCAN_ID * isidp,
179  FILTER_INFO * data_filter, TRAN_ISOLATION isolation);
180 static SCAN_CODE scan_next_list_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
181 static SCAN_CODE scan_next_showstmt_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
182 static SCAN_CODE scan_next_set_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
183 static SCAN_CODE scan_next_json_table_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
184 static SCAN_CODE scan_next_value_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
185 static SCAN_CODE scan_next_method_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
186 static SCAN_CODE scan_handle_single_scan (THREAD_ENTRY * thread_p, SCAN_ID * s_id, QP_SCAN_FUNC next_scan);
187 static SCAN_CODE scan_prev_scan_local (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
188 static void resolve_domains_on_list_scan (LLIST_SCAN_ID * llsidp, val_list_node * ref_val_list);
189 static void resolve_domain_on_regu_operand (REGU_VARIABLE * regu_var, val_list_node * ref_val_list,
190  QFILE_TUPLE_VALUE_TYPE_LIST * p_type_list);
192  bool use_range_opt, int max_size);
193 static int scan_dump_key_into_tuple (THREAD_ENTRY * thread_p, INDX_SCAN_ID * iscan_id, DB_VALUE * key, OID * oid,
194  QFILE_TUPLE_RECORD * tplrec);
195 static int scan_save_range_details (INDX_SCAN_ID * isidp_src, ISS_RANGE_DETAILS * rdp_dest);
196 static int scan_restore_range_details (ISS_RANGE_DETAILS * rdp_src, INDX_SCAN_ID * isidp_dest);
197 static SCAN_CODE scan_get_next_iss_value (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, INDX_SCAN_ID * isidp);
198 static SCAN_CODE call_get_next_index_oidset (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, INDX_SCAN_ID * isidp,
199  bool should_go_to_next_value);
200 static int scan_key_compare (DB_VALUE * val1, DB_VALUE * val2, int num_index_term);
201 
202 /* for hash list scan */
203 static SCAN_CODE scan_build_hash_list_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
204 static SCAN_CODE scan_next_hash_list_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id);
205 static SCAN_CODE scan_hash_probe_next (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, QFILE_TUPLE * tuple);
206 static HASH_METHOD check_hash_list_scan (LLIST_SCAN_ID * llsidp, int *val_cnt, int hash_list_scan_yn);
207 
208 /*
209  * scan_init_iss () - initialize index skip scan structure
210  * return: error code
211  * isidp: pointer to index scan id structure that contains iss structure
212  */
213 int
215 {
216  DB_VALUE *last_key = NULL;
217  INDEX_SKIP_SCAN *iss = NULL;
218 
219  if (isidp == NULL)
220  {
221  assert_release (false);
223 
224  return ER_FAILED;
225  }
226 
227  iss = &isidp->iss;
228 
229  /* initialize iss structure */
230  iss->current_op = ISS_OP_NONE;
231  iss->skipped_range = NULL;
232 
233  if (isidp->indx_info == NULL)
234  {
235  /* no index info specified so no iss needed */
236  iss->use = false;
237  return NO_ERROR;
238  }
239 
240  iss->use = isidp->indx_info->use_iss != 0;
241 
242  if (!iss->use)
243  {
244  /* if not using iss, nothing more to do */
245  return NO_ERROR;
246  }
247 
248  /* assign range */
249  iss->skipped_range = &isidp->indx_info->iss_range;
250 
251  if (iss->skipped_range->key1 == NULL || iss->skipped_range->key1->value.funcp == NULL
252  || iss->skipped_range->key1->value.funcp->operand == NULL
253  || iss->skipped_range->key1->value.funcp->operand->value.type != TYPE_DBVAL)
254  {
255  /* this should never happen */
256  assert_release (false);
258 
259  return ER_FAILED;
260  }
261 
262  /* reset key value */
263  last_key = &iss->skipped_range->key1->value.funcp->operand->value.value.dbval;
264 
265  if (!DB_IS_NULL (last_key))
266  {
267  pr_clear_value (last_key);
268  db_make_null (last_key);
269  }
270 
271  return NO_ERROR;
272 }
273 
274 /*
275  * scan_init_index_scan () - initialize an index scan structure with the
276  * specified OID buffer
277  * return : void
278  * isidp (in) : index scan
279  * oid_list (in) : OID list.
280  * mvcc_snapshot(in) : MVCC snapshot
281  */
282 void
284 {
285  if (isidp == NULL)
286  {
287  assert (false);
288  return;
289  }
290 
291  isidp->oid_list = oid_list;
292  isidp->copy_buf = NULL;
293  isidp->copy_buf_len = 0;
294  memset ((void *) (&(isidp->indx_cov)), 0, sizeof (INDX_COV));
295  isidp->indx_info = NULL;
296  memset ((void *) (&(isidp->multi_range_opt)), 0, sizeof (MULTI_RANGE_OPT));
297  scan_init_iss (isidp);
298  isidp->scan_cache.mvcc_snapshot = mvcc_snapshot;
299  isidp->need_count_only = false;
300  isidp->check_not_vacuumed = false;
301  isidp->not_vacuumed_res = DISK_VALID;
302 }
303 
304 /*
305  * scan_save_range_details () - save range details from the index scan id to
306  * a "backup" iss_range_details structure.
307  * return: error code
308  * rdp_dest: pointer to range details structure to be filled with data from isidp_src
309  * isidp_src: pointer to index scan id
310  */
311 static int
313 {
314  if (rdp_dest == NULL || isidp_src == NULL || isidp_src->indx_info == NULL)
315  {
316  assert (false);
317  return ER_FAILED;
318  }
319 
320  rdp_dest->key_cnt = isidp_src->indx_info->key_info.key_cnt;
321  rdp_dest->key_ranges = isidp_src->indx_info->key_info.key_ranges;
322  rdp_dest->key_pred = isidp_src->key_pred;
323  rdp_dest->range_type = isidp_src->indx_info->range_type;
324  rdp_dest->part_key_desc = isidp_src->bt_scan.btid_int.part_key_desc;
325 
326  return NO_ERROR;
327 }
328 
329 /*
330  * scan_restore_range_details () - restore range details from the backup
331  * structure into the index scan id.
332  * return: error code
333  * rdp_src: pointer to range details structure to be restored
334  * isidp_dest: pointer to index scan id to be filled
335  *
336  * Note:
337  * The index scan is reset so that it is considered a brand new scan (for
338  * instance, curr_keyno is set to -1 etc.)
339  */
340 static int
342 {
343  if (isidp_dest == NULL || rdp_src == NULL || isidp_dest->indx_info == NULL)
344  {
345  return ER_FAILED;
346  }
347 
348  isidp_dest->curr_keyno = -1;
349  isidp_dest->indx_info->key_info.key_cnt = rdp_src->key_cnt;
350 
351  isidp_dest->indx_info->key_info.key_ranges = rdp_src->key_ranges;
352  isidp_dest->key_pred = rdp_src->key_pred;
353  isidp_dest->indx_info->range_type = rdp_src->range_type;
354  isidp_dest->bt_scan.btid_int.part_key_desc = rdp_src->part_key_desc;
355 
356  return NO_ERROR;
357 }
358 
359 /*
360  * scan_get_next_iss_value () - retrieve the next value to be used in the
361  * index skip scan: the next value from the
362  * first column of the index.
363  * return: S_SUCCESS on successfully retrieving the next value
364  * S_ERROR on encountering an error
365  * S_END when the search does not find any "next value" (reached
366  * end of the btree).
367  * thread_p(in):
368  * scan_id (in): scan id
369  * isidp (in): index scan id
370  *
371  * Note:
372  * This function is called from call_get_next_index_oidset whenever the
373  * current value for the first index column is exhausted and we need to go on
374  * to the next possible value of C1. It is ONLY called within an index skip
375  * scan optimization context (ONLY when isidp->iss.use is TRUE).
376  * We call scan_get_index_oidset(), which in turn calls btree_range_search,
377  * but first we set the stage: prepare a "fake" range to obtain the next value
378  * for C1 (the first column), extract the value that btree_range_search returns
379  * inside isidp->iss.dbval, fill in slot 0 of the real range ([C1=?]) with
380  * that new value, and restore the real range as if it were ready to be used
381  * for the first time.
382  */
383 static SCAN_CODE
385 {
386  /* we are being called either before any other btree range search, or after somebody finished a real range search and
387  * wants to advance to the next value for the first column of the index. */
388 
389  INDEX_SKIP_SCAN *iss = NULL;
390  DB_VALUE *last_key = NULL;
391  ISS_RANGE_DETAILS scan_range_det, fetch_range_det;
392  bool descending_skip_key = false;
393  bool descending_scan = false;
394  int i;
395 
396  if (isidp == NULL)
397  {
398  /* null pointer was passed to function */
399  assert_release (false);
401 
402  return S_ERROR;
403  }
404 
405  if (!isidp->iss.use)
406  {
407  /* not using iss but function was called; should not be here */
408  assert_release (false);
410 
411  return S_ERROR;
412  }
413 
414  if (isidp->iss.skipped_range == NULL || isidp->iss.skipped_range->key1 == NULL
415  || isidp->iss.skipped_range->key1->value.funcp == NULL
416  || isidp->iss.skipped_range->key1->value.funcp->operand == NULL
417  || isidp->iss.skipped_range->key1->value.funcp->operand->value.type != TYPE_DBVAL)
418  {
419  /* the fetch range is corrupted; should not be here */
420  assert_release (false);
422 
423  return S_ERROR;
424  }
425 
426  if (isidp->bt_scan.btid_int.key_type == NULL || isidp->bt_scan.btid_int.key_type->setdomain == NULL
428  {
429  /* key type is not midxkey so this is not a multi-column index; should not be here */
430  assert_release (false);
432 
433  return S_ERROR;
434  }
435 
436  /* populate local variables iss and last_key */
437  descending_skip_key = isidp->bt_scan.btid_int.key_type->setdomain->is_desc;
438  iss = &isidp->iss;
439  last_key = &iss->skipped_range->key1->value.funcp->operand->value.value.dbval;
440 
441  if (iss->current_op == ISS_OP_NONE)
442  {
443  /* first iteration of index skip scan; set up range for fetching first value. key1 might be set but will be
444  * ignored for INF_INF range. */
446  iss->skipped_range->range = INF_INF;
447  }
448  else if (iss->current_op == ISS_OP_DO_RANGE_SEARCH)
449  {
450  /* find out whether the first column of the index is asc or desc */
451  descending_scan = (isidp->bt_scan.use_desc_index ? true : false);
452  if (descending_skip_key)
453  {
454  descending_scan = !descending_scan;
455  }
456 
457  if (descending_scan)
458  {
459  /* if we're doing a descending scan, we can stop before searching for first_column < NULL since it won't
460  * produce any results */
461  if (DB_IS_NULL (last_key))
462  {
463  pr_clear_value (last_key);
464  db_make_null (last_key);
465 
466  return S_END;
467  }
468 
469  /* set the upper bound to last used key value and lower bound to NULL (i.e. infinity) */
470  iss->skipped_range->key2 = iss->skipped_range->key1;
471  iss->skipped_range->key1 = NULL;
472  }
473 
474  /* set up ISS state for searching next distinct key */
476  iss->skipped_range->range = (descending_scan ? INF_LT : GT_INF);
477  }
478  else
479  {
480  /* operator is neither ISS_OP_NONE nor ISS_OP_DO_RANGE_SEARCH; we shouldn't be here */
481  assert_release (false);
483 
484  return S_ERROR;
485  }
486 
487  /* populate details structure for the fetch range so we can load it */
488  fetch_range_det.key_cnt = 1;
489  fetch_range_det.key_ranges = iss->skipped_range;
490  fetch_range_det.key_pred.pred_expr = NULL;
491  fetch_range_det.key_pred.pr_eval_fnc = NULL;
492  fetch_range_det.key_pred.regu_list = NULL;
493  fetch_range_det.range_type = R_RANGE;
494  fetch_range_det.part_key_desc = descending_skip_key;
495 
496  /* save current range details */
497  if (scan_save_range_details (isidp, &scan_range_det) != NO_ERROR)
498  {
499  if (descending_scan)
500  {
501  /* return range to initial state before exit */
502  iss->skipped_range->key1 = iss->skipped_range->key2;
503  iss->skipped_range->key2 = NULL;
504  }
505  return S_ERROR;
506  }
507 
508  /* load the range we set up for fetching the next key of the first column */
509  scan_restore_range_details (&fetch_range_det, isidp);
510 
511  isidp->curr_keyno = -1;
512 
513  /* run a scan to get next key for first index column; value will be stored in the lower (or higher) bound of the
514  * fetch range (i.e. in last_key) */
515  if (scan_get_index_oidset (thread_p, scan_id, NULL, NULL) != NO_ERROR)
516  {
517  if (descending_scan)
518  {
519  /* return range to initial state before exit */
520  iss->skipped_range->key1 = iss->skipped_range->key2;
521  iss->skipped_range->key2 = NULL;
522  }
523  scan_restore_range_details (&scan_range_det, isidp);
524  return S_ERROR;
525  }
526 
527  /* undo bounds swapping if scan is descending */
528  if (descending_scan)
529  {
530  iss->skipped_range->key1 = iss->skipped_range->key2;
531  iss->skipped_range->key2 = NULL;
532  }
533 
534  /* as soon as the scan returned, convert the midxkey dbvalue to real db value (if necessary) */
535  if (scan_id->s.isid.oids_count == 0)
536  {
537  /* no other keys exist; restore scan range and exit */
538  scan_restore_range_details (&scan_range_det, isidp);
539  return S_END;
540  }
541  else if (DB_VALUE_DOMAIN_TYPE (last_key) == DB_TYPE_MIDXKEY)
542  {
543  /* scan_get_index_oidset() returned a midxkey */
544  DB_VALUE first_midxkey_val;
545  DB_VALUE tmp;
546  int ret;
547 
548  /* initialize temporary variables */
549  db_make_null (&first_midxkey_val);
550  db_make_null (&tmp);
551 
552  /* put pointer to first value of midxkey into first_midxkey_val */
553  ret = pr_midxkey_get_element_nocopy (&last_key->data.midxkey, 0, &first_midxkey_val, NULL, NULL);
554  if (ret != NO_ERROR)
555  {
556  scan_restore_range_details (&scan_range_det, isidp);
557  return S_ERROR;
558  }
559 
560  /* first_midxkey_val may hold pointer to first value from last_key, which we actually want to place in last_key.
561  * steps: 1. clone first_midxkey_val to a temp variable so we have a DB_VALUE independent of last_key 2. clear
562  * last_key (no longer holds important data) 3. clone temp variable to last_key (for later use) 4. clear tmp (we
563  * no longer need it) */
564  pr_clone_value (&first_midxkey_val, &tmp);
565  pr_clear_value (last_key);
566  pr_clone_value (&tmp, last_key);
567  pr_clear_value (&tmp);
568  pr_clear_value (&first_midxkey_val);
569  }
570 
571  /* use last_key in scan_range */
572  for (i = 0; i < scan_range_det.key_cnt; i++)
573  {
574  KEY_RANGE *kr = &(scan_range_det.key_ranges[i]);
575 
576  if (kr == NULL)
577  {
578  continue;
579  }
580 
581  if (kr->key1 != NULL)
582  {
585 
586  if (kr->key1->value.funcp->operand != NULL)
587  {
588  REGU_VARIABLE *regu = &kr->key1->value.funcp->operand->value;
589 
590  regu->type = TYPE_DBVAL;
591  regu->domain = tp_domain_resolve_default (DB_VALUE_DOMAIN_TYPE (last_key));
592 
593  pr_clear_value (&regu->value.dbval);
594  pr_clone_value (last_key, &regu->value.dbval);
595  }
596  }
597 
598  if (kr->key2 != NULL)
599  {
602 
603  if (kr->key2->value.funcp->operand != NULL)
604  {
605  REGU_VARIABLE *regu = &kr->key2->value.funcp->operand->value;
606 
607  regu->type = TYPE_DBVAL;
608  regu->domain = tp_domain_resolve_default (DB_VALUE_DOMAIN_TYPE (last_key));
609 
610  pr_clear_value (&regu->value.dbval);
611  pr_clone_value (last_key, &regu->value.dbval);
612  }
613  }
614  }
615 
616  /* restore the range used for normal scanning */
617  scan_restore_range_details (&scan_range_det, isidp);
618 
619  /* prepare for range search */
621  isidp->curr_keyno = -1;
622 
623  return S_SUCCESS;
624 }
625 
626 /*
627  * scan_init_scan_pred () - initialize SCAN_PRED structure
628  * return: none
629  */
630 static void
631 scan_init_scan_pred (SCAN_PRED * scan_pred_p, regu_variable_list_node * regu_list, PRED_EXPR * pred_expr,
632  PR_EVAL_FNC pr_eval_fnc)
633 {
634  assert (scan_pred_p != NULL);
635 
636  scan_pred_p->regu_list = regu_list;
637  scan_pred_p->pred_expr = pred_expr;
638  scan_pred_p->pr_eval_fnc = pr_eval_fnc;
639 }
640 
641 /*
642  * scan_init_scan_attrs () - initialize SCAN_ATTRS structure
643  * return: none
644  */
645 static void
646 scan_init_scan_attrs (SCAN_ATTRS * scan_attrs_p, int num_attrs, ATTR_ID * attr_ids, HEAP_CACHE_ATTRINFO * attr_cache)
647 {
648  assert (scan_attrs_p != NULL);
649 
650  scan_attrs_p->num_attrs = num_attrs;
651  scan_attrs_p->attr_ids = attr_ids;
652  scan_attrs_p->attr_cache = attr_cache;
653 }
654 
655 /*
656  * scan_init_filter_info () - initialize FILTER_INFO structure as a data/key filter
657  * return: none
658  */
659 void
661  val_list_node * val_list, VAL_DESCR * val_descr, OID * class_oid, int btree_num_attrs,
662  ATTR_ID * btree_attr_ids, int *num_vstr_ptr, ATTR_ID * vstr_ids)
663 {
664  assert (filter_info_p != NULL);
665 
666  filter_info_p->scan_pred = scan_pred;
667  filter_info_p->scan_attrs = scan_attrs;
668  filter_info_p->val_list = val_list;
669  filter_info_p->val_descr = val_descr;
670  filter_info_p->class_oid = class_oid;
671  filter_info_p->btree_num_attrs = btree_num_attrs;
672  filter_info_p->btree_attr_ids = btree_attr_ids;
673  filter_info_p->num_vstr_ptr = num_vstr_ptr;
674  filter_info_p->vstr_ids = vstr_ids;
675  filter_info_p->func_idx_col_id = -1;
676 }
677 
678 /*
679  * scan_init_indx_coverage () - initialize INDX_COV structure
680  * return: error code
681  *
682  * coverage_enabled(in): true if coverage is enabled
683  * output_val_list(in): output val list
684  * regu_val_list(in): regu val list
685  * vd(in): val descriptor
686  * query_id(in): the query id
687  * max_key_len(in): the maximum key length
688  * indx_cov(in/out): index coverage data
689  */
690 static int
691 scan_init_indx_coverage (THREAD_ENTRY * thread_p, int coverage_enabled, valptr_list_node * output_val_list,
692  regu_variable_list_node * regu_val_list, VAL_DESCR * vd, QUERY_ID query_id, int max_key_len,
693  int func_index_col_id, INDX_COV * indx_cov)
694 {
695  int err = NO_ERROR;
696  int num_membuf_pages = 0;
697 
698  if (indx_cov == NULL)
699  {
700  return ER_FAILED;
701  }
702 
703  indx_cov->val_descr = vd;
704  indx_cov->output_val_list = output_val_list;
705  indx_cov->regu_val_list = regu_val_list;
706  indx_cov->query_id = query_id;
707 
708  if (coverage_enabled == false)
709  {
710  indx_cov->type_list = NULL;
711  indx_cov->list_id = NULL;
712  indx_cov->tplrec = NULL;
713  indx_cov->lsid = NULL;
714  indx_cov->max_tuples = 0;
715  indx_cov->func_index_col_id = -1;
716  return NO_ERROR;
717  }
718 
719  indx_cov->func_index_col_id = func_index_col_id;
720  indx_cov->type_list =
722  if (indx_cov->type_list == NULL)
723  {
725  goto exit_on_error;
726  }
727 
728  if (qdata_get_valptr_type_list (thread_p, output_val_list, indx_cov->type_list) != NO_ERROR)
729  {
730  err = ER_FAILED;
731  goto exit_on_error;
732  }
733 
734  /*
735  * Covering index scan needs large-size memory buffer in order to decrease
736  * the number of times doing stop-and-resume during btree_range_search.
737  * To do it, QFILE_FLAG_USE_KEY_BUFFER is introduced. If the flag is set,
738  * the list file allocates PRM_INDEX_SCAN_KEY_BUFFER_PAGES pages memory
739  * for its memory buffer, which is generally larger than prm_get_integer_value (PRM_ID_TEMP_MEM_BUFFER_PAGES).
740  */
741  indx_cov->list_id = qfile_open_list (thread_p, indx_cov->type_list, NULL, query_id, QFILE_FLAG_USE_KEY_BUFFER);
742  if (indx_cov->list_id == NULL)
743  {
744  err = ER_FAILED;
745  goto exit_on_error;
746  }
747 
748  num_membuf_pages = qmgr_get_temp_file_membuf_pages (indx_cov->list_id->tfile_vfid);
749  assert (num_membuf_pages > 0);
750 
751  if (max_key_len > 0 && num_membuf_pages > 0)
752  {
753  indx_cov->max_tuples = num_membuf_pages * IO_PAGESIZE / max_key_len;
754  indx_cov->max_tuples = MAX (indx_cov->max_tuples, 1);
755  }
756  else
757  {
759  }
760 
761  indx_cov->tplrec = (QFILE_TUPLE_RECORD *) db_private_alloc (thread_p, sizeof (QFILE_TUPLE_RECORD));
762  if (indx_cov->tplrec == NULL)
763  {
765  goto exit_on_error;
766  }
767  indx_cov->tplrec->size = 0;
768  indx_cov->tplrec->tpl = NULL;
769 
770  indx_cov->lsid = (QFILE_LIST_SCAN_ID *) db_private_alloc (thread_p, sizeof (QFILE_LIST_SCAN_ID));
771  if (indx_cov->lsid == NULL)
772  {
774  goto exit_on_error;
775  }
776  indx_cov->lsid->status = S_CLOSED;
777 
778  return NO_ERROR;
779 
780 exit_on_error:
781 
782  if (indx_cov->type_list != NULL)
783  {
784  if (indx_cov->type_list->domp != NULL)
785  {
786  db_private_free_and_init (thread_p, indx_cov->type_list->domp);
787  }
788  db_private_free_and_init (thread_p, indx_cov->type_list);
789  }
790 
791  if (indx_cov->list_id != NULL)
792  {
794  }
795 
796  if (indx_cov->tplrec != NULL)
797  {
798  if (indx_cov->tplrec->tpl != NULL)
799  {
800  db_private_free_and_init (thread_p, indx_cov->tplrec->tpl);
801  }
802  db_private_free_and_init (thread_p, indx_cov->tplrec);
803  }
804 
805  if (indx_cov->lsid != NULL)
806  {
807  db_private_free_and_init (thread_p, indx_cov->lsid);
808  }
809 
810  return err;
811 }
812 
813 /*
814  * scan_init_index_key_limit () - initialize/reset index key limits
815  * return: error code
816  */
817 static int
818 scan_init_index_key_limit (THREAD_ENTRY * thread_p, INDX_SCAN_ID * isidp, KEY_INFO * key_infop, VAL_DESCR * vd)
819 {
820  DB_VALUE *dbvalp;
822  bool is_lower_limit_negative = false;
823  TP_DOMAIN_STATUS dom_status;
824 
825  if (key_infop->key_limit_l != NULL)
826  {
827  if (fetch_peek_dbval (thread_p, key_infop->key_limit_l, vd, NULL, NULL, NULL, &dbvalp) != NO_ERROR)
828  {
829  return ER_FAILED;
830  }
831  dom_status = tp_value_coerce (dbvalp, dbvalp, domainp);
832  if (dom_status != DOMAIN_COMPATIBLE)
833  {
834  (void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbvalp, domainp);
835 
836  return ER_FAILED;
837  }
838 
839  if (DB_VALUE_DOMAIN_TYPE (dbvalp) != DB_TYPE_BIGINT)
840  {
843  }
844  else
845  {
846  isidp->key_limit_lower = db_get_bigint (dbvalp);
847  }
848 
849  if (isidp->key_limit_lower < 0)
850  {
851  if (key_infop->is_user_given_keylimit == true)
852  {
853  /* We don't allow users to give us a bad keylimit bound */
854 
855  /* still want to have better error code */
858  }
859 
860  /* Optimizer adopts keylimit optimization */
861 
862  /* SELECT * from t where ROWNUM = 0 order by a: this would sometimes get optimized using keylimit, if the
863  * circumstances are right. in this case, the lower limit would be "0-1", effectiveley -1. We cannot allow
864  * that to happen, since -1 is a special value meaning "there is no lower limit", and certain critical
865  * decisions (such as resetting the key limit for multiple ranges) depend on knowing whether or not there is
866  * a lower key limit. We set a flag to remember, later on, to "adjust" the key limits such that, if the lower
867  * limit is negative, to return no results.
868  */
869  is_lower_limit_negative = true;
870  }
871  }
872  else
873  {
874  isidp->key_limit_lower = -1;
875  }
876 
877  if (key_infop->key_limit_u != NULL)
878  {
879  if (fetch_peek_dbval (thread_p, key_infop->key_limit_u, vd, NULL, NULL, NULL, &dbvalp) != NO_ERROR)
880  {
881  return ER_FAILED;
882  }
883  dom_status = tp_value_coerce (dbvalp, dbvalp, domainp);
884  if (dom_status != DOMAIN_COMPATIBLE)
885  {
886  (void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbvalp, domainp);
887 
888  return ER_FAILED;
889  }
890  if (DB_VALUE_DOMAIN_TYPE (dbvalp) != DB_TYPE_BIGINT)
891  {
894  }
895  else
896  {
897  isidp->key_limit_upper = db_get_bigint (dbvalp);
898  }
899 
900  if (isidp->key_limit_upper < 0)
901  {
902  if (key_infop->is_user_given_keylimit == true)
903  {
904  /* We don't allow users to give us a bad keylimit bound */
905 
906  /* still want to have better error code */
909  }
910 
911  /* Optimizer adopts keylimit optimization */
912 
913  /* Try to sanitize the upper value. It might have been computed from operations on host variables, which are
914  * unpredictable.
915  */
916  isidp->key_limit_upper = 0;
917  }
918  }
919  else
920  {
921  isidp->key_limit_upper = -1;
922  }
923 
924  if (is_lower_limit_negative && isidp->key_limit_upper > 0)
925  {
926  /* decrease the upper limit: key_limit_lower is negative */
927  isidp->key_limit_upper += isidp->key_limit_lower;
928  if (isidp->key_limit_upper < 0)
929  {
930  isidp->key_limit_upper = 0;
931  }
932  isidp->key_limit_lower = 0; /* reset it to something usable */
933  }
934 
935  return NO_ERROR;
936 }
937 
938 /*
939  * scan_alloc_oid_list () - Allocate an index scan OID list.
940  *
941  * return : Error code.
942  * oid_buf_p (out) : Allocated buffer.
943  * oid_buf_capacity (out) : Allocated buffer capacity.
944  */
945 static int
947 {
948  /* Assert expected arguments. */
949  assert (oid_list_p != NULL && *oid_list_p == NULL);
950 
951  /* Allocate OID list entry. */
952  *oid_list_p = (BTREE_ISCAN_OID_LIST *) malloc (sizeof (BTREE_ISCAN_OID_LIST));
953  if (*oid_list_p == NULL)
954  {
957  }
958 
959  /* Allocate OID list buffer. */
960  (*oid_list_p)->capacity = ISCAN_OID_BUFFER_CAPACITY / OR_OID_SIZE;
961  (*oid_list_p)->oidp = (OID *) malloc ((*oid_list_p)->capacity * OR_OID_SIZE);
962  if ((*oid_list_p)->oidp == NULL)
963  {
964  /* Could not allocate memory. */
966 
967  /* Free already allocated. */
968  free_and_init (*oid_list_p);
970  }
971  /* Allocation successful. */
972  /* Initialize other fields. */
973  (*oid_list_p)->next_list = NULL;
974  (*oid_list_p)->max_oid_cnt = (*oid_list_p)->capacity;
975  (*oid_list_p)->oid_cnt = 0;
976  return NO_ERROR;
977 }
978 
979 /*
980  * scan_free_oid_list () - Free an index scan OID list.
981  *
982  * return : void
983  */
984 static void
986 {
987  assert (oid_list_p != NULL);
988 
989  if (oid_list_p->oidp != NULL)
990  {
991  free_and_init (oid_list_p->oidp);
992  }
993  free_and_init (oid_list_p);
994 }
995 
996 /*
997  * scan_alloc_iscan_oid_buf_list () - Allocate or use a preallocated buffer for index scan OID list.
998  *
999  * return : Error code.
1000  * oid_list (out) : Output OID list with allocated buffer.
1001  */
1002 static int
1004 {
1005 #if defined (SERVER_MODE)
1006  int rv;
1007 #endif /* SERVER_MODE */
1008  int error_code = NO_ERROR;
1009 
1010  /* Assert expected argument. */
1011  assert (oid_list != NULL && *oid_list == NULL);
1012 
1013  /* Is buffer empty? */
1014  if (scan_Iscan_oid_buf_list != NULL)
1015  {
1016  /* Not empty. */
1017  /* Protect by mutex and try to get from buffer. */
1018  rv = pthread_mutex_lock (&scan_Iscan_oid_buf_list_mutex);
1019  /* Was buffer emptied? */
1020  if (scan_Iscan_oid_buf_list != NULL)
1021  {
1022  /* Not empty */
1023  /* Pop first entry. */
1024  *oid_list = scan_Iscan_oid_buf_list;
1025 
1026  /* Update buffer. */
1027  scan_Iscan_oid_buf_list = scan_Iscan_oid_buf_list->next_list;
1028  scan_Iscan_oid_buf_list_count--;
1029  pthread_mutex_unlock (&scan_Iscan_oid_buf_list_mutex);
1030 
1031  /* Reset next_list link. */
1032  (*oid_list)->next_list = NULL;
1033  return NO_ERROR;
1034  }
1035  /* Empty. */
1036  pthread_mutex_unlock (&scan_Iscan_oid_buf_list_mutex);
1037  }
1038 
1039  /* Allocate a new OID list entry. */
1040  error_code = scan_alloc_oid_list (oid_list);
1041  if (error_code != NO_ERROR)
1042  {
1043  ASSERT_ERROR ();
1044  return error_code;
1045  }
1046  /* Safe guard. */
1047  assert (*oid_list != NULL);
1048  assert ((*oid_list)->oidp != NULL);
1049  assert ((*oid_list)->capacity > 0);
1050 
1051  /* Success. */
1052  return NO_ERROR;
1053 }
1054 
1055 /*
1056  * scan_free_iscan_oid_buf_list () - Free OID buffer from OID list of index scan.
1057  *
1058  * return : Void.
1059  * oid_list (in) : OID list to free.
1060  */
1061 static void
1063 {
1064 #if defined (SERVER_MODE)
1065  int rv;
1066 #endif /* SERVER_MODE */
1067 
1068  /* Free entry. */
1069  rv = pthread_mutex_lock (&scan_Iscan_oid_buf_list_mutex);
1070  /* Is buffer at its full capacity? */
1071  if (scan_Iscan_oid_buf_list_count < MAX_NTRANS)
1072  {
1073  /* Add oid_list to scan_Iscan_oid_buf_list */
1074  oid_list->next_list = scan_Iscan_oid_buf_list;
1075  scan_Iscan_oid_buf_list = oid_list;
1076  scan_Iscan_oid_buf_list_count++;
1077  }
1078  else
1079  {
1080  /* Too many buffers, just free it. */
1081  scan_free_oid_list (oid_list);
1082  }
1083  pthread_mutex_unlock (&scan_Iscan_oid_buf_list_mutex);
1084 }
1085 
1086 /*
1087  * rop_to_range () - map left/right to range operator
1088  * return:
1089  * range(out): full-RANGE operator
1090  * left(in): left-side range operator
1091  * right(in): right-side range operator
1092  */
1093 static void
1094 rop_to_range (RANGE * range, ROP_TYPE left, ROP_TYPE right)
1095 {
1096  int i;
1097 
1098  *range = NA_NA;
1099 
1100  for (i = 0; i < rop_range_table_size; i++)
1101  {
1102  if (left == rop_range_table[i].left && right == rop_range_table[i].right)
1103  {
1104  /* found match */
1105  *range = rop_range_table[i].range;
1106  break;
1107  }
1108  }
1109 }
1110 
1111 /*
1112  * range_to_rop () - map range to left/right operator
1113  * return:
1114  * left(out): left-side range operator
1115  * right(out): right-side range operator
1116  * range(in): full-RANGE operator
1117  */
1118 static void
1119 range_to_rop (ROP_TYPE * left, ROP_TYPE * right, RANGE range)
1120 {
1121  int i;
1122 
1123  *left = ROP_NA;
1124  *right = ROP_NA;
1125 
1126  for (i = 0; i < rop_range_table_size; i++)
1127  {
1128  if (range == rop_range_table[i].range)
1129  {
1130  /* found match */
1131  *left = rop_range_table[i].left;
1132  *right = rop_range_table[i].right;
1133  break;
1134  }
1135  }
1136 }
1137 
1138 /*
1139  * scan_key_compare ()
1140  * val1(in):
1141  * val2(in):
1142  * num_index_term(in):
1143  * return:
1144  */
1145 static int
1146 scan_key_compare (DB_VALUE * val1, DB_VALUE * val2, int num_index_term)
1147 {
1148  int rc = DB_UNK;
1149  DB_TYPE key_type;
1150  int dummy_diff_column;
1151  bool dummy_dom_is_desc, dummy_next_dom_is_desc;
1152  static bool ignore_trailing_space = prm_get_bool_value (PRM_ID_IGNORE_TRAILING_SPACE);
1153  static int coerce = (ignore_trailing_space) ? 1 : 3;
1154 
1155  if (val1 == NULL || val2 == NULL)
1156  {
1157  assert_release (0);
1158  return rc;
1159  }
1160 
1161  if (DB_IS_NULL (val1))
1162  {
1163  if (DB_IS_NULL (val2))
1164  {
1165  rc = DB_EQ;
1166  }
1167  else
1168  {
1169  rc = DB_LT;
1170  }
1171  }
1172  else if (DB_IS_NULL (val2))
1173  {
1174  rc = DB_GT;
1175  }
1176  else
1177  {
1178  key_type = DB_VALUE_DOMAIN_TYPE (val1);
1179  if (key_type == DB_TYPE_MIDXKEY)
1180  {
1181  rc =
1182  pr_midxkey_compare (db_get_midxkey (val1), db_get_midxkey (val2), 1, 1, num_index_term, NULL, NULL,
1183  NULL, &dummy_diff_column, &dummy_dom_is_desc, &dummy_next_dom_is_desc);
1184  }
1185  else
1186  {
1187  /*
1188  * we need to compare without ignoring trailing space
1189  * corece = 3 enforce"no-ignore trailing space
1190  */
1191  rc = tp_value_compare (val1, val2, coerce, 1);
1192  }
1193  }
1194 
1195  return rc;
1196 }
1197 
1198 /*
1199  * compare_val_op () - compare two values specified by range operator
1200  * return:
1201  * val1(in):
1202  * op1(in):
1203  * val2(in):
1204  * op2(in):
1205  * num_index_term(in):
1206  */
1207 static ROP_TYPE
1208 compare_val_op (DB_VALUE * val1, ROP_TYPE op1, DB_VALUE * val2, ROP_TYPE op2, int num_index_term)
1209 {
1210  int rc;
1211 
1212  if (op1 == ROP_GT_INF) /* val1 is -INF */
1213  {
1214  return (op1 == op2) ? ROP_EQ : ROP_LT;
1215  }
1216  if (op1 == ROP_LT_INF) /* val1 is +INF */
1217  {
1218  return (op1 == op2) ? ROP_EQ : ROP_GT;
1219  }
1220  if (op2 == ROP_GT_INF) /* val2 is -INF */
1221  {
1222  return (op2 == op1) ? ROP_EQ : ROP_GT;
1223  }
1224  if (op2 == ROP_LT_INF) /* val2 is +INF */
1225  {
1226  return (op2 == op1) ? ROP_EQ : ROP_LT;
1227  }
1228 
1229  rc = scan_key_compare (val1, val2, num_index_term);
1230 
1231  if (rc == DB_EQ)
1232  {
1233  /* (val1, op1) == (val2, op2) */
1234  if (op1 == op2)
1235  {
1236  return ROP_EQ;
1237  }
1238  if (op1 == ROP_EQ || op1 == ROP_GE || op1 == ROP_LE)
1239  {
1240  if (op2 == ROP_EQ || op2 == ROP_GE || op2 == ROP_LE)
1241  {
1242  return ROP_EQ;
1243  }
1244  return (op2 == ROP_GT) ? ROP_LT_ADJ : ROP_GT_ADJ;
1245  }
1246  if (op1 == ROP_GT)
1247  {
1248  if (op2 == ROP_EQ || op2 == ROP_GE || op2 == ROP_LE)
1249  {
1250  return ROP_GT_ADJ;
1251  }
1252  return (op2 == ROP_LT) ? ROP_GT : ROP_EQ;
1253  }
1254  if (op1 == ROP_LT)
1255  {
1256  if (op2 == ROP_EQ || op2 == ROP_GE || op2 == ROP_LE)
1257  {
1258  return ROP_LT_ADJ;
1259  }
1260  return (op2 == ROP_GT) ? ROP_LT : ROP_EQ;
1261  }
1262  }
1263  else if (rc == DB_LT)
1264  {
1265  /* (val1, op1) < (val2, op2) */
1266  return ROP_LT;
1267  }
1268  else if (rc == DB_GT)
1269  {
1270  /* (val1, op1) > (val2, op2) */
1271  return ROP_GT;
1272  }
1273 
1274  /* tp_value_compare() returned error? */
1275  return (rc == DB_EQ) ? ROP_EQ : ROP_NA;
1276 }
1277 
1278 /*
1279  * key_val_compare () - key value sorting function
1280  * return:
1281  * p1 (in): pointer to key1 range
1282  * p2 (in): pointer to key2 range
1283  */
1284 static int
1285 key_val_compare (const void *p1, const void *p2)
1286 {
1287  int p1_num_index_term, p2_num_index_term;
1288  DB_VALUE *p1_key, *p2_key;
1289 
1290  p1_num_index_term = ((KEY_VAL_RANGE *) p1)->num_index_term;
1291  p2_num_index_term = ((KEY_VAL_RANGE *) p2)->num_index_term;
1292  assert_release (p1_num_index_term == p2_num_index_term);
1293 
1294  p1_key = &((KEY_VAL_RANGE *) p1)->key1;
1295  p2_key = &((KEY_VAL_RANGE *) p2)->key1;
1296 
1297  return scan_key_compare (p1_key, p2_key, p1_num_index_term);
1298 }
1299 
1300 /*
1301  * eliminate_duplicated_keys () - elimnate duplicated key values
1302  * return: number of keys, -1 for error
1303  * key_vals (in): pointer to array of KEY_VAL_RANGE structure
1304  * key_cnt (in): number of keys; size of key_vals
1305  */
1306 static int
1308 {
1309  int n;
1310  KEY_VAL_RANGE *curp, *nextp;
1311  static bool ignore_trailing_space = prm_get_bool_value (PRM_ID_IGNORE_TRAILING_SPACE);
1312  static int coerce = (ignore_trailing_space) ? 1 : 3;
1313 
1314  curp = key_vals;
1315  nextp = key_vals + 1;
1316  n = 0;
1317  while (key_cnt > 1 && n < key_cnt - 1)
1318  {
1319  /*
1320  * we need to compare without ignoring trailing space
1321  * corece = 3 enforce"no-ignore trailing space
1322  */
1323  if (tp_value_compare (&curp->key1, &nextp->key1, coerce, 1) == DB_EQ)
1324  {
1325  pr_clear_value (&nextp->key1);
1326  pr_clear_value (&nextp->key2);
1327  memmove (nextp, nextp + 1, sizeof (KEY_VAL_RANGE) * (key_cnt - n - 2));
1328  key_cnt--;
1329  }
1330  else
1331  {
1332  curp++;
1333  nextp++;
1334  n++;
1335  }
1336  }
1337 
1338  return key_cnt;
1339 }
1340 
1341 /*
1342  * merge_key_ranges () - merge search key ranges
1343  * return: number of keys, -1 for error
1344  * key_vals (in): pointer to array of KEY_VAL_RANGE structure
1345  * key_cnt (in): number of keys; size of key_vals
1346  */
1347 static int
1349 {
1350  int cur_n, next_n;
1351  KEY_VAL_RANGE *curp, *nextp;
1352  ROP_TYPE cur_op1, cur_op2, next_op1, next_op2;
1353  ROP_TYPE cmp_1, cmp_2, cmp_3, cmp_4;
1354  bool is_mergeable;
1355 
1356  cmp_1 = cmp_2 = cmp_3 = cmp_4 = ROP_NA;
1357 
1358  curp = key_vals;
1359  cur_n = 0;
1360  while (key_cnt > 1 && cur_n < key_cnt - 1)
1361  {
1362  range_to_rop (&cur_op1, &cur_op2, curp->range);
1363 
1364  nextp = curp + 1;
1365  next_n = cur_n + 1;
1366  while (next_n < key_cnt)
1367  {
1368  range_to_rop (&next_op1, &next_op2, nextp->range);
1369 
1370  /* check if the two key ranges are mergable */
1371  is_mergeable = true; /* init */
1372  cmp_1 = cmp_2 = cmp_3 = cmp_4 = ROP_NA;
1373 
1374  if (is_mergeable == true)
1375  {
1376  cmp_1 = compare_val_op (&curp->key2, cur_op2, &nextp->key1, next_op1, curp->num_index_term);
1377  if (cmp_1 == ROP_NA || cmp_1 == ROP_LT)
1378  {
1379  is_mergeable = false; /* error or disjoint */
1380  }
1381  }
1382 
1383  if (is_mergeable == true)
1384  {
1385  cmp_2 = compare_val_op (&curp->key1, cur_op1, &nextp->key2, next_op2, curp->num_index_term);
1386  if (cmp_2 == ROP_NA || cmp_2 == ROP_GT)
1387  {
1388  is_mergeable = false; /* error or disjoint */
1389  }
1390  }
1391 
1392  if (is_mergeable == true)
1393  {
1394  /* determine the lower bound of the merged key range */
1395  cmp_3 = compare_val_op (&curp->key1, cur_op1, &nextp->key1, next_op1, curp->num_index_term);
1396  if (cmp_3 == ROP_NA)
1397  {
1398  is_mergeable = false;
1399  }
1400  }
1401 
1402  if (is_mergeable == true)
1403  {
1404  /* determine the upper bound of the merged key range */
1405  cmp_4 = compare_val_op (&curp->key2, cur_op2, &nextp->key2, next_op2, curp->num_index_term);
1406  if (cmp_4 == ROP_NA)
1407  {
1408  is_mergeable = false;
1409  }
1410  }
1411 
1412  if (is_mergeable == false)
1413  {
1414  /* they are disjoint */
1415  nextp++;
1416  next_n++;
1417  continue; /* skip and go ahead */
1418  }
1419 
1420  /* determine the lower bound of the merged key range */
1421  if (cmp_3 == ROP_GT_ADJ || cmp_3 == ROP_GT)
1422  {
1423  pr_clear_value (&curp->key1);
1424  curp->key1 = nextp->key1; /* bitwise copy */
1425  db_make_null (&nextp->key1);
1426  cur_op1 = next_op1;
1427  }
1428  else
1429  {
1430  pr_clear_value (&nextp->key1);
1431  }
1432 
1433  /* determine the upper bound of the merged key range */
1434  if (cmp_4 == ROP_LT || cmp_4 == ROP_LT_ADJ)
1435  {
1436  pr_clear_value (&curp->key2);
1437  curp->key2 = nextp->key2; /* bitwise copy */
1438  db_make_null (&nextp->key2);
1439  cur_op2 = next_op2;
1440  }
1441  else
1442  {
1443  pr_clear_value (&nextp->key2);
1444  }
1445 
1446  /* determine the new range type */
1447  rop_to_range (&curp->range, cur_op1, cur_op2);
1448  /* remove merged one(nextp) */
1449  memmove (nextp, nextp + 1, sizeof (KEY_VAL_RANGE) * (key_cnt - next_n - 1));
1450  key_cnt--;
1451  }
1452 
1453  curp++;
1454  cur_n++;
1455  }
1456 
1457  return key_cnt;
1458 }
1459 
1460 /*
1461  * check_key_vals () - check key values
1462  * return: number of keys, -1 for error
1463  * key_vals (in): pointer to array of KEY_VAL_RANGE structure
1464  * key_cnt (in): number of keys; size of key_vals
1465  * chk_fn (in): check function for key_vals
1466  */
1467 static int
1468 check_key_vals (KEY_VAL_RANGE * key_vals, int key_cnt, QPROC_KEY_VAL_FU * key_val_fn)
1469 {
1470  if (key_cnt <= 1)
1471  {
1472  return key_cnt;
1473  }
1474 
1475  qsort ((void *) key_vals, key_cnt, sizeof (KEY_VAL_RANGE), key_val_compare);
1476 
1477  return ((*key_val_fn) (key_vals, key_cnt));
1478 }
1479 
1480 /*
1481  * scan_dbvals_to_midxkey () -
1482  * return: NO_ERROR or ER_code
1483  *
1484  * retval (out):
1485  * indexal (out):
1486  * btree_domainp (in):
1487  * num_term (in):
1488  * func (in):
1489  * vd (in):
1490  * key_minmax (in):
1491  * is_iss (in)
1492  */
1493 static int
1494 scan_dbvals_to_midxkey (THREAD_ENTRY * thread_p, DB_VALUE * retval, bool * indexable, TP_DOMAIN * btree_domainp,
1495  int num_term, REGU_VARIABLE * func, VAL_DESCR * vd, int key_minmax, bool is_iss,
1496  DB_VALUE * fetched_values)
1497 {
1498  int ret = NO_ERROR;
1499  DB_VALUE *val = NULL;
1500  DB_TYPE val_type_id;
1501  DB_MIDXKEY midxkey;
1502 
1503  int idx_ncols = 0, natts, i, j;
1504  int buf_size, nullmap_size;
1505  unsigned char *bits;
1506 
1507  regu_variable_list_node *operand;
1508 
1509  char *nullmap_ptr; /* ponter to boundbits */
1510  char *key_ptr; /* current position in key */
1511 
1512  OR_BUF buf;
1513 
1514  bool need_new_setdomain = false;
1515  TP_DOMAIN *idx_setdomain = NULL, *vals_setdomain = NULL;
1516  TP_DOMAIN *idx_dom = NULL, *val_dom = NULL, *dom = NULL, *next = NULL;
1517  TP_DOMAIN dom_buf;
1518  DB_VALUE *coerced_values = NULL;
1519  bool *has_coerced_values = NULL;
1520 
1521  *indexable = false;
1522 
1523  if (TP_DOMAIN_TYPE (func->domain) != DB_TYPE_MIDXKEY)
1524  {
1525  assert (false);
1526  return ER_FAILED;
1527  }
1528 
1529  idx_ncols = btree_domainp->precision;
1530  if (idx_ncols <= 0)
1531  {
1532  assert (false);
1533  return ER_FAILED;
1534  }
1535 
1536  idx_setdomain = btree_domainp->setdomain;
1537 
1538 #if !defined(NDEBUG)
1539  {
1540  int dom_ncols = 0;
1541 
1542  for (idx_dom = idx_setdomain; idx_dom != NULL; idx_dom = idx_dom->next)
1543  {
1544  dom_ncols++;
1545  if (idx_dom->precision < 0)
1546  {
1547  assert (false);
1548  return ER_FAILED;
1549  }
1550  }
1551 
1552  if (dom_ncols <= 0)
1553  {
1554  assert (false);
1555  return ER_FAILED;
1556  }
1557 
1558  assert (dom_ncols == idx_ncols);
1559  }
1560 #endif /* NDEBUG */
1561 
1562  buf_size = 0;
1563  midxkey.buf = NULL;
1564  midxkey.min_max_val.position = -1;
1565 
1566  /* bitmap is always fully sized */
1567  nullmap_size = OR_MULTI_BOUND_BIT_BYTES (idx_ncols);
1568  buf_size = nullmap_size;
1569 
1570  /* check to need a new setdomain */
1571  for (operand = func->value.funcp->operand, idx_dom = idx_setdomain, i = 0; operand != NULL && idx_dom != NULL;
1572  operand = operand->next, idx_dom = idx_dom->next, i++)
1573  {
1574  ret = fetch_peek_dbval (thread_p, &(operand->value), vd, NULL, NULL, NULL, &val);
1575  if (ret != NO_ERROR)
1576  {
1577  goto err_exit;
1578  }
1579 
1580  pr_clear_value (&fetched_values[i]);
1581  ret = pr_clone_value (val, &fetched_values[i]);
1582  if (ret != NO_ERROR)
1583  {
1584  goto err_exit;
1585  }
1586 
1587  if (DB_IS_NULL (val))
1588  {
1589  if (is_iss && i == 0)
1590  {
1591  /* If this is INDEX SKIP SCAN we allow the first column to be NULL and we don't need a new domain for it */
1592  continue;
1593  }
1594  else
1595  {
1596  /* to fix multi-column index NULL problem */
1597  goto end;
1598  }
1599  }
1600 
1601  val_type_id = DB_VALUE_DOMAIN_TYPE (val);
1602  if (TP_IS_STRING_TYPE (val_type_id))
1603  {
1604  /* we need to check for maxes */
1605  if (val->data.ch.medium.is_max_string)
1606  {
1607  /* oops, we found max. */
1608  midxkey.min_max_val.position = i;
1609  midxkey.min_max_val.type = MAX_COLUMN;
1610 
1611  /* just stop here */
1612  break;
1613  }
1614  }
1615 
1616  if (TP_DOMAIN_TYPE (idx_dom) != val_type_id)
1617  {
1618  /* allocate DB_VALUE array to store coerced values. */
1619  if (has_coerced_values == NULL)
1620  {
1621  assert (has_coerced_values == NULL && coerced_values == NULL);
1622  coerced_values = (DB_VALUE *) db_private_alloc (thread_p, sizeof (DB_VALUE) * idx_ncols);
1623  if (coerced_values == NULL)
1624  {
1625  goto err_exit;
1626  }
1627  for (j = 0; j < idx_ncols; j++)
1628  {
1629  db_make_null (&coerced_values[j]);
1630  }
1631 
1632  has_coerced_values = (bool *) db_private_alloc (thread_p, sizeof (bool) * idx_ncols);
1633  if (has_coerced_values == NULL)
1634  {
1635  goto err_exit;
1636  }
1637  memset (has_coerced_values, 0x0, sizeof (bool) * idx_ncols);
1638  }
1639 
1640  /* Coerce the value to index domain. If there is loss, we should make a new setdomain. */
1641  ret = tp_value_coerce_strict (val, &coerced_values[i], idx_dom);
1642  if (ret != NO_ERROR)
1643  {
1644  need_new_setdomain = true;
1645  }
1646  else
1647  {
1648  has_coerced_values[i] = true;
1649  }
1650  }
1651  else if (TP_DOMAIN_TYPE (idx_dom) == DB_TYPE_NUMERIC || TP_DOMAIN_TYPE (idx_dom) == DB_TYPE_CHAR
1652  || TP_DOMAIN_TYPE (idx_dom) == DB_TYPE_BIT || TP_DOMAIN_TYPE (idx_dom) == DB_TYPE_NCHAR)
1653  {
1654  /* skip variable string domain : DB_TYPE_VARCHAR, DB_TYPE_VARNCHAR, DB_TYPE_VARBIT */
1655 
1656  val_dom = tp_domain_resolve_value (val, &dom_buf);
1657  if (val_dom == NULL)
1658  {
1659  goto err_exit;
1660  }
1661 
1662  if (!tp_domain_match_ignore_order (idx_dom, val_dom, TP_EXACT_MATCH))
1663  {
1664  need_new_setdomain = true;
1665  }
1666  }
1667  }
1668 
1669  /* calculate midxkey's size & make a new setdomain if need */
1670  /* NOTICE that this will stop the iteration on MAX_COLUMN value if exists.
1671  * Remaining key values including MAX_COLUMN position will be filled as NULL
1672  * by btree_coerce_key at the end of this function.
1673  */
1674  for (operand = func->value.funcp->operand, idx_dom = idx_setdomain, natts = 0;
1675  operand != NULL && idx_dom != NULL
1676  && (midxkey.min_max_val.position == -1 || natts < midxkey.min_max_val.position);
1677  operand = operand->next, idx_dom = idx_dom->next, natts++)
1678  {
1679  /* If there is coerced value, we will use it regardless of whether a new setdomain is required or not. */
1680  if (has_coerced_values != NULL && has_coerced_values[natts] == true)
1681  {
1682  assert (coerced_values != NULL);
1683  val = &coerced_values[natts];
1684  }
1685  else
1686  {
1687  assert (fetched_values != NULL);
1688  val = &fetched_values[natts];
1689  }
1690 
1691  if (need_new_setdomain == true)
1692  {
1693  /* make a value's domain */
1694  val_dom = tp_domain_resolve_value (val, &dom_buf);
1695  if (val_dom == NULL)
1696  {
1697  goto err_exit;
1698  }
1699 
1700  val_dom = tp_domain_copy (val_dom, false);
1701  if (val_dom == NULL)
1702  {
1703  goto err_exit;
1704  }
1705  val_dom->is_desc = idx_dom->is_desc;
1706 
1707  /* make a new setdomain */
1708  if (vals_setdomain == NULL)
1709  {
1710  assert (dom == NULL);
1711  vals_setdomain = val_dom;
1712  }
1713  else
1714  {
1715  assert (dom != NULL);
1716  dom->next = val_dom;
1717  }
1718 
1719  dom = val_dom;
1720  }
1721  else
1722  {
1723  dom = idx_dom;
1724  }
1725 
1726  if (DB_IS_NULL (val))
1727  {
1728  if (is_iss && natts == 0)
1729  {
1730  /* We allow the first column to be NULL and we're not writing it in the MIDXKEY buffer */
1731  continue;
1732  }
1733  else
1734  {
1735  /* impossible case */
1736  assert_release (false);
1737  goto end;
1738  }
1739  }
1740 
1741  buf_size += dom->type->get_index_size_of_value (val);
1742  }
1743 
1744  /* add more domain to setdomain for partial key */
1745  if (need_new_setdomain == true)
1746  {
1747  assert (dom != NULL);
1748  if (idx_dom != NULL)
1749  {
1750  val_dom = tp_domain_copy (idx_dom, false);
1751  if (val_dom == NULL)
1752  {
1753  goto err_exit;
1754  }
1755 
1756  dom->next = val_dom;
1757  }
1758  }
1759 
1760  midxkey.buf = (char *) db_private_alloc (thread_p, buf_size);
1761  if (midxkey.buf == NULL)
1762  {
1763  retval->need_clear = false;
1764  goto err_exit;
1765  }
1766 
1767  nullmap_ptr = midxkey.buf;
1768  key_ptr = nullmap_ptr + nullmap_size;
1769 
1770  OR_BUF_INIT (buf, key_ptr, buf_size - nullmap_size);
1771 
1772  if (nullmap_size > 0)
1773  {
1774  bits = (unsigned char *) nullmap_ptr;
1775  for (i = 0; i < nullmap_size; i++)
1776  {
1777  bits[i] = (unsigned char) 0;
1778  }
1779  }
1780 
1781  /* generate multi columns key (values -> midxkey.buf) */
1782  for (operand = func->value.funcp->operand, i = 0, dom = (vals_setdomain != NULL) ? vals_setdomain : idx_setdomain;
1783  operand != NULL && dom != NULL && (i < natts); operand = operand->next, dom = dom->next, i++)
1784  {
1785  if (has_coerced_values != NULL && has_coerced_values[i] == true)
1786  {
1787  assert (coerced_values != NULL);
1788  val = &coerced_values[i];
1789  }
1790  else
1791  {
1792  assert (fetched_values != NULL);
1793  val = &fetched_values[i];
1794  }
1795 
1796  if (DB_IS_NULL (val))
1797  {
1798  if (is_iss && i == 0)
1799  {
1800  /* There is nothing to write for NULL. Just make sure the bit is not set */
1801  OR_CLEAR_BOUND_BIT (nullmap_ptr, i);
1802  continue;
1803  }
1804  else
1805  {
1806  /* impossible case */
1807  assert_release (false);
1808  goto end;
1809  }
1810  }
1811 
1812  dom->type->index_writeval (&buf, val);
1813  OR_ENABLE_BOUND_BIT (nullmap_ptr, i);
1814  }
1815 
1816  assert (buf_size == CAST_BUFLEN (buf.ptr - midxkey.buf));
1817 
1818  /* Make midxkey DB_VALUE */
1819  midxkey.size = buf_size;
1820  midxkey.ncolumns = natts;
1821 
1822  if (vals_setdomain != NULL)
1823  {
1824  midxkey.domain = tp_domain_construct (DB_TYPE_MIDXKEY, NULL, idx_ncols, 0, vals_setdomain);
1825  if (midxkey.domain == NULL)
1826  {
1827  goto err_exit;
1828  }
1829 
1830  midxkey.domain = tp_domain_cache (midxkey.domain);
1831  }
1832  else
1833  {
1834  midxkey.domain = btree_domainp;
1835  }
1836 
1837  ret = db_make_midxkey (retval, &midxkey);
1838  if (ret != NO_ERROR)
1839  {
1840  goto err_exit;
1841  }
1842 
1843  retval->need_clear = true;
1844 
1845  *indexable = true;
1846 
1847  ret = btree_coerce_key (retval, num_term, btree_domainp, key_minmax);
1848 
1849  if (has_coerced_values)
1850  {
1851  db_private_free_and_init (thread_p, has_coerced_values);
1852  }
1853 
1854  if (coerced_values)
1855  {
1856  db_private_free_and_init (thread_p, coerced_values);
1857  }
1858 
1859  return ret;
1860 
1861 end:
1862  if (midxkey.buf)
1863  {
1864  db_private_free_and_init (thread_p, midxkey.buf);
1865  }
1866 
1867  if (vals_setdomain != NULL)
1868  {
1869  for (dom = vals_setdomain; dom != NULL; dom = next)
1870  {
1871  next = dom->next;
1872  tp_domain_free (dom);
1873  }
1874  }
1875 
1876  if (has_coerced_values)
1877  {
1878  db_private_free_and_init (thread_p, has_coerced_values);
1879  }
1880 
1881  if (coerced_values)
1882  {
1883  db_private_free_and_init (thread_p, coerced_values);
1884  }
1885 
1886  return ret;
1887 
1888 err_exit:
1889 
1890  if (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR)
1891  {
1892  ret = ER_FAILED;
1893  }
1894 
1895  goto end;
1896 }
1897 
1898 /*
1899  * scan_regu_key_to_index_key:
1900  */
1901 static int
1903  INDX_SCAN_ID * iscan_id, TP_DOMAIN * btree_domainp, VAL_DESCR * vd)
1904 {
1905  bool indexable = true;
1906  int key_minmax;
1907  int curr_key_prefix_length = 0;
1908  int count;
1909  int ret = NO_ERROR;
1910  DB_TYPE db_type;
1911  int key_len;
1912  regu_variable_list_node *requ_list;
1913 
1914  assert ((key_ranges->range >= GE_LE && key_ranges->range <= INF_LT) || (key_ranges->range == EQ_NA));
1915  assert (!(key_ranges->key1 == NULL && key_ranges->key2 == NULL));
1916 
1917  if (iscan_id->bt_attrs_prefix_length && iscan_id->bt_num_attrs == 1)
1918  {
1919  curr_key_prefix_length = iscan_id->bt_attrs_prefix_length[0];
1920  }
1921 
1922  /* TO_DO : fix to move this to XASL generator */
1923  if (key_ranges->key1)
1924  {
1925  if (key_ranges->key1->type == TYPE_FUNC && key_ranges->key1->value.funcp->ftype == F_MIDXKEY)
1926  {
1927  for (requ_list = key_ranges->key1->value.funcp->operand, count = 0; requ_list; requ_list = requ_list->next)
1928  {
1929  count++;
1930  }
1931  }
1932  else
1933  {
1934  count = 1;
1935  }
1936  key_val_range->num_index_term = count;
1937  }
1938 
1939  if (key_ranges->key2)
1940  {
1941  if (key_ranges->key2->type == TYPE_FUNC && key_ranges->key2->value.funcp->ftype == F_MIDXKEY)
1942  {
1943  for (requ_list = key_ranges->key2->value.funcp->operand, count = 0; requ_list; requ_list = requ_list->next)
1944  {
1945  count++;
1946  }
1947  }
1948  else
1949  {
1950  assert_release (key_val_range->num_index_term <= 1);
1951  count = 1;
1952  }
1953  key_val_range->num_index_term = MAX (key_val_range->num_index_term, count);
1954  }
1955 
1956  if (key_ranges->key1)
1957  {
1958  if (key_ranges->key1->type == TYPE_FUNC && key_ranges->key1->value.funcp->ftype == F_MIDXKEY)
1959  {
1960  if (key_val_range->range == GT_INF || key_val_range->range == GT_LE || key_val_range->range == GT_LT)
1961  {
1962  key_minmax = BTREE_COERCE_KEY_WITH_MAX_VALUE;
1963  }
1964  else
1965  {
1966  key_minmax = BTREE_COERCE_KEY_WITH_MIN_VALUE;
1967  }
1968 
1969  ret =
1970  scan_dbvals_to_midxkey (thread_p, &key_val_range->key1, &indexable, btree_domainp,
1971  key_val_range->num_index_term, key_ranges->key1, vd, key_minmax, iscan_id->iss.use,
1972  iscan_id->fetched_values);
1973  }
1974  else
1975  {
1976  ret = fetch_copy_dbval (thread_p, key_ranges->key1, vd, NULL, NULL, NULL, &key_val_range->key1);
1977  db_type = DB_VALUE_DOMAIN_TYPE (&key_val_range->key1);
1978 
1979  if (ret == NO_ERROR && curr_key_prefix_length > 0)
1980  {
1981  if (TP_IS_CHAR_TYPE (db_type) || TP_IS_BIT_TYPE (db_type))
1982  {
1983  key_len = db_get_string_length (&key_val_range->key1);
1984 
1985  if (key_len > curr_key_prefix_length)
1986  {
1987  ret = db_string_truncate (&key_val_range->key1, curr_key_prefix_length);
1988  key_val_range->is_truncated = true;
1989  }
1990  }
1991  }
1992 
1993  assert (DB_VALUE_TYPE (&key_val_range->key1) != DB_TYPE_MIDXKEY);
1994  }
1995 
1996  if (ret != NO_ERROR || indexable == false)
1997  {
1998  key_val_range->range = NA_NA;
1999 
2000  return ret;
2001  }
2002  }
2003 
2004  if (key_ranges->key2)
2005  {
2006  if (key_ranges->key2->type == TYPE_FUNC && key_ranges->key2->value.funcp->ftype == F_MIDXKEY)
2007  {
2008  if (key_val_range->range == INF_LT || key_val_range->range == GE_LT || key_val_range->range == GT_LT)
2009  {
2010  key_minmax = BTREE_COERCE_KEY_WITH_MIN_VALUE;
2011  }
2012  else
2013  {
2014  key_minmax = BTREE_COERCE_KEY_WITH_MAX_VALUE;
2015  }
2016 
2017  ret =
2018  scan_dbvals_to_midxkey (thread_p, &key_val_range->key2, &indexable, btree_domainp,
2019  key_val_range->num_index_term, key_ranges->key2, vd, key_minmax, iscan_id->iss.use,
2020  iscan_id->fetched_values);
2021  }
2022  else
2023  {
2024  ret = fetch_copy_dbval (thread_p, key_ranges->key2, vd, NULL, NULL, NULL, &key_val_range->key2);
2025 
2026  db_type = DB_VALUE_DOMAIN_TYPE (&key_val_range->key2);
2027 
2028  if (ret == NO_ERROR && curr_key_prefix_length > 0)
2029  {
2030  if (TP_IS_CHAR_TYPE (db_type) || TP_IS_BIT_TYPE (db_type))
2031  {
2032  key_len = db_get_string_length (&key_val_range->key2);
2033 
2034  if (key_len > curr_key_prefix_length)
2035  {
2036  ret = db_string_truncate (&key_val_range->key2, curr_key_prefix_length);
2037  key_val_range->is_truncated = true;
2038  }
2039  }
2040  }
2041 
2042  assert (DB_VALUE_TYPE (&key_val_range->key2) != DB_TYPE_MIDXKEY);
2043  }
2044 
2045  if (ret != NO_ERROR || indexable == false)
2046  {
2047  key_val_range->range = NA_NA;
2048 
2049  return ret;
2050  }
2051  }
2052  else
2053  {
2054  if (key_ranges->key1 == NULL)
2055  {
2056  /* impossible case */
2057  assert (false);
2058 
2059  key_val_range->range = NA_NA;
2060 
2061  return ER_FAILED;
2062  }
2063 
2064  if ((iscan_id->indx_info->range_type == R_KEY || iscan_id->indx_info->range_type == R_KEYLIST)
2065  && key_ranges->key1->type == TYPE_FUNC && key_ranges->key1->value.funcp->ftype == F_MIDXKEY)
2066  {
2067  assert (key_val_range->range == EQ_NA);
2068  ret = pr_clone_value (&key_val_range->key1, &key_val_range->key2);
2069  if (ret != NO_ERROR)
2070  {
2071  key_val_range->range = NA_NA;
2072 
2073  return ret;
2074  }
2075 
2076  /* Set minmax type opposite to key1 */
2077  if (key_val_range->key2.data.midxkey.min_max_val.type == MIN_COLUMN)
2078  {
2079  key_val_range->key2.data.midxkey.min_max_val.type = MAX_COLUMN;
2080  }
2081  else
2082  {
2083  key_val_range->key2.data.midxkey.min_max_val.type = MIN_COLUMN;
2084  }
2085  }
2086  else
2087  {
2088  ret = pr_clone_value (&key_val_range->key1, &key_val_range->key2);
2089  if (ret != NO_ERROR)
2090  {
2091  key_val_range->range = NA_NA;
2092 
2093  return ret;
2094  }
2095  }
2096  }
2097 
2098  if (key_val_range->range == EQ_NA)
2099  {
2100  key_val_range->range = GE_LE;
2101  }
2102 
2103  switch (iscan_id->indx_info->range_type)
2104  {
2105  case R_KEY:
2106  case R_KEYLIST:
2107  /* When key received as NULL, currently this is assumed an UNBOUND value and no object value in the index is
2108  * equal to NULL value in the index scan context. They can be equal to NULL only in the "is NULL" context. */
2109 
2110  /* to fix multi-column index NULL problem */
2111  if (DB_IS_NULL (&key_val_range->key1))
2112  {
2113  key_val_range->range = NA_NA;
2114 
2115  return ret;
2116  }
2117  break;
2118 
2119  case R_RANGE:
2120  case R_RANGELIST:
2121  /* When key received as NULL, currently this is assumed an UNBOUND value and no object value in the index is
2122  * equal to NULL value in the index scan context. They can be equal to NULL only in the "is NULL" context. */
2123  if (key_val_range->range >= GE_LE && key_val_range->range <= GT_LT)
2124  {
2125  /* to fix multi-column index NULL problem */
2126  if (DB_IS_NULL (&key_val_range->key1) || DB_IS_NULL (&key_val_range->key2))
2127  {
2128  key_val_range->range = NA_NA;
2129 
2130  return ret;
2131  }
2132  else
2133  {
2134  int c = DB_UNK;
2135 
2136  c = scan_key_compare (&key_val_range->key1, &key_val_range->key2, key_val_range->num_index_term);
2137 
2138  if (c == DB_UNK)
2139  {
2140  /* impossible case */
2141  assert_release (false);
2142 
2143  key_val_range->range = NA_NA;
2144 
2145  return ER_FAILED;
2146  }
2147  else if (c > 0)
2148  {
2149  key_val_range->range = NA_NA;
2150 
2151  return ret;
2152  }
2153  }
2154  }
2155  else if (key_val_range->range >= GE_INF && key_val_range->range <= GT_INF)
2156  {
2157  /* to fix multi-column index NULL problem */
2158  if (DB_IS_NULL (&key_val_range->key1))
2159  {
2160  key_val_range->range = NA_NA;
2161 
2162  return ret;
2163  }
2164  }
2165  else if (key_val_range->range >= INF_LE && key_val_range->range <= INF_LT)
2166  {
2167  /* to fix multi-column index NULL problem */
2168  if (DB_IS_NULL (&key_val_range->key2))
2169  {
2170  key_val_range->range = NA_NA;
2171 
2172  return ret;
2173  }
2174  }
2175  break;
2176 
2177  default:
2178  assert_release (false);
2179  break; /* impossible case */
2180  }
2181 
2182  return ret;
2183 }
2184 
2185 /*
2186  * scan_get_index_oidset () - Fetch the next group of set of object identifiers
2187  * from the index associated with the scan identifier.
2188  * return: NO_ERROR, or ER_code
2189  * s_id(in): Scan identifier
2190  *
2191  * Note: If you feel the need
2192  */
2193 static int
2194 scan_get_index_oidset (THREAD_ENTRY * thread_p, SCAN_ID * s_id, DB_BIGINT * key_limit_upper,
2195  DB_BIGINT * key_limit_lower)
2196 {
2197  INDX_SCAN_ID *iscan_id;
2198  FILTER_INFO key_filter;
2199  indx_info *indx_infop;
2200  BTREE_SCAN *bts;
2201  int key_cnt, i;
2202  KEY_VAL_RANGE *key_vals;
2204  RANGE range, saved_range;
2205  int ret = NO_ERROR;
2206  int curr_key_prefix_length = 0;
2207 
2208  /* pointer to INDX_SCAN_ID structure */
2209  iscan_id = &s_id->s.isid;
2210 
2211  /* pointer to indx_info in INDX_SCAN_ID structure */
2212  indx_infop = iscan_id->indx_info;
2213 
2214  /* pointer to index scan info. structure */
2215  bts = &iscan_id->bt_scan;
2216 
2217  /* number of keys */
2218  if (iscan_id->curr_keyno == -1) /* very first time */
2219  {
2220  key_cnt = indx_infop->key_info.key_cnt;
2221  }
2222  else
2223  {
2224  key_cnt = iscan_id->key_cnt;
2225  }
2226 
2227  /* key values */
2228  key_vals = iscan_id->key_vals;
2229 
2230  /* key ranges */
2231  key_ranges = indx_infop->key_info.key_ranges;
2232 
2233  if (key_cnt < 1 || !key_vals || !key_ranges)
2234  {
2236  return ER_FAILED;
2237  }
2238 
2239  if (iscan_id->bt_attrs_prefix_length && iscan_id->bt_num_attrs == 1)
2240  {
2241  curr_key_prefix_length = iscan_id->bt_attrs_prefix_length[0];
2242  }
2243 
2244  /* if it is the first time of this scan */
2245  if (iscan_id->curr_keyno == -1 && indx_infop->key_info.key_cnt == key_cnt)
2246  {
2247  /* make DB_VALUE key values from KEY_VALS key ranges */
2248  for (i = 0; i < key_cnt; i++)
2249  {
2250  /* initialize DB_VALUE first for error case */
2251  key_vals[i].range = NA_NA;
2252  db_make_null (&key_vals[i].key1);
2253  db_make_null (&key_vals[i].key2);
2254  key_vals[i].is_truncated = false;
2255  key_vals[i].num_index_term = 0;
2256 
2257  key_vals[i].range = key_ranges[i].range;
2258  if (key_vals[i].range == INF_INF)
2259  {
2260  continue;
2261  }
2262 
2263  ret =
2264  scan_regu_key_to_index_key (thread_p, &key_ranges[i], &key_vals[i], iscan_id, bts->btid_int.key_type,
2265  s_id->vd);
2266 
2267  if (ret != NO_ERROR)
2268  {
2269  goto exit_on_error;
2270  }
2271 
2272  assert_release (key_vals[i].num_index_term > 0);
2273  }
2274 
2275  /* eliminating duplicated keys and merging ranges are required even though the query optimizer does them because
2276  * the search keys or ranges could be unbound values at optimization step such as join attribute */
2277  if (indx_infop->range_type == R_KEYLIST)
2278  {
2279  /* eliminate duplicated keys in the search key list */
2280  key_cnt = iscan_id->key_cnt = check_key_vals (key_vals, key_cnt, eliminate_duplicated_keys);
2281  }
2282  else if (indx_infop->range_type == R_RANGELIST)
2283  {
2284  /* merge search key ranges */
2285  key_cnt = iscan_id->key_cnt = check_key_vals (key_vals, key_cnt, merge_key_ranges);
2286  }
2287 
2288  /* if is order by skip and first column is descending, the order will be reversed so reverse the key ranges to be
2289  * desc. */
2290  if ((indx_infop->range_type == R_KEYLIST || indx_infop->range_type == R_RANGELIST)
2291  && ((indx_infop->orderby_desc && indx_infop->orderby_skip)
2292  || (indx_infop->groupby_desc && indx_infop->groupby_skip)))
2293  {
2294  /* in both cases we should reverse the key lists if we have a reverse order by or group by which is skipped */
2295  check_key_vals (key_vals, key_cnt, reverse_key_list);
2296  }
2297 
2298  if (key_cnt < 0)
2299  {
2300  goto exit_on_error;
2301  }
2302 
2303  iscan_id->curr_keyno = 0;
2304  }
2305 
2306  /*
2307  * init vars to execute B+tree key range search
2308  */
2309 
2310  ret = NO_ERROR;
2311 
2312  /* set key filter information */
2313  scan_init_filter_info (&key_filter, &iscan_id->key_pred, &iscan_id->key_attrs, s_id->val_list, s_id->vd,
2314  &iscan_id->cls_oid, iscan_id->bt_num_attrs, iscan_id->bt_attr_ids, &iscan_id->num_vstr,
2315  iscan_id->vstr_ids);
2316  iscan_id->oids_count = 0;
2317  key_filter.func_idx_col_id = iscan_id->indx_info->func_idx_col_id;
2318 
2319  if (iscan_id->multi_range_opt.use && iscan_id->multi_range_opt.cnt > 0)
2320  {
2321  /* reset any previous results for multiple range optimization */
2322  int i;
2323 
2324  for (i = 0; i < iscan_id->multi_range_opt.cnt; i++)
2325  {
2326  if (iscan_id->multi_range_opt.top_n_items[i] != NULL)
2327  {
2329  db_private_free_and_init (thread_p, iscan_id->multi_range_opt.top_n_items[i]);
2330  }
2331  }
2332 
2333  iscan_id->multi_range_opt.cnt = 0;
2334  }
2335 
2336  /* if the end of this scan */
2337  if (iscan_id->curr_keyno > key_cnt)
2338  {
2339  return NO_ERROR;
2340  }
2341  else
2342  {
2343  /* Clear output val list to avoid memory leak. */
2345  for (p = iscan_id->indx_cov.regu_val_list; p; p = p->next)
2346  {
2347  pr_clear_value (p->value.vfetch_to);
2348  }
2349  }
2350 
2351  switch (indx_infop->range_type)
2352  {
2353  case R_KEY:
2354  /* key value search */
2355 
2356  /* check prerequisite condition */
2357  range = key_vals[0].range;
2358 
2359  if (range == NA_NA)
2360  {
2361  /* skip this key value */
2362  iscan_id->curr_keyno++;
2363  break;
2364  }
2365 
2366  if (key_cnt != 1)
2367  {
2369  goto exit_on_error;
2370  }
2371 
2372  ret =
2373  btree_prepare_bts (thread_p, bts, &indx_infop->btid, iscan_id, &key_vals[0], &key_filter,
2374  &iscan_id->cls_oid, key_limit_upper, key_limit_lower, true, NULL);
2375  if (ret != NO_ERROR)
2376  {
2377  assert (er_errid () != NO_ERROR);
2378  goto exit_on_error;
2379  }
2381  if (ret != NO_ERROR)
2382  {
2383  assert (er_errid () != NO_ERROR);
2384  goto exit_on_error;
2385  }
2386  iscan_id->oids_count = bts->n_oids_read_last_iteration;
2387  assert (iscan_id->oids_count >= 0);
2388 
2389  /* We only want to advance the key ptr if we've exhausted the current crop of oids on the current key. */
2390  if (BTREE_END_OF_SCAN (bts))
2391  {
2392  iscan_id->curr_keyno++;
2393  }
2394 
2395  if (iscan_id->multi_range_opt.use)
2396  {
2397  /* with multiple range optimization, we store the only the top N OIDS or index keys: the only valid exit
2398  * condition from 'btree_range_search' is when the index scan has reached the end for this key */
2399  assert (BTREE_END_OF_SCAN (bts));
2400  }
2401 
2402  break;
2403 
2404  case R_RANGE:
2405  /* range search */
2406 
2407  /* check prerequisite condition */
2408  saved_range = range = key_vals[0].range;
2409 
2410  if (range == NA_NA)
2411  {
2412  /* skip this key value */
2413  iscan_id->curr_keyno++;
2414  break;
2415  }
2416 
2417  if (key_cnt != 1 || range < GE_LE || range > INF_INF)
2418  {
2420  goto exit_on_error;
2421  }
2422 
2423  if (range >= GE_INF && range <= GT_INF)
2424  {
2425  pr_clear_value (&key_vals[0].key2);
2426  PRIM_SET_NULL (&key_vals[0].key2);
2427  }
2428 
2429  if (range >= INF_LE && range <= INF_LT)
2430  {
2431  pr_clear_value (&key_vals[0].key1);
2432  PRIM_SET_NULL (&key_vals[0].key1);
2433  }
2434 
2435  if (key_vals[0].is_truncated == true)
2436  { /* specially, key value search */
2437  range = GE_LE;
2438  }
2439 
2440  if (range == INF_INF)
2441  {
2442  /* if we reached the key count limit, break */
2443  if (iscan_id->curr_keyno >= key_cnt)
2444  {
2445  iscan_id->curr_keyno++;
2446  break;
2447  }
2448 
2449  pr_clear_value (&key_vals[0].key1);
2450  pr_clear_value (&key_vals[0].key2);
2451  PRIM_SET_NULL (&key_vals[0].key1);
2452  PRIM_SET_NULL (&key_vals[0].key2);
2453 
2454  assert_release (key_vals[0].num_index_term == 0);
2455  }
2456 
2457  key_vals[0].range = range;
2458  ret =
2459  btree_prepare_bts (thread_p, bts, &indx_infop->btid, iscan_id, &key_vals[0], &key_filter,
2460  &iscan_id->cls_oid, key_limit_upper, key_limit_lower, true, NULL);
2461  if (ret != NO_ERROR)
2462  {
2463  assert (er_errid () != NO_ERROR);
2464  goto exit_on_error;
2465  }
2467  key_vals[0].range = saved_range;
2468  if (ret != NO_ERROR)
2469  {
2470  assert (er_errid () != NO_ERROR);
2471  goto exit_on_error;
2472  }
2473  iscan_id->oids_count = bts->n_oids_read_last_iteration;
2474  assert (iscan_id->oids_count >= 0);
2475 
2476  /* We only want to advance the key ptr if we've exhausted the current crop of oids on the current key. */
2477  if (BTREE_END_OF_SCAN (bts))
2478  {
2479  iscan_id->curr_keyno++;
2480  }
2481 
2482  if (iscan_id->multi_range_opt.use)
2483  {
2484  /* with multiple range optimization, we store the only the top N OIDS or index keys: the only valid exit
2485  * condition from 'btree_range_search' is when the index scan has reached the end for this key */
2486  assert (BTREE_END_OF_SCAN (bts));
2487  }
2488  break;
2489 
2490  case R_KEYLIST:
2491  /* multiple key value search */
2492 
2493  /* for each key value */
2494  while (iscan_id->curr_keyno < key_cnt)
2495  {
2496  /* check prerequisite condition */
2497  range = key_vals[iscan_id->curr_keyno].range;
2498 
2499  if (range == NA_NA)
2500  {
2501  /* skip this key value and continue to the next */
2502  iscan_id->curr_keyno++;
2503  if (key_limit_upper && !key_limit_lower && indx_infop->key_info.key_limit_reset)
2504  {
2505  if (scan_init_index_key_limit (thread_p, iscan_id, &indx_infop->key_info, s_id->vd) != NO_ERROR)
2506  {
2507  goto exit_on_error;
2508  }
2509  *key_limit_upper = iscan_id->key_limit_upper;
2510  }
2511  continue;
2512  }
2513 
2514  ret =
2515  btree_prepare_bts (thread_p, bts, &indx_infop->btid, iscan_id, &key_vals[iscan_id->curr_keyno],
2516  &key_filter, &iscan_id->cls_oid, key_limit_upper, key_limit_lower, true, NULL);
2517  if (ret != NO_ERROR)
2518  {
2519  assert (er_errid () != NO_ERROR);
2520  goto exit_on_error;
2521  }
2523  if (ret != NO_ERROR)
2524  {
2525  assert (er_errid () != NO_ERROR);
2526  goto exit_on_error;
2527  }
2528  iscan_id->oids_count = bts->n_oids_read_last_iteration;
2529  assert (iscan_id->oids_count >= 0);
2530 
2531  /* We only want to advance the key ptr if we've exhausted the current crop of oids on the current key. */
2532  if (BTREE_END_OF_SCAN (bts))
2533  {
2534  iscan_id->curr_keyno++;
2535  /* reset upper key limit, if flag is set */
2536  if (key_limit_upper && !key_limit_lower && indx_infop->key_info.key_limit_reset)
2537  {
2538  if (scan_init_index_key_limit (thread_p, iscan_id, &indx_infop->key_info, s_id->vd) != NO_ERROR)
2539  {
2540  goto exit_on_error;
2541  }
2542  *key_limit_upper = iscan_id->key_limit_upper;
2543  }
2544  }
2545 
2546  if (iscan_id->multi_range_opt.use)
2547  {
2548  /* with multiple range optimization, we store the only the top N OIDS or index keys: the only valid exit
2549  * condition from 'btree_range_search' is when the index scan has reached the end for this key */
2550  assert (BTREE_END_OF_SCAN (bts));
2551  /* continue loop : exhaust all keys in one shot when in multiple range search optimization mode */
2552  continue;
2553  }
2554  if (iscan_id->oids_count > 0)
2555  {
2556  /* we've got some result */
2557  break;
2558  }
2559  }
2560 
2561  break;
2562 
2563  case R_RANGELIST:
2564  /* multiple range search */
2565 
2566  /* for each key value */
2567  while (iscan_id->curr_keyno < key_cnt)
2568  {
2569  /* check prerequisite condition */
2570  saved_range = range = key_vals[iscan_id->curr_keyno].range;
2571 
2572  if (range == NA_NA)
2573  {
2574  /* skip this key value and continue to the next */
2575  iscan_id->curr_keyno++;
2576  if (key_limit_upper && !key_limit_lower && indx_infop->key_info.key_limit_reset)
2577  {
2578  if (scan_init_index_key_limit (thread_p, iscan_id, &indx_infop->key_info, s_id->vd) != NO_ERROR)
2579  {
2580  goto exit_on_error;
2581  }
2582  *key_limit_upper = iscan_id->key_limit_upper;
2583  }
2584  continue;
2585  }
2586 
2587  if (range < GE_LE || range > INF_INF)
2588  {
2590  goto exit_on_error;
2591  }
2592 
2593  if (range >= GE_INF && range <= GT_INF)
2594  {
2595  pr_clear_value (&key_vals[iscan_id->curr_keyno].key2);
2596  PRIM_SET_NULL (&key_vals[iscan_id->curr_keyno].key2);
2597  }
2598 
2599  if (key_vals[iscan_id->curr_keyno].is_truncated == true)
2600  { /* specially, key value search */
2601  range = GE_LE;
2602  }
2603 
2604  if (range >= INF_LE && range <= INF_LT)
2605  {
2606  pr_clear_value (&key_vals[iscan_id->curr_keyno].key1);
2607  PRIM_SET_NULL (&key_vals[iscan_id->curr_keyno].key1);
2608  }
2609 
2610  if (range == INF_INF)
2611  {
2612  if (key_cnt != 1)
2613  {
2614  assert_release (0);
2616  goto exit_on_error;
2617  }
2618 
2619  /* if we reached the key count limit, break */
2620  if (iscan_id->curr_keyno >= key_cnt)
2621  {
2622  iscan_id->curr_keyno++;
2623  break;
2624  }
2625 
2626  pr_clear_value (&key_vals[0].key1);
2627  pr_clear_value (&key_vals[0].key2);
2628  PRIM_SET_NULL (&key_vals[0].key1);
2629  PRIM_SET_NULL (&key_vals[0].key2);
2630  }
2631 
2632  key_vals[iscan_id->curr_keyno].range = range;
2633  ret =
2634  btree_prepare_bts (thread_p, bts, &indx_infop->btid, iscan_id, &key_vals[iscan_id->curr_keyno],
2635  &key_filter, &iscan_id->cls_oid, key_limit_upper, key_limit_lower, true, NULL);
2636  if (ret != NO_ERROR)
2637  {
2638  assert (er_errid () != NO_ERROR);
2639  goto exit_on_error;
2640  }
2642  key_vals[iscan_id->curr_keyno].range = saved_range;
2643  if (ret != NO_ERROR)
2644  {
2645  assert (er_errid () != NO_ERROR);
2646  goto exit_on_error;
2647  }
2648  iscan_id->oids_count = bts->n_oids_read_last_iteration;
2649  assert (iscan_id->oids_count >= 0);
2650 
2651  /* We only want to advance the key ptr if we've exhausted the current crop of oids on the current key. */
2652  if (BTREE_END_OF_SCAN (bts))
2653  {
2654  iscan_id->curr_keyno++;
2655  /* reset upper key limit, if flag is set */
2656  if (key_limit_upper && !key_limit_lower && indx_infop->key_info.key_limit_reset)
2657  {
2658  if (scan_init_index_key_limit (thread_p, iscan_id, &indx_infop->key_info, s_id->vd) != NO_ERROR)
2659  {
2660  goto exit_on_error;
2661  }
2662  *key_limit_upper = iscan_id->key_limit_upper;
2663  }
2664  }
2665 
2666  if (iscan_id->multi_range_opt.use)
2667  {
2668  /* with multiple range optimization, we store the only the top N OIDS or index keys: the only valid exit
2669  * condition from 'btree_range_search' is when the index scan has reached the end for this key */
2670  assert (BTREE_END_OF_SCAN (bts));
2671  /* continue loop : exhaust all keys in one shot when in multiple range search optimization mode */
2672  continue;
2673  }
2674  if (iscan_id->oids_count > 0)
2675  {
2676  /* we've got some result */
2677  break;
2678  }
2679  }
2680 
2681  break;
2682 
2683  default:
2685  goto exit_on_error;
2686 
2687  }
2688 
2689  /* When covering index is used, 'index_scan_in_oid_order' parameter is ignored. */
2690  if (iscan_id->oid_list != NULL && iscan_id->oid_list->oidp != NULL && iscan_id->oids_count > 1
2691  && iscan_id->iscan_oid_order == true && iscan_id->need_count_only == false)
2692  {
2693  qsort (iscan_id->oid_list->oidp, iscan_id->oids_count, sizeof (OID), oid_compare);
2694  }
2695 
2696 end:
2697 
2698  if (key_limit_upper != NULL && *key_limit_upper == 0)
2699  {
2700  /* End scan here! */
2701  iscan_id->curr_keyno = key_cnt;
2702  }
2703 
2704  /* if the end of this scan */
2705  if (iscan_id->curr_keyno == key_cnt)
2706  {
2707  for (i = 0; i < key_cnt; i++)
2708  {
2709  pr_clear_value (&key_vals[i].key1);
2710  pr_clear_value (&key_vals[i].key2);
2711  }
2712  iscan_id->curr_keyno++; /* to prevent duplicate frees */
2713  }
2714 
2715  if (thread_is_on_trace (thread_p))
2716  {
2717  s_id->scan_stats.read_keys += iscan_id->bt_scan.read_keys;
2718  iscan_id->bt_scan.read_keys = 0;
2719  s_id->scan_stats.qualified_keys += iscan_id->bt_scan.qualified_keys;
2720  iscan_id->bt_scan.qualified_keys = 0;
2721  }
2722 
2723  return ret;
2724 
2725 exit_on_error:
2726  iscan_id->curr_keyno = key_cnt; /* set as end of this scan */
2727 
2728  ret = (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
2729  goto end;
2730 }
2731 
2732 /*
2733  *
2734  * SCAN MANAGEMENT ROUTINES
2735  *
2736  */
2737 
2738 /*
2739  * scan_init_scan_id () -
2740  * return:
2741  * scan_id(out): Scan identifier
2742  * mvcc_select_lock_needed(in):
2743  * scan_op_type(in): scan operation type
2744  * fixed(in):
2745  * grouped(in):
2746  * single_fetch(in):
2747  * join_dbval(in):
2748  * val_list(in):
2749  * vd(in):
2750  *
2751  * Note: If you feel the need
2752  */
2753 static void
2754 scan_init_scan_id (SCAN_ID * scan_id, bool mvcc_select_lock_needed, SCAN_OPERATION_TYPE scan_op_type, int fixed,
2755  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list,
2756  VAL_DESCR * vd)
2757 {
2758  scan_id->status = S_OPENED;
2759  scan_id->position = S_BEFORE;
2760  scan_id->direction = S_FORWARD;
2761 
2762  scan_id->mvcc_select_lock_needed = mvcc_select_lock_needed;
2763  scan_id->scan_op_type = scan_op_type;
2764  scan_id->fixed = fixed;
2765 
2766  scan_id->grouped = grouped; /* is it grouped or single scan? */
2767  scan_id->qualified_block = false;
2768  scan_id->single_fetch = single_fetch;
2769  scan_id->single_fetched = false;
2770  scan_id->null_fetched = false;
2771  scan_id->qualification = QPROC_QUALIFIED;
2772 
2773  /* join term */
2774  scan_id->join_dbval = join_dbval;
2775 
2776  /* value list and descriptor */
2777  scan_id->val_list = val_list; /* points to the XASL tree */
2778  scan_id->vd = vd; /* set value descriptor pointer */
2779  scan_id->scan_immediately_stop = false;
2780 }
2781 
2782 /*
2783  * scan_open_heap_scan () -
2784  * return: NO_ERROR
2785  * scan_id(out): Scan identifier
2786  * mvcc_select_lock_needed(in):
2787  * scan_op_type(in): scan operation type
2788  * fixed(in):
2789  * grouped(in):
2790  * single_fetch(in):
2791  * join_dbval(in):
2792  * val_list(in):
2793  * vd(in):
2794  * cls_oid(in):
2795  * hfid(in):
2796  * regu_list_pred(in):
2797  * pr(in):
2798  * regu_list_rest(in):
2799  * num_attrs_pred(in):
2800  * attrids_pred(in):
2801  * cache_pred(in):
2802  * num_attrs_rest(in):
2803  * attrids_rest(in):
2804  * cache_rest(in):
2805  * cache_recordinfo(in):
2806  * regu_list_recordinfo(in):
2807  *
2808  * Note: If you feel the need
2809  */
2810 int
2812  /* fields of SCAN_ID */
2813  bool mvcc_select_lock_needed, SCAN_OPERATION_TYPE scan_op_type, int fixed, int grouped,
2814  QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list, VAL_DESCR * vd,
2815  /* fields of HEAP_SCAN_ID */
2816  OID * cls_oid, HFID * hfid, regu_variable_list_node * regu_list_pred, PRED_EXPR * pr,
2817  regu_variable_list_node * regu_list_rest, int num_attrs_pred, ATTR_ID * attrids_pred,
2818  HEAP_CACHE_ATTRINFO * cache_pred, int num_attrs_rest, ATTR_ID * attrids_rest,
2819  HEAP_CACHE_ATTRINFO * cache_rest, SCAN_TYPE scan_type, DB_VALUE ** cache_recordinfo,
2820  regu_variable_list_node * regu_list_recordinfo)
2821 {
2822  HEAP_SCAN_ID *hsidp;
2823  DB_TYPE single_node_type = DB_TYPE_NULL;
2824 
2825  /* scan type is HEAP SCAN or HEAP SCAN RECORD INFO */
2826  assert (scan_type == S_HEAP_SCAN || scan_type == S_HEAP_SCAN_RECORD_INFO);
2827  scan_id->type = scan_type;
2828 
2829  /* initialize SCAN_ID structure */
2830  scan_init_scan_id (scan_id, mvcc_select_lock_needed, scan_op_type, fixed, grouped, single_fetch, join_dbval, val_list,
2831  vd);
2832 
2833  /* initialize HEAP_SCAN_ID structure */
2834  hsidp = &scan_id->s.hsid;
2835 
2836  /* class object OID */
2837  COPY_OID (&hsidp->cls_oid, cls_oid);
2838 
2839  /* heap file identifier */
2840  hsidp->hfid = *hfid; /* bitwise copy */
2841 
2842  /* OID within the heap */
2843  UT_CAST_TO_NULL_HEAP_OID (&hsidp->hfid, &hsidp->curr_oid);
2844 
2845  /* scan predicates */
2846  scan_init_scan_pred (&hsidp->scan_pred, regu_list_pred, pr,
2847  ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
2848  /* attribute information from predicates */
2849  scan_init_scan_attrs (&hsidp->pred_attrs, num_attrs_pred, attrids_pred, cache_pred);
2850 
2851  /* regulator variable list for other than predicates */
2852  hsidp->rest_regu_list = regu_list_rest;
2853 
2854  /* attribute information from other than predicates */
2855  scan_init_scan_attrs (&hsidp->rest_attrs, num_attrs_rest, attrids_rest, cache_rest);
2856 
2857  /* flags */
2858  /* do not reset hsidp->caches_inited here */
2859  hsidp->scancache_inited = false;
2860  hsidp->scanrange_inited = false;
2861 
2862  hsidp->cache_recordinfo = cache_recordinfo;
2863  hsidp->recordinfo_regu_list = regu_list_recordinfo;
2864 
2865  return NO_ERROR;
2866 }
2867 
2868 /*
2869  * scan_open_heap_page_scan () - Opens a page by page heap scan.
2870  *
2871  * return : Error code.
2872  * thread_p (in) :
2873  * scan_id (in) :
2874  * val_list (in) :
2875  * vd (in) :
2876  * cls_oid (in) :
2877  * hfid (in) :
2878  * pr (in) :
2879  * scan_type (in) :
2880  * cache_page_info (in) :
2881  * regu_list_page_info (in) :
2882  */
2883 int
2885  /* fields of SCAN_ID */
2886  val_list_node * val_list, VAL_DESCR * vd,
2887  /* fields of HEAP_SCAN_ID */
2888  OID * cls_oid, HFID * hfid, PRED_EXPR * pr, SCAN_TYPE scan_type, DB_VALUE ** cache_page_info,
2889  regu_variable_list_node * regu_list_page_info)
2890 {
2891  HEAP_PAGE_SCAN_ID *hpsidp = NULL;
2892  DB_TYPE single_node_type = DB_TYPE_NULL;
2893 
2894  scan_id->type = scan_type;
2895 
2896  scan_init_scan_id (scan_id, true, S_SELECT, true, false, QPROC_NO_SINGLE_INNER, NULL, val_list, vd);
2897 
2898  hpsidp = &scan_id->s.hpsid;
2899 
2900  COPY_OID (&hpsidp->cls_oid, cls_oid);
2901  hpsidp->hfid = *hfid;
2902  hpsidp->cache_page_info = cache_page_info;
2903  hpsidp->page_info_regu_list = regu_list_page_info;
2904  scan_init_scan_pred (&hpsidp->scan_pred, NULL, pr, (pr == NULL) ? NULL : eval_fnc (thread_p, pr, &single_node_type));
2905  VPID_SET_NULL (&hpsidp->curr_vpid);
2906  return NO_ERROR;
2907 }
2908 
2909 /*
2910  * scan_open_class_attr_scan () -
2911  * return: NO_ERROR
2912  * scan_id(out): Scan identifier
2913  * grouped(in):
2914  * single_fetch(in):
2915  * join_dbval(in):
2916  * val_list(in):
2917  * vd(in):
2918  * cls_oid(in):
2919  * hfid(in):
2920  * regu_list_pred(in):
2921  * pr(in):
2922  * regu_list_rest(in):
2923  * num_attrs_pred(in):
2924  * attrids_pred(in):
2925  * cache_pred(in):
2926  * num_attrs_rest(in):
2927  * attrids_rest(in):
2928  * cache_rest(in):
2929  *
2930  * Note: If you feel the need
2931  */
2932 int
2934  /* fields of SCAN_ID */
2935  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval,
2936  val_list_node * val_list, VAL_DESCR * vd,
2937  /* fields of HEAP_SCAN_ID */
2938  OID * cls_oid, HFID * hfid, regu_variable_list_node * regu_list_pred, PRED_EXPR * pr,
2939  regu_variable_list_node * regu_list_rest, int num_attrs_pred, ATTR_ID * attrids_pred,
2940  HEAP_CACHE_ATTRINFO * cache_pred, int num_attrs_rest, ATTR_ID * attrids_rest,
2941  HEAP_CACHE_ATTRINFO * cache_rest)
2942 {
2943  HEAP_SCAN_ID *hsidp;
2944  DB_TYPE single_node_type = DB_TYPE_NULL;
2945 
2946  /* scan type is CLASS ATTR SCAN */
2947  scan_id->type = S_CLASS_ATTR_SCAN;
2948 
2949  /* initialize SCAN_ID structure */
2950  /* mvcc_select_lock_needed = false, fixed = true */
2951  scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
2952 
2953  /* initialize HEAP_SCAN_ID structure */
2954  hsidp = &scan_id->s.hsid;
2955 
2956  /* class object OID */
2957  COPY_OID (&hsidp->cls_oid, cls_oid);
2958  /* heap file identifier */
2959  hsidp->hfid = *hfid; /* bitwise copy */
2960  /* OID within the heap */
2961  UT_CAST_TO_NULL_HEAP_OID (&hsidp->hfid, &hsidp->curr_oid);
2962 
2963  /* scan predicates */
2964  scan_init_scan_pred (&hsidp->scan_pred, regu_list_pred, pr,
2965  ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
2966  /* attribute information from predicates */
2967  scan_init_scan_attrs (&hsidp->pred_attrs, num_attrs_pred, attrids_pred, cache_pred);
2968  /* regulator vairable list for other than predicates */
2969  hsidp->rest_regu_list = regu_list_rest;
2970  /* attribute information from other than predicates */
2971  scan_init_scan_attrs (&hsidp->rest_attrs, num_attrs_rest, attrids_rest, cache_rest);
2972 
2973  /* flags */
2974  /* do not reset hsidp->caches_inited here */
2975  hsidp->scancache_inited = false;
2976  hsidp->scanrange_inited = false;
2977 
2978  return NO_ERROR;
2979 }
2980 
2981 /*
2982  * scan_open_index_scan () -
2983  * return: NO_ERROR, or ER_code
2984  * scan_id(out): Scan identifier
2985  * mvcc_select_lock_needed(in):
2986  * fixed(in):
2987  * grouped(in):
2988  * single_fetch(in):
2989  * join_dbval(in):
2990  * val_list(in):
2991  * vd(in):
2992  * indx_info(in):
2993  * cls_oid(in):
2994  * hfid(in):
2995  * regu_list_key(in):
2996  * pr_key(in):
2997  * regu_list_pred(in):
2998  * pr(in):
2999  * regu_list_rest(in):
3000  * pr_range(in):
3001  * regu_list_range(in):
3002  * num_attrs_key(in):
3003  * attrids_key(in):
3004  * num_attrs_pred(in):
3005  * attrids_pred(in):
3006  * cache_pred(in):
3007  * num_attrs_rest(in):
3008  * attrids_rest(in):
3009  * cache_rest(in):
3010  * num_attrs_range(in):
3011  * attrids_range(in):
3012  * cache_range(in):
3013  * iscan_oid_order(in):
3014  * query_id(in):
3015  *
3016  * Note: If you feel the need
3017  */
3018 int
3020  /* fields of SCAN_ID */
3021  bool mvcc_select_lock_needed, SCAN_OPERATION_TYPE scan_op_type, int fixed, int grouped,
3022  QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list, VAL_DESCR * vd,
3023  /* fields of INDX_SCAN_ID */
3024  indx_info * indx_info, OID * cls_oid, HFID * hfid, regu_variable_list_node * regu_list_key,
3025  PRED_EXPR * pr_key, regu_variable_list_node * regu_list_pred, PRED_EXPR * pr,
3026  regu_variable_list_node * regu_list_rest, PRED_EXPR * pr_range,
3027  regu_variable_list_node * regu_list_range, valptr_list_node * output_val_list,
3028  regu_variable_list_node * regu_val_list, int num_attrs_key, ATTR_ID * attrids_key,
3029  HEAP_CACHE_ATTRINFO * cache_key, int num_attrs_pred, ATTR_ID * attrids_pred,
3030  HEAP_CACHE_ATTRINFO * cache_pred, int num_attrs_rest, ATTR_ID * attrids_rest,
3031  HEAP_CACHE_ATTRINFO * cache_rest, int num_attrs_range, ATTR_ID * attrids_range,
3032  HEAP_CACHE_ATTRINFO * cache_range, bool iscan_oid_order, QUERY_ID query_id)
3033 {
3034  int ret = NO_ERROR;
3035  INDX_SCAN_ID *isidp;
3036  DB_TYPE single_node_type = DB_TYPE_NULL;
3037  BTID *btid;
3038  VPID Root_vpid;
3039  PAGE_PTR Root;
3040  BTREE_ROOT_HEADER *root_header = NULL;
3041  BTREE_SCAN *BTS;
3042  int coverage_enabled;
3043  int func_index_col_id;
3044 
3045  /* scan type is INDEX SCAN */
3046  scan_id->type = S_INDX_SCAN;
3047 
3048  /* initialize SCAN_ID structure */
3049  scan_init_scan_id (scan_id, mvcc_select_lock_needed, scan_op_type, fixed, grouped, single_fetch, join_dbval, val_list,
3050  vd);
3051 
3052  /* read Root page header info */
3053  btid = &indx_info->btid;
3054 
3055  Root_vpid.pageid = btid->root_pageid;
3056  Root_vpid.volid = btid->vfid.volid;
3057 
3058  Root = pgbuf_fix (thread_p, &Root_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
3059  if (Root == NULL)
3060  {
3061  return ER_FAILED;
3062  }
3063 
3064  (void) pgbuf_check_page_ptype (thread_p, Root, PAGE_BTREE);
3065 
3066  root_header = btree_get_root_header (thread_p, Root);
3067  if (root_header == NULL)
3068  {
3069  pgbuf_unfix_and_init (thread_p, Root);
3070  return ER_FAILED;
3071  }
3072 
3073  /* initialize INDEX_SCAN_ID structure */
3074  isidp = &scan_id->s.isid;
3075 
3076  /* index information */
3077  isidp->indx_info = indx_info;
3078 
3079  /* init allocated fields */
3080  isidp->bt_num_attrs = 0;
3081  isidp->bt_attr_ids = NULL;
3082  isidp->vstr_ids = NULL;
3083  isidp->oid_list = NULL;
3084  isidp->curr_oidp = NULL;
3085  isidp->copy_buf = NULL;
3086  isidp->copy_buf_len = 0;
3087  isidp->key_vals = NULL;
3088 
3089  isidp->indx_cov.type_list = NULL;
3090  isidp->indx_cov.list_id = NULL;
3091  isidp->indx_cov.tplrec = NULL;
3092  isidp->indx_cov.lsid = NULL;
3093  isidp->fetched_values = NULL;
3094 
3095  /* index scan info */
3096  BTS = &isidp->bt_scan;
3097  BTREE_INIT_SCAN (BTS);
3098 
3099  /* construct BTID_INT structure */
3100  BTS->btid_int.sys_btid = btid;
3101 
3102  if (btree_glean_root_header_info (thread_p, root_header, &BTS->btid_int) != NO_ERROR)
3103  {
3104  pgbuf_unfix_and_init (thread_p, Root);
3105  goto exit_on_error;
3106  }
3107  BTS->is_btid_int_valid = true;
3108 
3109  pgbuf_unfix_and_init (thread_p, Root);
3110 
3111  /* initialize key limits */
3112  if (scan_init_index_key_limit (thread_p, isidp, &indx_info->key_info, vd) != NO_ERROR)
3113  {
3114  goto exit_on_error;
3115  }
3116 
3117  /* attribute information of the index key */
3118  if (heap_get_indexinfo_of_btid (thread_p, cls_oid, &indx_info->btid, &isidp->bt_type, &isidp->bt_num_attrs,
3119  &isidp->bt_attr_ids, &isidp->bt_attrs_prefix_length, NULL,
3120  &func_index_col_id) != NO_ERROR)
3121  {
3122  goto exit_on_error;
3123  }
3124 
3125  /* attribute information of the variable string attrs in index key */
3126  isidp->num_vstr = 0;
3127  isidp->vstr_ids = NULL;
3128 
3130  {
3131  isidp->num_vstr = isidp->bt_num_attrs; /* init to maximum */
3132  isidp->vstr_ids = (ATTR_ID *) db_private_alloc (thread_p, isidp->num_vstr * sizeof (ATTR_ID));
3133  if (isidp->vstr_ids == NULL)
3134  {
3135  goto exit_on_error;
3136  }
3137  }
3138 
3139  /* indicator whether covering index is used or not */
3140  coverage_enabled = (indx_info->coverage != 0) && (scan_op_type == S_SELECT) && !mvcc_select_lock_needed;
3141  scan_id->scan_stats.loose_index_scan = indx_info->ils_prefix_len > 0;
3142 
3143  /* is a single range? */
3144  isidp->one_range = false;
3145 
3146  /* initial values */
3147  isidp->curr_keyno = -1;
3148  isidp->curr_oidno = -1;
3149 
3150  /* OID buffer */
3151  if (coverage_enabled)
3152  {
3153  /* Covering index do not use an oid buffer. */
3154  scan_id->scan_stats.covered_index = true;
3155  }
3156  else
3157  {
3158  ret = scan_alloc_iscan_oid_buf_list (&isidp->oid_list);
3159  if (ret != NO_ERROR)
3160  {
3161  goto exit_on_error;
3162  }
3163  /* Safe guard. */
3164  assert (isidp->oid_list->oidp != NULL);
3165  assert (isidp->oid_list->capacity > 0);
3166  assert (isidp->oid_list->next_list == NULL);
3167 
3168  /* Initialize OID list. */
3170  isidp->oid_list->oid_cnt = 0;
3171  /* Initialize current OID pointer to start of buffer. */
3172  isidp->curr_oidp = isidp->oid_list->oidp;
3173 
3174  /* Safe guard */
3175  /* OID count limit should not exceed buffer capacity. */
3176  assert (isidp->oid_list->max_oid_cnt <= isidp->oid_list->capacity);
3177  }
3178 
3179  /* class object OID */
3180  COPY_OID (&isidp->cls_oid, cls_oid);
3181 
3182  /* heap file identifier */
3183  isidp->hfid = *hfid; /* bitwise copy */
3184 
3185  /* key filter */
3186  scan_init_scan_pred (&isidp->key_pred, regu_list_key, pr_key,
3187  ((pr_key) ? eval_fnc (thread_p, pr_key, &single_node_type) : NULL));
3188 
3189  /* attribute information from key filter */
3190  scan_init_scan_attrs (&isidp->key_attrs, num_attrs_key, attrids_key, cache_key);
3191 
3192  /* scan predicates */
3193  scan_init_scan_pred (&isidp->scan_pred, regu_list_pred, pr,
3194  ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3195 
3196  /* attribute information from predicates */
3197  scan_init_scan_attrs (&isidp->pred_attrs, num_attrs_pred, attrids_pred, cache_pred);
3198 
3199  /* scan range filter */
3200  scan_init_scan_pred (&isidp->range_pred, regu_list_range, pr_range,
3201  ((pr_range) ? eval_fnc (thread_p, pr_range, &single_node_type) : NULL));
3202 
3203  /* attribute information from range filter */
3204  scan_init_scan_attrs (&isidp->range_attrs, num_attrs_range, attrids_range, cache_range);
3205 
3206  /* regulator variable list for other than predicates */
3207  isidp->rest_regu_list = regu_list_rest;
3208 
3209  /* attribute information from other than predicates */
3210  scan_init_scan_attrs (&isidp->rest_attrs, num_attrs_rest, attrids_rest, cache_rest);
3211 
3212  /* flags */
3213  /* do not reset hsidp->caches_inited here */
3214  isidp->scancache_inited = false;
3215 
3216  /* convert key values in the form of REGU_VARIABLE to the form of DB_VALUE */
3217  isidp->key_cnt = indx_info->key_info.key_cnt;
3218  if (isidp->key_cnt > 0)
3219  {
3220  bool need_copy_buf;
3221 
3222  isidp->key_vals = (KEY_VAL_RANGE *) db_private_alloc (thread_p, isidp->key_cnt * sizeof (KEY_VAL_RANGE));
3223  if (isidp->key_vals == NULL)
3224  {
3225  goto exit_on_error;
3226  }
3227 
3228  need_copy_buf = false; /* init */
3229 
3230  if (BTS->btid_int.key_type == NULL || BTS->btid_int.key_type->type == NULL)
3231  {
3232  goto exit_on_error;
3233  }
3234 
3235  /* check for the need of index key copy_buf */
3237  {
3238  /* found multi-column key-val */
3239  need_copy_buf = true;
3240 
3241  /* make fetched values for scan_regu_key_to_index_key(). */
3242  isidp->fetched_values = (DB_VALUE *) db_private_alloc (thread_p, sizeof (DB_VALUE) * isidp->bt_num_attrs);
3243  if (isidp->fetched_values == NULL)
3244  {
3245  goto exit_on_error;
3246  }
3247  for (int j = 0; j < isidp->bt_num_attrs; j++)
3248  {
3249  db_make_null (&isidp->fetched_values[j]);
3250  }
3251  }
3252  else
3253  { /* single-column index */
3254  if (indx_info->key_info.key_ranges[0].range != EQ_NA)
3255  {
3256  /* found single-column key-range, not key-val */
3258  {
3259  /* this type needs index key copy_buf */
3260  need_copy_buf = true;
3261  }
3262  }
3263  }
3264 
3265  if (need_copy_buf)
3266  {
3267  /* alloc index key copy_buf */
3268  isidp->copy_buf = (char *) db_private_alloc (thread_p, DBVAL_BUFSIZE);
3269  if (isidp->copy_buf == NULL)
3270  {
3271  goto exit_on_error;
3272  }
3273  isidp->copy_buf_len = DBVAL_BUFSIZE;
3274  }
3275  }
3276  else
3277  {
3278  isidp->key_cnt = 0;
3279  isidp->key_vals = NULL;
3280  }
3281 
3282  isidp->iscan_oid_order = iscan_oid_order;
3283 
3284  if (scan_init_indx_coverage (thread_p, coverage_enabled, output_val_list, regu_val_list, vd, query_id,
3285  root_header->node.max_key_len, func_index_col_id, &(isidp->indx_cov)) != NO_ERROR)
3286  {
3287  goto exit_on_error;
3288  }
3289 
3290  if (scan_init_iss (isidp) != NO_ERROR)
3291  {
3292  goto exit_on_error;
3293  }
3294 
3295  /* initialize multiple range search optimization structure */
3296  {
3297  bool use_multi_range_opt = (isidp->bt_num_attrs > 1 && isidp->indx_info->key_info.key_limit_reset == true
3298  && isidp->key_limit_upper > 0 && isidp->key_limit_upper < DB_INT32_MAX
3299  && isidp->key_limit_lower == -1) ? true : false;
3300 
3301  if (scan_init_multi_range_optimization (thread_p, &(isidp->multi_range_opt), use_multi_range_opt,
3302  (int) isidp->key_limit_upper) != NO_ERROR)
3303  {
3304  goto exit_on_error;
3305  }
3306 
3307  scan_id->scan_stats.multi_range_opt = isidp->multi_range_opt.use;
3308  }
3309 
3310  return ret;
3311 
3312 exit_on_error:
3313 
3314  if (isidp->key_vals)
3315  {
3316  db_private_free_and_init (thread_p, isidp->key_vals);
3317  }
3318  if (isidp->fetched_values)
3319  {
3320  db_private_free_and_init (thread_p, isidp->fetched_values);
3321  }
3322  if (isidp->bt_attr_ids)
3323  {
3324  db_private_free_and_init (thread_p, isidp->bt_attr_ids);
3325  }
3326  if (isidp->vstr_ids)
3327  {
3328  db_private_free_and_init (thread_p, isidp->vstr_ids);
3329  }
3330  if (isidp->oid_list != NULL)
3331  {
3333  isidp->oid_list = NULL;
3334  }
3335  if (isidp->copy_buf)
3336  {
3337  db_private_free_and_init (thread_p, isidp->copy_buf);
3338  }
3339  if (isidp->indx_cov.type_list != NULL)
3340  {
3341  if (isidp->indx_cov.type_list->domp != NULL)
3342  {
3343  db_private_free_and_init (thread_p, isidp->indx_cov.type_list->domp);
3344  }
3345  db_private_free_and_init (thread_p, isidp->indx_cov.type_list);
3346  }
3347  if (isidp->indx_cov.list_id != NULL)
3348  {
3350  }
3351  if (isidp->indx_cov.tplrec != NULL)
3352  {
3353  if (isidp->indx_cov.tplrec->tpl != NULL)
3354  {
3355  db_private_free_and_init (thread_p, isidp->indx_cov.tplrec->tpl);
3356  }
3357  db_private_free_and_init (thread_p, isidp->indx_cov.tplrec);
3358  }
3359  if (isidp->indx_cov.lsid != NULL)
3360  {
3361  db_private_free_and_init (thread_p, isidp->indx_cov.lsid);
3362  }
3363 
3364  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
3365 }
3366 
3367 /*
3368  * scan_open_index_key_info_scan () - Opens a scan for index key info
3369  *
3370  * return : Error code.
3371  * thread_p (in) : Thread entry.
3372  * scan_id (out) : Pointer where scan data is saved.
3373  * val_list (in) : XASL values list.
3374  * vd (in) : XASL values descriptors.
3375  * indx_info (in) : Index info.
3376  * cls_oid (in) : Class object identifier.
3377  * hfid (in) : Heap file identifier.
3378  * pr (in) : Scan predicate.
3379  * output_val_list (in) : Output value pointers list.
3380  * iscan_oid_order (in) : Index scan OID order.
3381  * query_id (in) : Query identifier.
3382  * key_info_values (in) : Array of value pointers to store key info.
3383  * key_info_regu_list (in) : Regulator variable list for key info.
3384  */
3385 int
3387  /* fields of SCAN_ID */
3388  val_list_node * val_list, VAL_DESCR * vd,
3389  /* fields of INDX_SCAN_ID */
3390  indx_info * indx_info, OID * cls_oid, HFID * hfid, PRED_EXPR * pr,
3391  valptr_list_node * output_val_list, bool iscan_oid_order, QUERY_ID query_id,
3392  DB_VALUE ** key_info_values, regu_variable_list_node * key_info_regu_list)
3393 {
3394  int ret = NO_ERROR;
3395  INDX_SCAN_ID *isidp = NULL;
3396  BTID *btid = NULL;
3397  VPID root_vpid;
3398  PAGE_PTR root_page = NULL;
3399  BTREE_ROOT_HEADER *root_header = NULL;
3400  BTREE_SCAN *bts = NULL;
3401  int func_index_col_id;
3402  DB_TYPE single_node_type = DB_TYPE_NULL;
3403 
3404  scan_id->type = S_INDX_KEY_INFO_SCAN;
3405 
3406  /* initialize SCAN_ID structure */
3407  scan_init_scan_id (scan_id, 1, S_SELECT, false, false, QPROC_NO_SINGLE_INNER, NULL, val_list, vd);
3408 
3409  /* read root_page page header info */
3410  btid = &indx_info->btid;
3411 
3412  root_vpid.pageid = btid->root_pageid;
3413  root_vpid.volid = btid->vfid.volid;
3414 
3415  root_page = pgbuf_fix (thread_p, &root_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
3416  if (root_page == NULL)
3417  {
3418  return ER_FAILED;
3419  }
3420  root_header = btree_get_root_header (thread_p, root_page);
3421  pgbuf_unfix_and_init (thread_p, root_page);
3422 
3423  /* initialize INDEX_SCAN_ID structure */
3424  isidp = &scan_id->s.isid;
3425 
3426  /* index information */
3427  isidp->indx_info = indx_info;
3428 
3429  /* init allocated fields */
3430  isidp->bt_num_attrs = 0;
3431  isidp->bt_attr_ids = NULL;
3432  isidp->vstr_ids = NULL;
3433  isidp->oid_list = NULL;
3434  isidp->curr_oidp = NULL;
3435  isidp->copy_buf = NULL;
3436  isidp->copy_buf_len = 0;
3437  isidp->key_vals = NULL;
3438 
3439  isidp->indx_cov.type_list = NULL;
3440  isidp->indx_cov.list_id = NULL;
3441  isidp->indx_cov.tplrec = NULL;
3442  isidp->indx_cov.lsid = NULL;
3443 
3444  /* initialize key limits */
3445  if (scan_init_index_key_limit (thread_p, isidp, &indx_info->key_info, vd) != NO_ERROR)
3446  {
3447  goto exit_on_error;
3448  }
3449 
3450  /* index scan info */
3451  bts = &isidp->bt_scan;
3452  BTREE_INIT_SCAN (bts);
3453 
3454  /* construct BTID_INT structure */
3455  bts->btid_int.sys_btid = btid;
3456  if (btree_glean_root_header_info (thread_p, root_header, &bts->btid_int) != NO_ERROR)
3457  {
3458  goto exit_on_error;
3459  }
3460  bts->is_btid_int_valid = true;
3461 
3462  /* attribute information of the index key */
3463  if (heap_get_indexinfo_of_btid (thread_p, cls_oid, &indx_info->btid, &isidp->bt_type, &isidp->bt_num_attrs,
3464  NULL, NULL, NULL, &func_index_col_id) != NO_ERROR)
3465  {
3466  goto exit_on_error;
3467  }
3468 
3469  /* attribute information of the variable string attrs in index key */
3470  isidp->num_vstr = 0;
3471  isidp->vstr_ids = NULL;
3472 
3474  {
3475  isidp->num_vstr = isidp->bt_num_attrs; /* init to maximum */
3476  isidp->vstr_ids = (ATTR_ID *) db_private_alloc (thread_p, isidp->num_vstr * sizeof (ATTR_ID));
3477  if (isidp->vstr_ids == NULL)
3478  {
3479  goto exit_on_error;
3480  }
3481  }
3482 
3483  /* is a single range? */
3484  isidp->one_range = true;
3485 
3486  /* initial values */
3487  isidp->curr_keyno = -1;
3488  isidp->curr_oidno = -1;
3489 
3490  /* class object OID */
3491  COPY_OID (&isidp->cls_oid, cls_oid);
3492 
3493  /* heap file identifier */
3494  isidp->hfid = *hfid; /* bitwise copy */
3495 
3496  /* flags */
3497  /* do not reset hsidp->caches_inited here */
3498  isidp->scancache_inited = false;
3499 
3500  /* convert key values in the form of REGU_VARIABLE to the form of DB_VALUE */
3501  isidp->key_cnt = 0;
3502  isidp->key_vals = NULL;
3503 
3504  /* scan predicate */
3505  scan_init_scan_pred (&isidp->scan_pred, NULL, pr, ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3506 
3507  isidp->iscan_oid_order = iscan_oid_order;
3508 
3509  if (scan_init_indx_coverage (thread_p, false, NULL, NULL, vd, query_id, root_header->node.max_key_len,
3510  func_index_col_id, &(isidp->indx_cov)) != NO_ERROR)
3511  {
3512  goto exit_on_error;
3513  }
3514 
3515  if (scan_init_iss (isidp) != NO_ERROR)
3516  {
3517  goto exit_on_error;
3518  }
3519 
3520  /* initialize multiple range search optimization structure */
3521  isidp->multi_range_opt.use = false;
3522 
3523  isidp->key_info_values = key_info_values;
3524  isidp->key_info_regu_list = key_info_regu_list;
3525 
3526  return ret;
3527 
3528 exit_on_error:
3529 
3530  if (isidp->key_vals)
3531  {
3532  db_private_free_and_init (thread_p, isidp->key_vals);
3533  }
3534  if (isidp->bt_attr_ids)
3535  {
3536  db_private_free_and_init (thread_p, isidp->bt_attr_ids);
3537  }
3538  if (isidp->vstr_ids)
3539  {
3540  db_private_free_and_init (thread_p, isidp->vstr_ids);
3541  }
3542  assert (isidp->oid_list == NULL);
3543  if (isidp->copy_buf)
3544  {
3545  db_private_free_and_init (thread_p, isidp->copy_buf);
3546  }
3547  if (isidp->indx_cov.type_list != NULL)
3548  {
3549  if (isidp->indx_cov.type_list->domp != NULL)
3550  {
3551  db_private_free_and_init (thread_p, isidp->indx_cov.type_list->domp);
3552  }
3553  db_private_free_and_init (thread_p, isidp->indx_cov.type_list);
3554  }
3555  if (isidp->indx_cov.list_id != NULL)
3556  {
3558  }
3559  if (isidp->indx_cov.tplrec != NULL)
3560  {
3561  if (isidp->indx_cov.tplrec->tpl != NULL)
3562  {
3563  db_private_free_and_init (thread_p, isidp->indx_cov.tplrec->tpl);
3564  }
3565  db_private_free_and_init (thread_p, isidp->indx_cov.tplrec);
3566  }
3567  if (isidp->indx_cov.lsid != NULL)
3568  {
3569  db_private_free_and_init (thread_p, isidp->indx_cov.lsid);
3570  }
3571 
3572  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
3573 }
3574 
3575 /*
3576  * scan_open_index_node_info_scan () - Opens a scan on b-tree nodes.
3577  *
3578  * return : Error code.
3579  * thread_p (in) : Thread entry.
3580  * scan_id (out) : Scan data.
3581  * val_list (in) : XASL value list.
3582  * vd (in) : XASL value descriptors.
3583  * indx_info (in) : Index info.
3584  * pr (in) : Scan predicate.
3585  * node_info_values (in) : Array of value pointers to store b-tree node
3586  * information.
3587  * node_info_regu_list (in) : Regulator variable list.
3588  */
3589 int
3591  /* fields of SCAN_ID */
3592  val_list_node * val_list, VAL_DESCR * vd,
3593  /* fields of INDX_SCAN_ID */
3594  indx_info * indx_info, PRED_EXPR * pr, DB_VALUE ** node_info_values,
3595  regu_variable_list_node * node_info_regu_list)
3596 {
3597  INDEX_NODE_SCAN_ID *idx_nsid_p = NULL;
3598  VPID root_vpid;
3599  PAGE_PTR root_page = NULL;
3600  BTREE_ROOT_HEADER *root_header = NULL;
3601  DB_TYPE single_node_type = DB_TYPE_NULL;
3602  BTID *btid = NULL;
3603 
3604  assert (scan_id != NULL);
3605 
3606  scan_id->type = S_INDX_NODE_INFO_SCAN;
3607 
3608  /* initialize SCAN_ID structure */
3609  scan_init_scan_id (scan_id, 1, S_SELECT, false, false, QPROC_NO_SINGLE_INNER, NULL, val_list, vd);
3610 
3611  idx_nsid_p = &scan_id->s.insid;
3612  idx_nsid_p->indx_info = indx_info;
3613 
3614  /* scan predicate */
3615  scan_init_scan_pred (&idx_nsid_p->scan_pred, NULL, pr, ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3616 
3617  BTREE_NODE_SCAN_INIT (&idx_nsid_p->btns);
3618 
3619  /* read root_page page header info */
3620  btid = &indx_info->btid;
3621 
3622  root_vpid.pageid = btid->root_pageid;
3623  root_vpid.volid = btid->vfid.volid;
3624 
3625  root_page = pgbuf_fix (thread_p, &root_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
3626  if (root_page == NULL)
3627  {
3628  return ER_FAILED;
3629  }
3630  root_header = btree_get_root_header (thread_p, root_page);
3631  pgbuf_unfix_and_init (thread_p, root_page);
3632 
3633  /* construct BTID_INT structure */
3634  idx_nsid_p->btns.btid_int.sys_btid = btid;
3635  if (btree_glean_root_header_info (thread_p, root_header, &idx_nsid_p->btns.btid_int) != NO_ERROR)
3636  {
3637  return ER_FAILED;
3638  }
3639 
3640  idx_nsid_p->node_info_values = node_info_values;
3641  idx_nsid_p->node_info_regu_list = node_info_regu_list;
3642  idx_nsid_p->caches_inited = false;
3643 
3644  return NO_ERROR;
3645 }
3646 
3647 /*
3648  * scan_open_list_scan () -
3649  * return: NO_ERROR
3650  * scan_id(out): Scan identifier
3651  * grouped(in):
3652  * single_fetch(in):
3653  * join_dbval(in):
3654  * val_list(in):
3655  * vd(in):
3656  * list_id(in):
3657  * regu_list_pred(in):
3658  * pr(in):
3659  * regu_list_rest(in):
3660  */
3661 int
3663  /* fields of SCAN_ID */
3664  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list,
3665  VAL_DESCR * vd,
3666  /* fields of LLIST_SCAN_ID */
3667  QFILE_LIST_ID * list_id, regu_variable_list_node * regu_list_pred, PRED_EXPR * pr,
3668  regu_variable_list_node * regu_list_rest, regu_variable_list_node * regu_list_build,
3669  regu_variable_list_node * regu_list_probe, int hash_list_scan_yn)
3670 {
3671  LLIST_SCAN_ID *llsidp;
3672  int val_cnt;
3673  DB_TYPE single_node_type = DB_TYPE_NULL;
3674 
3675  /* scan type is LIST SCAN */
3676  scan_id->type = S_LIST_SCAN;
3677 
3678  /* initialize SCAN_ID structure */
3679  /* mvcc_select_lock_needed = false, fixed = true */
3680  scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
3681 
3682  /* initialize LLIST_SCAN_ID structure */
3683  llsidp = &scan_id->s.llsid;
3684 
3685  /* list file ID */
3686  llsidp->list_id = list_id; /* points to XASL tree */
3687 
3688  /* scan predicates */
3689  scan_init_scan_pred (&llsidp->scan_pred, regu_list_pred, pr,
3690  ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3691 
3692  /* regulator variable list for other than predicates */
3693  llsidp->rest_regu_list = regu_list_rest;
3694 
3695  /* init for hash list scan */
3696  /* regulator variable list for build, probe */
3697  llsidp->hlsid.build_regu_list = regu_list_build;
3698  llsidp->hlsid.probe_regu_list = regu_list_probe;
3699  llsidp->hlsid.need_coerce_type = false;
3700 
3701  /* check if hash list scan is possible? */
3702  llsidp->hlsid.hash_list_scan_yn = check_hash_list_scan (llsidp, &val_cnt, hash_list_scan_yn);
3703  if (llsidp->hlsid.hash_list_scan_yn != HASH_METH_NOT_USE)
3704  {
3705  bool on_trace;
3706  TSC_TICKS start_tick, end_tick;
3707  TSCTIMEVAL tv_diff;
3708 
3709  on_trace = thread_is_on_trace (thread_p);
3710  if (on_trace)
3711  {
3712  tsc_getticks (&start_tick);
3713  }
3714 
3715  /* create hash table */
3716  llsidp->hlsid.hash_table =
3718  if (llsidp->hlsid.hash_table == NULL)
3719  {
3720  return S_ERROR;
3721  }
3722 
3723  /* alloc temp key */
3724  llsidp->hlsid.temp_key = qdata_alloc_hscan_key (thread_p, val_cnt, false);
3725  llsidp->hlsid.temp_new_key = qdata_alloc_hscan_key (thread_p, val_cnt, true);
3726  if (scan_start_scan (thread_p, scan_id) != NO_ERROR)
3727  {
3728  return S_ERROR;
3729  }
3730  if (scan_build_hash_list_scan (thread_p, scan_id) == S_ERROR)
3731  {
3732  return S_ERROR;
3733  }
3734  scan_end_scan (thread_p, scan_id);
3735 
3736  if (on_trace)
3737  {
3738  tsc_getticks (&end_tick);
3739  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
3740  TSC_ADD_TIMEVAL (scan_id->scan_stats.elapsed_hash_build, tv_diff);
3741  }
3742  }
3743  else
3744  {
3745  llsidp->hlsid.hash_table = NULL;
3746  llsidp->hlsid.temp_key = NULL;
3747  llsidp->hlsid.temp_new_key = NULL;
3748  llsidp->hlsid.curr_hash_entry = NULL;
3749  }
3750 
3751  return NO_ERROR;
3752 }
3753 
3754 /*
3755  * scan_open_showstmt_scan () -
3756  * return: NO_ERROR
3757  * scan_id(out): Scan identifier
3758  * grouped(in):
3759  * single_fetch(in):
3760  * join_dbval(in):
3761  * val_list(in):
3762  * vd(in):
3763  * show_type(in):
3764  * arg_list(in):
3765  */
3766 int
3768  /* fields of SCAN_ID */
3769  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list,
3770  VAL_DESCR * vd,
3771  /* fields of SHOWSTMT_SCAN_ID */
3772  PRED_EXPR * pr, SHOWSTMT_TYPE show_type, regu_variable_list_node * arg_list)
3773 {
3774  SHOWSTMT_SCAN_ID *stsidp;
3775  int i, arg_cnt, out_cnt;
3776  regu_variable_list_node *regu_var_p;
3777  REGU_VARIABLE *regu;
3778  QPROC_DB_VALUE_LIST valp;
3779  DB_VALUE **arg_values = NULL, **out_values = NULL;
3780  DB_TYPE single_node_type = DB_TYPE_NULL;
3781  int error;
3782 
3783  /* scan type is S_SHOWSTMT_SCAN */
3784  scan_id->type = S_SHOWSTMT_SCAN;
3785 
3786  /* initialize SCAN_ID structure */
3787  /* readonly_scan = true, fixed = true */
3788  scan_init_scan_id (scan_id, true, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
3789 
3790  /* initialize SHOWSTMT_SCAN_ID structure */
3791  stsidp = &scan_id->s.stsid;
3792 
3793  for (regu_var_p = arg_list, i = 0; regu_var_p; regu_var_p = regu_var_p->next)
3794  {
3795  i++;
3796  }
3797 
3798  arg_cnt = i;
3799  if (arg_cnt > 0)
3800  {
3801  arg_values = (DB_VALUE **) db_private_alloc (thread_p, arg_cnt * sizeof (DB_VALUE *));
3802  if (arg_values == NULL)
3803  {
3804  error = ER_OUT_OF_VIRTUAL_MEMORY;
3805  goto exit_on_error;
3806  }
3807 
3808  for (regu_var_p = arg_list, i = 0; regu_var_p; regu_var_p = regu_var_p->next, i++)
3809  {
3810  regu = &regu_var_p->value;
3811  assert (regu != NULL && regu->type == TYPE_POS_VALUE);
3812  error = fetch_peek_dbval (thread_p, regu, vd, NULL, NULL, NULL, &arg_values[i]);
3813  if (error != NO_ERROR)
3814  {
3815  goto exit_on_error;
3816  }
3817  }
3818  assert (i == arg_cnt);
3819  }
3820 
3821  /* prepare out_values */
3822  out_cnt = val_list->val_cnt;
3823  out_values = (DB_VALUE **) db_private_alloc (thread_p, out_cnt * sizeof (DB_VALUE *));
3824  if (out_values == NULL)
3825  {
3826  error = ER_OUT_OF_VIRTUAL_MEMORY;
3827  goto exit_on_error;
3828  }
3829 
3830  for (valp = val_list->valp, i = 0; valp; valp = valp->next, i++)
3831  {
3832  out_values[i] = valp->val;
3833  }
3834  assert (i == out_cnt);
3835 
3836  stsidp->show_type = show_type;
3837  stsidp->arg_values = arg_values;
3838  stsidp->arg_cnt = arg_cnt;
3839  stsidp->out_values = out_values;
3840  stsidp->out_cnt = out_cnt;
3841  stsidp->cursor = 0;
3842  stsidp->ctx = NULL;
3843 
3844  /* scan predicates */
3845  scan_init_scan_pred (&stsidp->scan_pred, NULL, pr, ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3846 
3847  return NO_ERROR;
3848 
3849 exit_on_error:
3850  if (arg_values != NULL)
3851  {
3852  db_private_free_and_init (thread_p, arg_values);
3853  }
3854 
3855  if (out_values != NULL)
3856  {
3857  db_private_free_and_init (thread_p, out_values);
3858  }
3859  return error;
3860 }
3861 
3862 
3863 
3864 /*
3865  * scan_open_values_scan () -
3866  * return: NO_ERROR
3867  * scan_id(out): Scan identifier
3868  * grouped(in):
3869  * single_fetch(in):
3870  * join_dbval(in):
3871  * val_list(in):
3872  * vd(in):
3873  * valptr_list(in):
3874  */
3875 int
3877  /* fields of SCAN_ID */
3878  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list,
3879  VAL_DESCR * vd,
3880  /* fields of REGU_VALUES_SCAN_ID */
3881  valptr_list_node * valptr_list)
3882 {
3883  REGU_VALUES_SCAN_ID *rvsidp;
3884 
3885  assert (valptr_list != NULL);
3886 
3887  scan_id->type = S_VALUES_SCAN;
3888 
3889  /* initialize SCAN_ID structure */
3890  /* mvcc_select_lock_needed = false, fixed = true */
3891  scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
3892 
3893  rvsidp = &scan_id->s.rvsid;
3894  rvsidp->regu_list = valptr_list->valptrp;
3895  rvsidp->value_cnt = valptr_list->valptr_cnt;
3896 
3897  return NO_ERROR;
3898 }
3899 
3900 /*
3901  * scan_open_set_scan () -
3902  * return: NO_ERROR
3903  * scan_id(out): Scan identifier
3904  * grouped(in):
3905  * single_fetch(in):
3906  * join_dbval(in):
3907  * val_list(in):
3908  * vd(in):
3909  * set_ptr(in):
3910  * regu_list_pred(in):
3911  * pr(in):
3912  */
3913 int
3914 scan_open_set_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id,
3915  /* fields of SCAN_ID */
3916  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list,
3917  VAL_DESCR * vd,
3918  /* fields of SET_SCAN_ID */
3919  REGU_VARIABLE * set_ptr, regu_variable_list_node * regu_list_pred, PRED_EXPR * pr)
3920 {
3921  SET_SCAN_ID *ssidp;
3922  DB_TYPE single_node_type = DB_TYPE_NULL;
3923 
3924  /* scan type is SET SCAN */
3925  scan_id->type = S_SET_SCAN;
3926 
3927  /* initialize SCAN_ID structure */
3928  /* mvcc_select_lock_needed = false, fixed = true */
3929  scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
3930 
3931  /* initialize SET_SCAN_ID structure */
3932  ssidp = &scan_id->s.ssid;
3933 
3934  ssidp->set_ptr = set_ptr; /* points to XASL tree */
3935 
3936  /* scan predicates */
3937  scan_init_scan_pred (&ssidp->scan_pred, regu_list_pred, pr,
3938  ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3939 
3940  return NO_ERROR;
3941 }
3942 
3943 /*
3944  * scan_open_json_table_scan () -
3945  * return: NO_ERROR
3946  * scan_id(out): Scan identifier
3947  * grouped(in):
3948  * single_fetch(in):
3949  * join_dbval(in):
3950  * val_list(in):
3951  * vd(in):
3952  */
3953 int
3954 scan_open_json_table_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch,
3955  DB_VALUE * join_dbval, val_list_node * val_list, VAL_DESCR * vd, PRED_EXPR * pr)
3956 {
3957  DB_TYPE single_node_type = DB_TYPE_NULL;
3958 
3959  /* scan type is JSON_TABLE SCAN */
3960  assert (scan_id->type == S_JSON_TABLE_SCAN);
3961 
3962  /* initialize SCAN_ID structure */
3963  /* mvcc_select_lock_needed = false, fixed = true */
3964  scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
3965 
3966  // scan_init_scan_pred
3967  scan_init_scan_pred (&scan_id->s.jtid.get_predicate (), NULL, pr,
3968  ((pr) ? eval_fnc (thread_p, pr, &single_node_type) : NULL));
3969  scan_id->s.jtid.set_value_descriptor (vd);
3970 
3971  return NO_ERROR;
3972 }
3973 
3974 /*
3975  * scan_open_method_scan () -
3976  * return: NO_ERROR, or ER_code
3977  * scan_id(out): Scan identifier
3978  * grouped(in):
3979  * single_fetch(in):
3980  * join_dbval(in):
3981  * val_list(in):
3982  * vd(in):
3983  * list_id(in):
3984  * meth_sig_list(in):
3985  *
3986  * Note: If you feel the need
3987  */
3988 int
3990  /* fields of SCAN_ID */
3991  int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list,
3992  VAL_DESCR * vd,
3993  /* */
3994  QFILE_LIST_ID * list_id, method_sig_list * meth_sig_list)
3995 {
3996  /* scan type is METHOD SCAN */
3997  scan_id->type = S_METHOD_SCAN;
3998 
3999  /* initialize SCAN_ID structure */
4000  /* mvcc_select_lock_needed = false, fixed = true */
4001  scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd);
4002 
4003  return method_open_scan (thread_p, &scan_id->s.vaid.scan_buf, list_id, meth_sig_list);
4004 }
4005 
4006 /*
4007  * scan_start_scan () - Start the scan process on the given scan identifier.
4008  * return: NO_ERROR, or ER_code
4009  * scan_id(out): Scan identifier
4010  *
4011  * Note: If you feel the need
4012  */
4013 int
4014 scan_start_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id)
4015 {
4016  int ret = NO_ERROR;
4017  int i;
4018  HEAP_SCAN_ID *hsidp = NULL;
4019  INDX_SCAN_ID *isidp = NULL;
4020  INDEX_NODE_SCAN_ID *insidp = NULL;
4021  LLIST_SCAN_ID *llsidp = NULL;
4022  SET_SCAN_ID *ssidp = NULL;
4023  REGU_VALUES_SCAN_ID *rvsidp = NULL;
4025  regu_variable_list_node *list_node = NULL;
4027  JSON_TABLE_SCAN_ID *jtidp = NULL;
4028 
4029  switch (scan_id->type)
4030  {
4031  case S_HEAP_SCAN:
4033  hsidp = &scan_id->s.hsid;
4034  UT_CAST_TO_NULL_HEAP_OID (&hsidp->hfid, &hsidp->curr_oid);
4035  if (!OID_IS_ROOTOID (&hsidp->cls_oid))
4036  {
4037  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
4038  if (mvcc_snapshot == NULL)
4039  {
4040  goto exit_on_error;
4041  }
4042  }
4043  if (scan_id->grouped)
4044  {
4045  ret = heap_scanrange_start (thread_p, &hsidp->scan_range, &hsidp->hfid, &hsidp->cls_oid, mvcc_snapshot);
4046  if (ret != NO_ERROR)
4047  {
4048  goto exit_on_error;
4049  }
4050  hsidp->scanrange_inited = true;
4051  }
4052  else
4053  {
4054  /* A new argument(is_indexscan = false) is appended */
4055  ret =
4056  heap_scancache_start (thread_p, &hsidp->scan_cache, &hsidp->hfid, &hsidp->cls_oid, scan_id->fixed, false,
4057  mvcc_snapshot);
4058  if (ret != NO_ERROR)
4059  {
4060  goto exit_on_error;
4061  }
4062  hsidp->scancache_inited = true;
4063  }
4064  if (hsidp->caches_inited != true)
4065  {
4066  hsidp->pred_attrs.attr_cache->num_values = -1;
4067  ret =
4068  heap_attrinfo_start (thread_p, &hsidp->cls_oid, hsidp->pred_attrs.num_attrs, hsidp->pred_attrs.attr_ids,
4069  hsidp->pred_attrs.attr_cache);
4070  if (ret != NO_ERROR)
4071  {
4072  goto exit_on_error;
4073  }
4074  hsidp->rest_attrs.attr_cache->num_values = -1;
4075  ret =
4076  heap_attrinfo_start (thread_p, &hsidp->cls_oid, hsidp->rest_attrs.num_attrs, hsidp->rest_attrs.attr_ids,
4077  hsidp->rest_attrs.attr_cache);
4078  if (ret != NO_ERROR)
4079  {
4080  heap_attrinfo_end (thread_p, hsidp->pred_attrs.attr_cache);
4081  goto exit_on_error;
4082  }
4083  if (hsidp->cache_recordinfo != NULL)
4084  {
4085  /* initialize cache_recordinfo values */
4086  for (i = 0; i < HEAP_RECORD_INFO_COUNT; i++)
4087  {
4088  db_make_null (hsidp->cache_recordinfo[i]);
4089  }
4090  }
4091  hsidp->caches_inited = true;
4092  }
4093  break;
4094 
4095  case S_HEAP_PAGE_SCAN:
4096  VPID_SET_NULL (&scan_id->s.hpsid.curr_vpid);
4097  break;
4098 
4099  case S_CLASS_ATTR_SCAN:
4100  hsidp = &scan_id->s.hsid;
4101  hsidp->pred_attrs.attr_cache->num_values = -1;
4102  if (hsidp->caches_inited != true)
4103  {
4104  ret =
4105  heap_attrinfo_start (thread_p, &hsidp->cls_oid, hsidp->pred_attrs.num_attrs, hsidp->pred_attrs.attr_ids,
4106  hsidp->pred_attrs.attr_cache);
4107  if (ret != NO_ERROR)
4108  {
4109  goto exit_on_error;
4110  }
4111  hsidp->rest_attrs.attr_cache->num_values = -1;
4112  ret =
4113  heap_attrinfo_start (thread_p, &hsidp->cls_oid, hsidp->rest_attrs.num_attrs, hsidp->rest_attrs.attr_ids,
4114  hsidp->rest_attrs.attr_cache);
4115  if (ret != NO_ERROR)
4116  {
4117  heap_attrinfo_end (thread_p, hsidp->pred_attrs.attr_cache);
4118  goto exit_on_error;
4119  }
4120  hsidp->caches_inited = true;
4121  }
4122  break;
4123 
4124  case S_INDX_SCAN:
4125  isidp = &scan_id->s.isid;
4126  if (!OID_IS_ROOTOID (&isidp->cls_oid))
4127  {
4128  mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
4129  if (mvcc_snapshot == NULL)
4130  {
4131  goto exit_on_error;
4132  }
4133  }
4134 
4135  /* A new argument(is_indexscan = true) is appended */
4136  ret =
4137  heap_scancache_start (thread_p, &isidp->scan_cache, &isidp->hfid, &isidp->cls_oid, scan_id->fixed, true,
4138  mvcc_snapshot);
4139  if (ret != NO_ERROR)
4140  {
4141  goto exit_on_error;
4142  }
4143  isidp->scancache_inited = true;
4144  if (isidp->caches_inited != true)
4145  {
4146  if (isidp->range_pred.regu_list != NULL)
4147  {
4148  isidp->range_attrs.attr_cache->num_values = -1;
4149  ret =
4150  heap_attrinfo_start (thread_p, &isidp->cls_oid, isidp->range_attrs.num_attrs,
4151  isidp->range_attrs.attr_ids, isidp->range_attrs.attr_cache);
4152  if (ret != NO_ERROR)
4153  {
4154  goto exit_on_error;
4155  }
4156  }
4157  if (isidp->key_pred.regu_list != NULL)
4158  {
4159  isidp->key_attrs.attr_cache->num_values = -1;
4160  ret =
4161  heap_attrinfo_start (thread_p, &isidp->cls_oid, isidp->key_attrs.num_attrs, isidp->key_attrs.attr_ids,
4162  isidp->key_attrs.attr_cache);
4163  if (ret != NO_ERROR)
4164  {
4165  if (isidp->range_pred.regu_list != NULL)
4166  {
4167  heap_attrinfo_end (thread_p, isidp->range_attrs.attr_cache);
4168  }
4169  goto exit_on_error;
4170  }
4171  }
4172  isidp->pred_attrs.attr_cache->num_values = -1;
4173  ret =
4174  heap_attrinfo_start (thread_p, &isidp->cls_oid, isidp->pred_attrs.num_attrs, isidp->pred_attrs.attr_ids,
4175  isidp->pred_attrs.attr_cache);
4176  if (ret != NO_ERROR)
4177  {
4178  if (isidp->range_pred.regu_list != NULL)
4179  {
4180  heap_attrinfo_end (thread_p, isidp->range_attrs.attr_cache);
4181  }
4182  if (isidp->key_pred.regu_list != NULL)
4183  {
4184  heap_attrinfo_end (thread_p, isidp->key_attrs.attr_cache);
4185  }
4186  goto exit_on_error;
4187  }
4188  isidp->rest_attrs.attr_cache->num_values = -1;
4189  ret =
4190  heap_attrinfo_start (thread_p, &isidp->cls_oid, isidp->rest_attrs.num_attrs, isidp->rest_attrs.attr_ids,
4191  isidp->rest_attrs.attr_cache);
4192  if (ret != NO_ERROR)
4193  {
4194  if (isidp->range_pred.regu_list != NULL)
4195  {
4196  heap_attrinfo_end (thread_p, isidp->range_attrs.attr_cache);
4197  }
4198  if (isidp->key_pred.regu_list != NULL)
4199  {
4200  heap_attrinfo_end (thread_p, isidp->key_attrs.attr_cache);
4201  }
4202  heap_attrinfo_end (thread_p, isidp->pred_attrs.attr_cache);
4203  goto exit_on_error;
4204  }
4205  isidp->caches_inited = true;
4206  }
4207  isidp->oids_count = 0;
4208  isidp->curr_keyno = -1;
4209  isidp->curr_oidno = -1;
4210  isidp->one_range = false;
4211  break;
4212 
4213  case S_INDX_KEY_INFO_SCAN:
4214  isidp = &scan_id->s.isid;
4215 
4216  if (!isidp->caches_inited)
4217  {
4218  for (i = 0; i < BTREE_KEY_INFO_COUNT; i++)
4219  {
4220  db_make_null (isidp->key_info_values[i]);
4221  }
4222  }
4223  isidp->caches_inited = true;
4224  isidp->oids_count = 0;
4225  isidp->curr_keyno = -1;
4226  isidp->curr_oidno = -1;
4227  break;
4228 
4229  case S_INDX_NODE_INFO_SCAN:
4230  insidp = &scan_id->s.insid;
4231 
4232  if (!insidp->caches_inited)
4233  {
4234  for (i = 0; i < BTREE_NODE_INFO_COUNT; i++)
4235  {
4236  db_make_null (insidp->node_info_values[i]);
4237  }
4238  insidp->caches_inited = true;
4239  }
4240  BTREE_NODE_SCAN_INIT (&insidp->btns);
4241  break;
4242 
4243  case S_LIST_SCAN:
4244  llsidp = &scan_id->s.llsid;
4245  /* open list file scan */
4246  if (qfile_open_list_scan (llsidp->list_id, &llsidp->lsid) != NO_ERROR)
4247  {
4248  goto exit_on_error;
4249  }
4250  qfile_start_scan_fix (thread_p, &llsidp->lsid);
4251  break;
4252 
4253  case S_SHOWSTMT_SCAN:
4254  if (showstmt_start_scan (thread_p, scan_id) != NO_ERROR)
4255  {
4256  goto exit_on_error;
4257  }
4258  break;
4259 
4260  case S_VALUES_SCAN:
4261  rvsidp = &scan_id->s.rvsid;
4262  if (rvsidp->regu_list == NULL)
4263  {
4265  goto exit_on_error;
4266  }
4267 
4268  for (list_node = rvsidp->regu_list; list_node; list_node = list_node->next)
4269  {
4270  regu_value_list = list_node->value.value.reguval_list;
4271  assert (regu_value_list != NULL && regu_value_list->regu_list != NULL);
4272 
4273  regu_value_list->current_value = regu_value_list->regu_list;
4274  }
4275  break;
4276 
4277  case S_SET_SCAN:
4278  ssidp = &scan_id->s.ssid;
4279  db_make_null (&ssidp->set);
4280  break;
4281 
4282  case S_JSON_TABLE_SCAN:
4283  jtidp = &scan_id->s.jtid;
4284  // todo: what else to add here?
4285  break;
4286 
4287  case S_METHOD_SCAN:
4288  break;
4289 
4290  default:
4292  goto exit_on_error;
4293  } /* switch (scan_id->type) */
4294 
4295  /* set scan status as started */
4296  scan_id->position = S_BEFORE;
4297  scan_id->direction = S_FORWARD;
4298  scan_id->status = S_STARTED;
4299  scan_id->qualified_block = false;
4300  scan_id->single_fetched = false;
4301  scan_id->null_fetched = false;
4302 
4303  return ret;
4304 
4305 exit_on_error:
4306 
4307  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
4308 }
4309 
4310 /*
4311  * scan_reset_scan_block () - Move the scan back to the beginning point inside the current scan block.
4312  * return: S_SUCCESS, S_END, S_ERROR
4313  * s_id(in/out): Scan identifier
4314  *
4315  * Note: If you feel the need
4316  */
4317 SCAN_CODE
4319 {
4320  SCAN_CODE status = S_SUCCESS;
4321 
4322  s_id->single_fetched = false;
4323  s_id->null_fetched = false;
4324 
4325  switch (s_id->type)
4326  {
4327  case S_HEAP_SCAN:
4328  if (s_id->grouped)
4329  {
4330  OID_SET_NULL (&s_id->s.hsid.curr_oid);
4331  }
4332  else
4333  {
4334  s_id->position = (s_id->direction == S_FORWARD) ? S_BEFORE : S_AFTER;
4335  OID_SET_NULL (&s_id->s.hsid.curr_oid);
4336  }
4337  break;
4338 
4339  case S_INDX_SCAN:
4340  if (s_id->grouped)
4341  {
4342  if (s_id->direction == S_FORWARD && s_id->s.isid.iscan_oid_order == true)
4343  {
4344  s_id->s.isid.curr_oidno = s_id->s.isid.oids_count;
4345  s_id->direction = S_BACKWARD;
4346  }
4347  else
4348  {
4349  s_id->s.isid.curr_oidno = -1;
4350  s_id->direction = S_FORWARD;
4351  }
4352 
4353  /* reinitialize index skip scan structure */
4354  if (scan_init_iss (&s_id->s.isid) != NO_ERROR)
4355  {
4356  status = S_ERROR;
4357  break;
4358  }
4359  }
4360  else
4361  {
4362  INDX_COV *indx_cov_p;
4363 
4364  s_id->s.isid.curr_oidno = -1;
4365  s_id->s.isid.curr_keyno = -1;
4366  s_id->position = S_BEFORE;
4367  BTREE_RESET_SCAN (&s_id->s.isid.bt_scan);
4368 
4369  /* reset key limits */
4370  if (s_id->s.isid.indx_info)
4371  {
4372  if (scan_init_index_key_limit (thread_p, &s_id->s.isid, &s_id->s.isid.indx_info->key_info, s_id->vd) !=
4373  NO_ERROR)
4374  {
4375  status = S_ERROR;
4376  break;
4377  }
4378  }
4379 
4380  /* reinitialize index skip scan structure */
4381  if (scan_init_iss (&s_id->s.isid) != NO_ERROR)
4382  {
4383  status = S_ERROR;
4384  break;
4385  }
4386 
4387  /* reset index covering */
4388  indx_cov_p = &(s_id->s.isid.indx_cov);
4389  if (indx_cov_p->lsid != NULL)
4390  {
4391  qfile_close_scan (thread_p, indx_cov_p->lsid);
4392  }
4393 
4394  if (indx_cov_p->list_id != NULL)
4395  {
4396  qfile_destroy_list (thread_p, indx_cov_p->list_id);
4397  QFILE_FREE_AND_INIT_LIST_ID (indx_cov_p->list_id);
4398 
4399  indx_cov_p->list_id = qfile_open_list (thread_p, indx_cov_p->type_list, NULL, indx_cov_p->query_id, 0);
4400  if (indx_cov_p->list_id == NULL)
4401  {
4402  status = S_ERROR;
4403  }
4404  }
4405  }
4406  break;
4407 
4408  case S_LIST_SCAN:
4409  /* may have scanned some already so clean up */
4410  qfile_end_scan_fix (thread_p, &s_id->s.llsid.lsid);
4411  qfile_close_scan (thread_p, &s_id->s.llsid.lsid);
4412 
4413  /* open list file scan for this outer row */
4414  if (qfile_open_list_scan (s_id->s.llsid.list_id, &s_id->s.llsid.lsid) != NO_ERROR)
4415  {
4416  status = S_ERROR;
4417  break;
4418  }
4419  qfile_start_scan_fix (thread_p, &s_id->s.llsid.lsid);
4420  s_id->position = S_BEFORE;
4421  s_id->s.llsid.lsid.position = S_BEFORE;
4422  break;
4423 
4424  case S_SHOWSTMT_SCAN:
4425  s_id->s.stsid.cursor = 0;
4426  s_id->position = S_BEFORE;
4427  break;
4428 
4429  case S_CLASS_ATTR_SCAN:
4430  case S_SET_SCAN:
4431  case S_JSON_TABLE_SCAN:
4432  s_id->position = S_BEFORE;
4433  break;
4434 
4435  default:
4437  status = S_ERROR;
4438  break;
4439  } /* switch (s_id->type) */
4440 
4441  return status;
4442 }
4443 
4444 /*
4445  * scan_next_scan_block () - Move the scan to the next scan block.
4446  * If there are no more scan blocks left, S_END is returned.
4447  * return: S_SUCCESS, S_END, S_ERROR
4448  * s_id(in/out): Scan identifier
4449  *
4450  * Note: If you feel the need
4451  */
4452 SCAN_CODE
4454 {
4455  SCAN_CODE sp_scan;
4456 
4457  s_id->single_fetched = false;
4458  s_id->null_fetched = false;
4459  s_id->qualified_block = false;
4460 
4461  switch (s_id->type)
4462  {
4463  case S_HEAP_SCAN:
4465  case S_HEAP_PAGE_SCAN:
4466  if (s_id->grouped)
4467  {
4468  /* grouped, fixed scan */
4469  if (s_id->direction == S_FORWARD)
4470  {
4471  sp_scan = heap_scanrange_to_following (thread_p, &s_id->s.hsid.scan_range, NULL);
4472  }
4473  else
4474  {
4475  sp_scan = heap_scanrange_to_prior (thread_p, &s_id->s.hsid.scan_range, NULL);
4476  }
4477 
4478  if (sp_scan == S_SUCCESS || sp_scan == S_END)
4479  {
4480  return sp_scan;
4481  }
4482  else
4483  {
4484  return S_ERROR;
4485  }
4486  }
4487  else
4488  {
4489  if (s_id->direction == S_FORWARD)
4490  {
4491  if (s_id->position == S_BEFORE)
4492  {
4493  return S_SUCCESS;
4494  }
4495  else
4496  {
4497  return S_END;
4498  }
4499  }
4500  else
4501  {
4502  if (s_id->position == S_AFTER)
4503  {
4504  return S_SUCCESS;
4505  }
4506  else
4507  {
4508  return S_END;
4509  }
4510  }
4511  }
4512 
4513  case S_INDX_SCAN:
4514  if (s_id->grouped)
4515  {
4516  if ((s_id->direction == S_FORWARD && s_id->position == S_BEFORE)
4517  || (!BTREE_END_OF_SCAN (&s_id->s.isid.bt_scan) || s_id->s.isid.indx_info->range_type == R_KEYLIST
4518  || s_id->s.isid.indx_info->range_type == R_RANGELIST))
4519  {
4520  if (!(s_id->position == S_BEFORE && s_id->s.isid.one_range == true))
4521  {
4522  /* get the next set of object identifiers specified in the range */
4523  if (scan_get_index_oidset (thread_p, s_id, NULL, NULL) != NO_ERROR)
4524  {
4525  return S_ERROR;
4526  }
4527 
4528  if (s_id->s.isid.oids_count == 0)
4529  { /* range is empty */
4530  s_id->position = S_AFTER;
4531  return S_END;
4532  }
4533 
4534  if (s_id->position == S_BEFORE && BTREE_END_OF_SCAN (&s_id->s.isid.bt_scan)
4535  && s_id->s.isid.indx_info->range_type != R_KEYLIST
4536  && s_id->s.isid.indx_info->range_type != R_RANGELIST)
4537  {
4538  s_id->s.isid.one_range = true;
4539  }
4540  }
4541 
4542  if (s_id->s.isid.iscan_oid_order == true)
4543  {
4544  s_id->position = S_ON;
4545  s_id->direction = S_BACKWARD;
4546  s_id->s.isid.curr_oidno = s_id->s.isid.oids_count;
4547  }
4548 
4549  return S_SUCCESS;
4550  }
4551  else
4552  {
4553  s_id->position = S_AFTER;
4554  return S_END;
4555  }
4556  }
4557  else
4558  {
4559  return ((s_id->position == S_BEFORE) ? S_SUCCESS : S_END);
4560  }
4561 
4562  case S_INDX_KEY_INFO_SCAN:
4563  case S_INDX_NODE_INFO_SCAN:
4564  if (s_id->grouped)
4565  {
4566  assert (0);
4567  return S_ERROR;
4568  }
4569  return ((s_id->position == S_BEFORE) ? S_SUCCESS : S_END);
4570 
4571  case S_CLASS_ATTR_SCAN:
4572  case S_LIST_SCAN:
4573  case S_SHOWSTMT_SCAN:
4574  case S_SET_SCAN:
4575  case S_METHOD_SCAN:
4576  case S_JSON_TABLE_SCAN:
4577  case S_VALUES_SCAN:
4578  return (s_id->position == S_BEFORE) ? S_SUCCESS : S_END;
4579 
4580  default:
4582  return S_ERROR;
4583  }
4584 }
4585 
4586 /*
4587  * scan_end_scan () - End the scan process on the given scan identifier.
4588  * return:
4589  * scan_id(in/out): Scan identifier
4590  *
4591  * Note: If you feel the need
4592  */
4593 void
4594 scan_end_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id)
4595 {
4596  HEAP_SCAN_ID *hsidp;
4597  INDX_SCAN_ID *isidp;
4598  LLIST_SCAN_ID *llsidp;
4599  REGU_VALUES_SCAN_ID *rvsidp;
4600  SET_SCAN_ID *ssidp;
4601  KEY_VAL_RANGE *key_vals;
4602  JSON_TABLE_SCAN_ID *jtidp;
4603  int i;
4604 
4605  if (scan_id == NULL)
4606  {
4607  return;
4608  }
4609 
4610  if ((scan_id->status == S_ENDED) || (scan_id->status == S_CLOSED))
4611  {
4612  return;
4613  }
4614 
4615  switch (scan_id->type)
4616  {
4617  case S_HEAP_SCAN:
4619  hsidp = &scan_id->s.hsid;
4620 
4621  /* do not free attr_cache here. xs_clear_access_spec_list() will free attr_caches. */
4622 
4623  if (scan_id->grouped)
4624  {
4625  if (hsidp->scanrange_inited)
4626  {
4627  heap_scanrange_end (thread_p, &hsidp->scan_range);
4628  }
4629  }
4630  else
4631  {
4632  if (hsidp->scancache_inited)
4633  {
4634  (void) heap_scancache_end (thread_p, &hsidp->scan_cache);
4635  }
4636  }
4637 
4638  /* switch scan direction for further iterations */
4639  if (scan_id->direction == S_FORWARD)
4640  {
4641  scan_id->direction = S_BACKWARD;
4642  }
4643  else
4644  {
4645  scan_id->direction = S_FORWARD;
4646  }
4647  break;
4648 
4649  case S_CLASS_ATTR_SCAN:
4650  /* do not free attr_cache here. xs_clear_access_spec_list() will free attr_caches. */
4651  break;
4652 
4653  case S_INDX_SCAN:
4654  isidp = &scan_id->s.isid;
4655 
4656  /* do not free attr_cache here. xs_clear_access_spec_list() will free attr_caches. */
4657 
4658  if (isidp->scancache_inited)
4659  {
4660  (void) heap_scancache_end (thread_p, &isidp->scan_cache);
4661  }
4662  if (isidp->curr_keyno >= 0 && isidp->curr_keyno < isidp->key_cnt)
4663  {
4664  key_vals = isidp->key_vals;
4665  for (i = 0; i < isidp->key_cnt; i++)
4666  {
4667  pr_clear_value (&key_vals[i].key1);
4668  pr_clear_value (&key_vals[i].key2);
4669  }
4670  }
4671  /* clear all the used keys */
4672  btree_scan_clear_key (&(isidp->bt_scan));
4673  /* clear last_key */
4674  (void) scan_init_iss (isidp);
4675  break;
4676 
4677  case S_LIST_SCAN:
4678  llsidp = &scan_id->s.llsid;
4679  qfile_end_scan_fix (thread_p, &llsidp->lsid);
4680  qfile_close_scan (thread_p, &llsidp->lsid);
4681  break;
4682 
4683  case S_SHOWSTMT_SCAN:
4684  showstmt_end_scan (thread_p, scan_id);
4685  break;
4686 
4687  case S_VALUES_SCAN:
4688  rvsidp = &scan_id->s.rvsid;
4689  break;
4690 
4691  case S_SET_SCAN:
4692  ssidp = &scan_id->s.ssid;
4693  pr_clear_value (&ssidp->set);
4694  break;
4695 
4696  case S_JSON_TABLE_SCAN:
4697  jtidp = &scan_id->s.jtid;
4698  jtidp->end (thread_p);
4699  break;
4700 
4701  case S_METHOD_SCAN:
4702  break;
4703 
4704  default:
4705  break;
4706  }
4707 
4708  scan_id->status = S_ENDED;
4709 }
4710 
4711 /*
4712  * scan_close_scan () - The scan identifier is closed and allocated areas and page buffers are freed.
4713  * return:
4714  * scan_id(in/out): Scan identifier
4715  *
4716  * Note: If you feel the need
4717  */
4718 void
4719 scan_close_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id)
4720 {
4721  INDX_SCAN_ID *isidp;
4722  SHOWSTMT_SCAN_ID *stsidp;
4723  LLIST_SCAN_ID *llsidp;
4724 
4725  if (scan_id == NULL || scan_id->status == S_CLOSED)
4726  {
4727  return;
4728  }
4729 
4730  switch (scan_id->type)
4731  {
4732  case S_HEAP_SCAN:
4734  case S_HEAP_PAGE_SCAN:
4735  case S_CLASS_ATTR_SCAN:
4736  case S_VALUES_SCAN:
4737  break;
4738 
4739  case S_INDX_SCAN:
4740  isidp = &scan_id->s.isid;
4741  if (isidp->key_vals)
4742  {
4743  db_private_free_and_init (thread_p, isidp->key_vals);
4744  }
4745  if (isidp->fetched_values)
4746  {
4747  for (int j = 0; j < isidp->bt_num_attrs; j++)
4748  {
4749  pr_clear_value (&isidp->fetched_values[j]);
4750  }
4751  db_private_free_and_init (thread_p, isidp->fetched_values);
4752  }
4753 
4754  /* free allocated memory for the scan */
4755  if (isidp->bt_attr_ids)
4756  {
4757  db_private_free_and_init (thread_p, isidp->bt_attr_ids);
4758  }
4759  if (isidp->bt_attrs_prefix_length)
4760  {
4762  }
4763  if (isidp->vstr_ids)
4764  {
4765  db_private_free_and_init (thread_p, isidp->vstr_ids);
4766  }
4767  if (isidp->oid_list != NULL)
4768  {
4770  isidp->oid_list = NULL;
4771  }
4772 
4773  /* free index key copy_buf */
4774  if (isidp->copy_buf)
4775  {
4776  db_private_free_and_init (thread_p, isidp->copy_buf);
4777  }
4778 
4779  /* free index covering */
4780  if (isidp->indx_cov.lsid != NULL)
4781  {
4782  qfile_close_scan (thread_p, isidp->indx_cov.lsid);
4783  db_private_free_and_init (thread_p, isidp->indx_cov.lsid);
4784  }
4785  if (isidp->indx_cov.list_id != NULL)
4786  {
4787  qfile_close_list (thread_p, isidp->indx_cov.list_id);
4788  qfile_destroy_list (thread_p, isidp->indx_cov.list_id);
4790  }
4791  if (isidp->indx_cov.type_list != NULL)
4792  {
4793  if (isidp->indx_cov.type_list->domp != NULL)
4794  {
4795  db_private_free_and_init (thread_p, isidp->indx_cov.type_list->domp);
4796  }
4797  db_private_free_and_init (thread_p, isidp->indx_cov.type_list);
4798  }
4799  if (isidp->indx_cov.tplrec != NULL)
4800  {
4801  if (isidp->indx_cov.tplrec->tpl != NULL)
4802  {
4803  db_private_free_and_init (thread_p, isidp->indx_cov.tplrec->tpl);
4804  }
4805  db_private_free_and_init (thread_p, isidp->indx_cov.tplrec);
4806  }
4807 
4808  /* free multiple range optimization struct */
4809  if (isidp->multi_range_opt.top_n_items != NULL)
4810  {
4811  int i;
4812 
4813  for (i = 0; i < isidp->multi_range_opt.size; i++)
4814  {
4815  if (isidp->multi_range_opt.top_n_items[i] != NULL)
4816  {
4819  }
4820  }
4822  isidp->multi_range_opt.top_n_items = NULL;
4824  isidp->multi_range_opt.tplrec.tpl = 0;
4825  }
4826  /* free buffer */
4827  if (isidp->multi_range_opt.buffer != NULL)
4828  {
4829  db_private_free_and_init (thread_p, isidp->multi_range_opt.buffer);
4830  }
4831  if (isidp->multi_range_opt.sort_att_idx != NULL)
4832  {
4834  }
4835  if (isidp->multi_range_opt.is_desc_order != NULL)
4836  {
4838  }
4839  if (isidp->multi_range_opt.sort_col_dom != NULL)
4840  {
4842  }
4843  memset ((void *) (&(isidp->multi_range_opt)), 0, sizeof (MULTI_RANGE_OPT));
4844  break;
4845 
4846  case S_LIST_SCAN:
4847  llsidp = &scan_id->s.llsid;
4848  /* clear hash list scan table */
4849  if (llsidp->hlsid.hash_table != NULL)
4850  {
4851 #if 0
4852  (void) mht_dump_hls (thread_p, stdout, llsidp->hlsid.hash_table, 1, qdata_print_hash_scan_entry,
4853  (void *) &llsidp->hlsid.hash_list_scan_yn);
4854  printf ("temp file : tuple count = %d, file_size = %dK\n", llsidp->list_id->tuple_cnt,
4855  llsidp->list_id->page_cnt * 16);
4856 #endif
4857  mht_clear_hls (llsidp->hlsid.hash_table, qdata_free_hscan_entry, (void *) thread_p);
4858  mht_destroy_hls (llsidp->hlsid.hash_table);
4859  }
4860  /* free temp keys and values */
4861  if (llsidp->hlsid.temp_key != NULL)
4862  {
4863  qdata_free_hscan_key (thread_p, llsidp->hlsid.temp_key, llsidp->hlsid.temp_key->val_count);
4864  llsidp->hlsid.temp_key = NULL;
4865  }
4866  /* free temp new keys and values */
4867  if (llsidp->hlsid.temp_new_key != NULL)
4868  {
4869  qdata_free_hscan_key (thread_p, llsidp->hlsid.temp_new_key, llsidp->hlsid.temp_new_key->val_count);
4870  llsidp->hlsid.temp_new_key = NULL;
4871  }
4872  break;
4873 
4874  case S_SHOWSTMT_SCAN:
4875  stsidp = &scan_id->s.stsid;
4876  if (stsidp->arg_values != NULL)
4877  {
4878  db_private_free_and_init (thread_p, stsidp->arg_values);
4879  }
4880  if (stsidp->out_values != NULL)
4881  {
4882  db_private_free_and_init (thread_p, stsidp->out_values);
4883  }
4884  break;
4885 
4886  case S_SET_SCAN:
4887  break;
4888 
4889  case S_METHOD_SCAN:
4890  method_close_scan (thread_p, &scan_id->s.vaid.scan_buf);
4891  break;
4892 
4893  case S_JSON_TABLE_SCAN:
4894  break;
4895 
4896  default:
4897  /* S_VALUES_SCAN */
4898  break;
4899  }
4900 
4901  scan_id->status = S_CLOSED;
4902 }
4903 
4904 /*
4905  * call_get_next_index_oidset () - Wrapper for scan_get_next_oidset, accounts
4906  * for scan variations, such as the "index
4907  * skip scan" optimization.
4908  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
4909  * thread_p (in):
4910  * scan_id (in/out):
4911  * isidp (in/out):
4912  * should_go_to_next_value (in): see Notes
4913  *
4914  * Note:
4915  * This function tries to obtain the next set of OIDs for the scan to consume.
4916  * The real heavy-lifting function is get_next_index_oidset(), which we call,
4917  * this one is a wrapper.
4918  * If the "Index Skip Scan" optimization is used, we cycle through successive
4919  * values of the first index column until we find one that lets
4920  * get_index_oidset() return with some results.
4921  * We also handle the case where we are called just because a new crop of OIDs
4922  * is needed.
4923  *
4924  * The boolean should_go_to_next_value controls whether we skip to the next
4925  * value for the first index column, or we still have data to read for the
4926  * current value (i.e. because the buffer was full. It is controlled by
4927  * the caller by evaluating BTREE_END_OF_SCAN. If this is true, there are no
4928  * more OIDS for the current value of the first index column and we should
4929  * "skip" to the next one.
4930  */
4931 static SCAN_CODE
4933  bool should_go_to_next_value)
4934 {
4935  DB_BIGINT *p_kl_upper = NULL;
4936  DB_BIGINT *p_kl_lower = NULL;
4937  int oids_cnt;
4938 
4939 /*
4940  * WHILE (true)
4941  * {
4942  * if (iss && should-skip-to-next-iss-value)
4943  * obtain-next-iss-value() or return if it does not find anything;
4944  *
4945  * get-index-oidset();
4946  *
4947  * if (oids count == 0) // did not find anything
4948  * {
4949  * should-skip-to-next-iss-value = true;
4950  * if (iss)
4951  * continue; // to allow the while () to fetch the next value for the
4952  * // first column in the index
4953  * return S_END; // BTRS returned nothing and we are not in ISS mode. Leave.
4954  * }
4955  *
4956  * break; //at least one OID found. get out of the loop.
4957  *}
4958  */
4959 
4960  while (1)
4961  {
4962  if (isidp->iss.use && should_go_to_next_value)
4963  {
4964  SCAN_CODE code = scan_get_next_iss_value (thread_p, scan_id, isidp);
4965  if (code != S_SUCCESS)
4966  {
4967  /* anything wrong? or even end of scan? just leave */
4968  return code;
4969  }
4970  }
4971 
4972  p_kl_lower = isidp->key_limit_lower == -1 ? NULL : &isidp->key_limit_lower;
4973  p_kl_upper = isidp->key_limit_upper == -1 ? NULL : &isidp->key_limit_upper;
4974 
4975  if (scan_get_index_oidset (thread_p, scan_id, p_kl_upper, p_kl_lower) != NO_ERROR)
4976  {
4977  return S_ERROR;
4978  }
4979 
4980  oids_cnt = isidp->multi_range_opt.use ? isidp->multi_range_opt.cnt : isidp->oids_count;
4981 
4982  if (oids_cnt == 0)
4983  {
4984  if (isidp->iss.use)
4985  {
4986  should_go_to_next_value = true;
4987  continue;
4988  }
4989  return S_END; /* no ISS, no oids, this is the end of scan. */
4990  }
4991 
4992  /* We have at least one OID. Break the loop, allow normal processing. */
4993  break;
4994  }
4995 
4996  return S_SUCCESS;
4997 }
4998 
4999 /*
5000  * scan_next_scan_local () - The scan is moved to the next scan item.
5001  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
5002  * scan_id(in/out): Scan identifier
5003  *
5004  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
5005  */
5006 static SCAN_CODE
5008 {
5009  SCAN_CODE status;
5010  bool on_trace;
5011  UINT64 old_fetches = 0, old_ioreads = 0;
5012  TSC_TICKS start_tick, end_tick;
5013  TSCTIMEVAL tv_diff;
5014 
5015  on_trace = thread_is_on_trace (thread_p);
5016  if (on_trace)
5017  {
5018  tsc_getticks (&start_tick);
5019 
5020  old_fetches = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_FETCHES);
5021  old_ioreads = perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_IOREADS);
5022  }
5023 
5024  switch (scan_id->type)
5025  {
5026  case S_HEAP_SCAN:
5028  status = scan_next_heap_scan (thread_p, scan_id);
5029  break;
5030 
5031  case S_HEAP_PAGE_SCAN:
5032  status = scan_next_heap_page_scan (thread_p, scan_id);
5033  break;
5034 
5035  case S_CLASS_ATTR_SCAN:
5036  status = scan_next_class_attr_scan (thread_p, scan_id);
5037  break;
5038 
5039  case S_INDX_SCAN:
5040  status = scan_next_index_scan (thread_p, scan_id);
5041  break;
5042 
5043  case S_INDX_KEY_INFO_SCAN:
5044  status = scan_next_index_key_info_scan (thread_p, scan_id);
5045  break;
5046 
5047  case S_INDX_NODE_INFO_SCAN:
5048  status = scan_next_index_node_info_scan (thread_p, scan_id);
5049  break;
5050 
5051  case S_LIST_SCAN:
5053  {
5054  status = scan_next_hash_list_scan (thread_p, scan_id);
5055  }
5056  else
5057  {
5058  status = scan_next_list_scan (thread_p, scan_id);
5059  }
5060  break;
5061 
5062  case S_SHOWSTMT_SCAN:
5063  status = scan_next_showstmt_scan (thread_p, scan_id);
5064  break;
5065 
5066  case S_VALUES_SCAN:
5067  status = scan_next_value_scan (thread_p, scan_id);
5068  break;
5069 
5070  case S_SET_SCAN:
5071  status = scan_next_set_scan (thread_p, scan_id);
5072  break;
5073 
5074  case S_JSON_TABLE_SCAN:
5075  status = scan_next_json_table_scan (thread_p, scan_id);
5076  break;
5077 
5078  case S_METHOD_SCAN:
5079  status = scan_next_method_scan (thread_p, scan_id);
5080  break;
5081 
5082  default:
5084  return S_ERROR;
5085  }
5086 
5087  if (on_trace)
5088  {
5089  tsc_getticks (&end_tick);
5090  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
5091  TSC_ADD_TIMEVAL (scan_id->scan_stats.elapsed_scan, tv_diff);
5092 
5093  scan_id->scan_stats.num_fetches += perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_FETCHES) - old_fetches;
5094  scan_id->scan_stats.num_ioreads += perfmon_get_from_statistic (thread_p, PSTAT_PB_NUM_IOREADS) - old_ioreads;
5095  }
5096 
5097  return status;
5098 }
5099 
5100 typedef enum
5101 {
5106 /*
5107  * scan_next_heap_scan () - The scan is moved to the next heap scan item.
5108  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
5109  * scan_id(in/out): Scan identifier
5110  *
5111  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
5112  */
5113 static SCAN_CODE
5115 {
5116  HEAP_SCAN_ID *hsidp;
5117  FILTER_INFO data_filter;
5119  SCAN_CODE sp_scan;
5120  DB_LOGICAL ev_res;
5121  OID current_oid, *p_current_oid = NULL;
5122  MVCC_SCAN_REEV_DATA mvcc_sel_reev_data;
5123  MVCC_REEV_DATA mvcc_reev_data;
5124  UPDDEL_MVCC_COND_REEVAL upd_reev;
5125  OID retry_oid;
5126  LOG_LSA ref_lsa;
5127  bool is_peeking;
5128  OBJECT_GET_STATUS object_get_status;
5130 
5131  hsidp = &scan_id->s.hsid;
5132  if (scan_id->mvcc_select_lock_needed)
5133  {
5134  p_current_oid = &current_oid;
5135  }
5136  else
5137  {
5138  p_current_oid = &hsidp->curr_oid;
5139  }
5140 
5141  /* set data filter information */
5142  scan_init_filter_info (&data_filter, &hsidp->scan_pred, &hsidp->pred_attrs, scan_id->val_list, scan_id->vd,
5143  &hsidp->cls_oid, 0, NULL, NULL, NULL);
5144 
5145  is_peeking = scan_id->fixed;
5146  if (scan_id->grouped)
5147  {
5148  is_peeking = PEEK;
5149  }
5150 
5151  if (data_filter.val_list)
5152  {
5153  for (p = data_filter.scan_pred->regu_list; p; p = p->next)
5154  {
5155  if (DB_NEED_CLEAR (p->value.vfetch_to))
5156  {
5157  pr_clear_value (p->value.vfetch_to);
5158  }
5159  }
5160  }
5161 
5162  while (1)
5163  {
5164  COPY_OID (&retry_oid, &hsidp->curr_oid);
5165  object_get_status = OBJ_GET_WITHOUT_LOCK;
5166 
5167  restart_scan_oid:
5168 
5169  /* get next object */
5170  if (scan_id->grouped)
5171  {
5172  /* grouped, fixed scan */
5173  sp_scan = heap_scanrange_next (thread_p, &hsidp->curr_oid, &recdes, &hsidp->scan_range, is_peeking);
5174  }
5175  else
5176  {
5177  recdes.data = NULL;
5178  if (scan_id->direction == S_FORWARD)
5179  {
5180  /* move forward */
5181  if (scan_id->type == S_HEAP_SCAN)
5182  {
5183  sp_scan =
5184  heap_next (thread_p, &hsidp->hfid, &hsidp->cls_oid, &hsidp->curr_oid, &recdes, &hsidp->scan_cache,
5185  is_peeking);
5186  }
5187  else
5188  {
5189  assert (scan_id->type == S_HEAP_SCAN_RECORD_INFO);
5190  sp_scan =
5191  heap_next_record_info (thread_p, &hsidp->hfid, &hsidp->cls_oid, &hsidp->curr_oid, &recdes,
5192  &hsidp->scan_cache, is_peeking, hsidp->cache_recordinfo);
5193  }
5194  }
5195  else
5196  {
5197  /* move backward */
5198  if (scan_id->type == S_HEAP_SCAN)
5199  {
5200  sp_scan =
5201  heap_prev (thread_p, &hsidp->hfid, &hsidp->cls_oid, &hsidp->curr_oid, &recdes, &hsidp->scan_cache,
5202  is_peeking);
5203  }
5204  else
5205  {
5206  assert (scan_id->type == S_HEAP_SCAN_RECORD_INFO);
5207  sp_scan =
5208  heap_prev_record_info (thread_p, &hsidp->hfid, &hsidp->cls_oid, &hsidp->curr_oid, &recdes,
5209  &hsidp->scan_cache, is_peeking, hsidp->cache_recordinfo);
5210  }
5211  }
5212  }
5213 
5214  if (sp_scan != S_SUCCESS)
5215  {
5216  /* scan error or end of scan */
5217  return (sp_scan == S_END) ? S_END : S_ERROR;
5218  }
5219 
5220  if (hsidp->scan_cache.page_watcher.pgptr != NULL)
5221  {
5222  LSA_COPY (&ref_lsa, pgbuf_get_lsa (hsidp->scan_cache.page_watcher.pgptr));
5223  }
5224 
5225  /* evaluate the predicates to see if the object qualifies */
5226  scan_id->scan_stats.read_rows++;
5227 
5228  ev_res = eval_data_filter (thread_p, p_current_oid, &recdes, &hsidp->scan_cache, &data_filter);
5229  if (ev_res == V_ERROR)
5230  {
5231  return S_ERROR;
5232  }
5233 
5234  if (is_peeking == PEEK && hsidp->scan_cache.page_watcher.pgptr != NULL
5235  && pgbuf_page_has_changed (hsidp->scan_cache.page_watcher.pgptr, &ref_lsa))
5236  {
5237  is_peeking = COPY;
5238  COPY_OID (&hsidp->curr_oid, &retry_oid);
5239  goto restart_scan_oid;
5240  }
5241 
5242  if (scan_id->qualification == QPROC_QUALIFIED)
5243  {
5244  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
5245  {
5246  continue; /* not qualified, continue to the next tuple */
5247  }
5248  }
5249  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
5250  {
5251  if (ev_res != V_FALSE) /* V_TRUE || V_UNKNOWN */
5252  {
5253  continue; /* qualified, continue to the next tuple */
5254  }
5255  }
5256  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
5257  {
5258  if (ev_res == V_TRUE)
5259  {
5260  scan_id->qualification = QPROC_QUALIFIED;
5261  }
5262  else if (ev_res == V_FALSE)
5263  {
5265  }
5266  else /* V_UNKNOWN */
5267  {
5268  /* nop */
5269  ;
5270  }
5271  }
5272  else
5273  { /* invalid value; the same as QPROC_QUALIFIED */
5274  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
5275  {
5276  continue; /* not qualified, continue to the next tuple */
5277  }
5278  }
5279 
5280  /* Data filter passed. If object should be locked and is not locked yet, lock it. */
5281 
5282  if (scan_id->mvcc_select_lock_needed)
5283  {
5284  /* data filter already initialized, don't have key or range init scan reevaluation structure */
5285  upd_reev.init (*scan_id);
5286  mvcc_sel_reev_data.set_filters (upd_reev);
5287  mvcc_sel_reev_data.qualification = &scan_id->qualification;
5288  mvcc_reev_data.set_scan_reevaluation (mvcc_sel_reev_data);
5289  COPY_OID (&current_oid, &hsidp->curr_oid);
5290  if (scan_id->fixed)
5291  {
5292  /* Reset recdes.data */
5293  recdes.data = NULL;
5294  }
5295 
5296  /* get with lock and reevaluate if the visible version wasn't the latest version */
5297  sp_scan =
5298  locator_lock_and_get_object_with_evaluation (thread_p, &current_oid, NULL, &recdes, &hsidp->scan_cache,
5299  is_peeking, NULL_CHN, &mvcc_reev_data, LOG_WARNING_IF_DELETED);
5300  if (sp_scan == S_SUCCESS && mvcc_reev_data.filter_result == V_FALSE)
5301  {
5302  continue;
5303  }
5304  else if (er_errid () == ER_HEAP_UNKNOWN_OBJECT || sp_scan == S_DOESNT_EXIST)
5305  {
5306  er_clear ();
5307  continue;
5308  }
5309  else if (sp_scan != S_SUCCESS)
5310  {
5311  return S_ERROR;
5312  }
5313  }
5314 
5315  if (mvcc_is_mvcc_disabled_class (&hsidp->cls_oid))
5316  {
5317  LOCK lock = NULL_LOCK;
5318  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5319  TRAN_ISOLATION tran_isolation = logtb_find_isolation (tran_index);
5320 
5321  if (scan_id->scan_op_type == S_DELETE || scan_id->scan_op_type == S_UPDATE)
5322  {
5323  lock = X_LOCK;
5324  }
5325  else if (oid_is_serial (&hsidp->cls_oid))
5326  {
5327  /* S_SELECT is currently handled only for serial, but may be extended to the other non-MVCC classes
5328  * if needed */
5329  lock = S_LOCK;
5330  }
5331 
5332  if (lock != NULL_LOCK && hsidp->scan_cache.page_watcher.pgptr != NULL)
5333  {
5334  if (tran_isolation == TRAN_READ_COMMITTED && lock == S_LOCK)
5335  {
5336  if (lock_hold_object_instant (thread_p, &hsidp->curr_oid, &hsidp->cls_oid, lock) == LK_GRANTED)
5337  {
5338  lock = NULL_LOCK;
5339  /* object_need_rescan needs to be kept false (page is still fixed, no other transaction could
5340  * have change it) */
5341  }
5342  }
5343  else
5344  {
5345  if (lock_object (thread_p, &hsidp->curr_oid, &hsidp->cls_oid, lock, LK_COND_LOCK) == LK_GRANTED)
5346  {
5347  /* successfully locked */
5348  lock = NULL_LOCK;
5349  /* object_need_rescan needs to be kept false (page is still fixed, no other transaction could
5350  * have change it) */
5351  }
5352  }
5353  }
5354 
5355  if (lock != NULL_LOCK)
5356  {
5357  VPID curr_vpid;
5358 
5359  VPID_SET_NULL (&curr_vpid);
5360 
5361  if (hsidp->scan_cache.page_watcher.pgptr != NULL)
5362  {
5363  pgbuf_get_vpid (hsidp->scan_cache.page_watcher.pgptr, &curr_vpid);
5364  pgbuf_ordered_unfix (thread_p, &hsidp->scan_cache.page_watcher);
5365  }
5366 #if defined (SERVER_MODE)
5367  else
5368  {
5369  if (object_get_status == OBJ_GET_WITHOUT_LOCK)
5370  {
5371  /* page not fixed, recdes was read without lock, object may have changed */
5372  object_get_status = OBJ_REPEAT_GET_WITH_LOCK;
5373  }
5374  else if (object_get_status == OBJ_REPEAT_GET_WITH_LOCK)
5375  {
5376  /* already read with lock, set flag to continue scanning next object */
5377  object_get_status = OBJ_GET_WITH_LOCK_COMPLETE;
5378  }
5379  }
5380 #endif
5381 
5382  if (lock_object (thread_p, &hsidp->curr_oid, &hsidp->cls_oid, lock, LK_UNCOND_LOCK) != LK_GRANTED)
5383  {
5384  return S_ERROR;
5385  }
5386 
5387  if (!heap_does_exist (thread_p, NULL, &hsidp->curr_oid))
5388  {
5389  /* not qualified, continue to the next tuple */
5390  lock_unlock_object_donot_move_to_non2pl (thread_p, &hsidp->curr_oid, &hsidp->cls_oid, lock);
5391  continue;
5392  }
5393 
5394  if (tran_isolation == TRAN_READ_COMMITTED && lock == S_LOCK)
5395  {
5396  /* release acquired lock in RC */
5397  lock_unlock_object_donot_move_to_non2pl (thread_p, &hsidp->curr_oid, &hsidp->cls_oid, lock);
5398  }
5399 
5400  assert (hsidp->scan_cache.page_watcher.pgptr == NULL);
5401 
5402  if (!VPID_ISNULL (&curr_vpid)
5403  && pgbuf_ordered_fix (thread_p, &curr_vpid, OLD_PAGE, PGBUF_LATCH_READ,
5404  &hsidp->scan_cache.page_watcher) != NO_ERROR)
5405  {
5406  return S_ERROR;
5407  }
5408 
5409  if (object_get_status == OBJ_REPEAT_GET_WITH_LOCK
5410  || (hsidp->scan_cache.page_watcher.pgptr != NULL
5411  && pgbuf_page_has_changed (hsidp->scan_cache.page_watcher.pgptr, &ref_lsa)))
5412  {
5413  is_peeking = COPY;
5414  COPY_OID (&hsidp->curr_oid, &retry_oid);
5415  goto restart_scan_oid;
5416  }
5417  }
5418  }
5419 
5420 
5421  scan_id->scan_stats.qualified_rows++;
5422 
5423  if (hsidp->rest_regu_list)
5424  {
5425  /* read the rest of the values from the heap into the attribute cache */
5426  if (heap_attrinfo_read_dbvalues (thread_p, p_current_oid, &recdes, &hsidp->scan_cache,
5427  hsidp->rest_attrs.attr_cache) != NO_ERROR)
5428  {
5429  return S_ERROR;
5430  }
5431 
5432  if (is_peeking == PEEK && hsidp->scan_cache.page_watcher.pgptr != NULL
5433  && pgbuf_page_has_changed (hsidp->scan_cache.page_watcher.pgptr, &ref_lsa))
5434  {
5435  is_peeking = COPY;
5436  COPY_OID (&hsidp->curr_oid, &retry_oid);
5437  goto restart_scan_oid;
5438  }
5439 
5440  /* fetch the rest of the values from the object instance */
5441  if (scan_id->val_list)
5442  {
5443  if (fetch_val_list (thread_p, hsidp->rest_regu_list, scan_id->vd, &hsidp->cls_oid, p_current_oid, NULL,
5444  PEEK) != NO_ERROR)
5445  {
5446  return S_ERROR;
5447  }
5448 
5449  if (is_peeking != 0 && hsidp->scan_cache.page_watcher.pgptr != NULL
5450  && pgbuf_page_has_changed (hsidp->scan_cache.page_watcher.pgptr, &ref_lsa))
5451  {
5452  is_peeking = COPY;
5453  COPY_OID (&hsidp->curr_oid, &retry_oid);
5454  goto restart_scan_oid;
5455  }
5456  }
5457  }
5458 
5459  if (hsidp->recordinfo_regu_list != NULL)
5460  {
5461  /* fetch the record info values */
5462  if (scan_id->val_list)
5463  {
5464  if (fetch_val_list (thread_p, hsidp->recordinfo_regu_list, scan_id->vd, &hsidp->cls_oid, p_current_oid,
5465  NULL, PEEK) != NO_ERROR)
5466  {
5467  return S_ERROR;
5468  }
5469 
5470  if (is_peeking == PEEK && hsidp->scan_cache.page_watcher.pgptr != NULL
5471  && pgbuf_page_has_changed (hsidp->scan_cache.page_watcher.pgptr, &ref_lsa))
5472  {
5473  is_peeking = COPY;
5474  COPY_OID (&hsidp->curr_oid, &retry_oid);
5475  goto restart_scan_oid;
5476  }
5477  }
5478  }
5479 
5480  return S_SUCCESS;
5481  }
5482 }
5483 
5484 /*
5485  * scan_next_heap_page_scan () - The scan is moved to the next page.
5486  *
5487  * return : Error code.
5488  * thread_p (in) : Thread entry.
5489  * scan_id (in) : Scan data.
5490  */
5491 static SCAN_CODE
5493 {
5494  HEAP_PAGE_SCAN_ID *hpsidp = NULL;
5495  FILTER_INFO data_filter;
5496  SCAN_CODE sp_scan;
5497  DB_LOGICAL ev_res;
5498 
5499  hpsidp = &scan_id->s.hpsid;
5500 
5501  scan_init_filter_info (&data_filter, &hpsidp->scan_pred, NULL, scan_id->val_list, scan_id->vd, &hpsidp->cls_oid, 0,
5502  NULL, NULL, NULL);
5503 
5504  while (true)
5505  {
5506  if (scan_id->direction == S_FORWARD)
5507  {
5508  /* move forward */
5509  sp_scan = heap_page_next (thread_p, &hpsidp->cls_oid, &hpsidp->hfid, &hpsidp->curr_vpid,
5510  hpsidp->cache_page_info);
5511  }
5512  else
5513  {
5514  /* move backward */
5515  sp_scan = heap_page_prev (thread_p, &hpsidp->cls_oid, &hpsidp->hfid, &hpsidp->curr_vpid,
5516  hpsidp->cache_page_info);
5517  }
5518 
5519  if (sp_scan != S_SUCCESS)
5520  {
5521  return (sp_scan == S_END) ? S_END : S_ERROR;
5522  }
5523 
5524  /* evaluate filter to see if the page qualifies */
5525  ev_res = eval_data_filter (thread_p, &hpsidp->cls_oid, NULL, NULL, &data_filter);
5526 
5527  if (ev_res == V_ERROR)
5528  {
5529  return S_ERROR;
5530  }
5531  else if (ev_res != V_TRUE)
5532  {
5533  /* V_FALSE || V_UNKNOWN */
5534  continue;
5535  }
5536 
5537  if (hpsidp->page_info_regu_list != NULL)
5538  {
5539  /* fetch the page info values */
5540  if (scan_id->val_list)
5541  {
5542  if (fetch_val_list (thread_p, hpsidp->page_info_regu_list, scan_id->vd, &hpsidp->cls_oid, NULL, NULL,
5543  PEEK) != NO_ERROR)
5544  {
5545  return S_ERROR;
5546  }
5547  }
5548  }
5549 
5550  return S_SUCCESS;
5551  }
5552 }
5553 
5554 /*
5555  * scan_next_class_attr_scan () - The scan is moved to the next class attribute scan item.
5556  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
5557  * scan_id(in/out): Scan identifier
5558  *
5559  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
5560  */
5561 static SCAN_CODE
5563 {
5564  HEAP_SCAN_ID *hsidp;
5565  FILTER_INFO data_filter;
5566  DB_LOGICAL ev_res;
5567 
5568  hsidp = &scan_id->s.hsid;
5569 
5570  /* set data filter information */
5571  scan_init_filter_info (&data_filter, &hsidp->scan_pred, &hsidp->pred_attrs, scan_id->val_list, scan_id->vd,
5572  &hsidp->cls_oid, 0, NULL, NULL, NULL);
5573 
5574  if (scan_id->position == S_BEFORE)
5575  {
5576  /* Class attribute scans are always single row scan. */
5577  scan_id->position = S_AFTER;
5578 
5579  /* evaluate the predicates to see if the object qualifies */
5580  ev_res = eval_data_filter (thread_p, NULL, NULL, NULL, &data_filter);
5581  if (ev_res == V_ERROR)
5582  {
5583  return S_ERROR;
5584  }
5585 
5586  if (scan_id->qualification == QPROC_QUALIFIED)
5587  {
5588  if (ev_res != V_TRUE)
5589  { /* V_FALSE || V_UNKNOWN */
5590  return S_END; /* not qualified */
5591  }
5592  }
5593  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
5594  {
5595  if (ev_res != V_FALSE)
5596  { /* V_TRUE || V_UNKNOWN */
5597  return S_END; /* qualified */
5598  }
5599  }
5600  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
5601  {
5602  if (ev_res == V_TRUE)
5603  {
5604  scan_id->qualification = QPROC_QUALIFIED;
5605  }
5606  else if (ev_res == V_FALSE)
5607  {
5609  }
5610  else /* V_UNKNOWN */
5611  {
5612  /* nop */
5613  ;
5614  }
5615  }
5616  else
5617  { /* invalid value; the same as QPROC_QUALIFIED */
5618  if (ev_res != V_TRUE)
5619  { /* V_FALSE || V_UNKNOWN */
5620  return S_END; /* not qualified */
5621  }
5622  }
5623 
5624  if (hsidp->rest_regu_list)
5625  {
5626  /* read the rest of the values from the heap into the attribute cache */
5628  {
5629  return S_ERROR;
5630  }
5631 
5632  /* fetch the rest of the values from the object instance */
5633  if (scan_id->val_list)
5634  {
5635  if (fetch_val_list (thread_p, hsidp->rest_regu_list, scan_id->vd, &hsidp->cls_oid, NULL, NULL, PEEK) !=
5636  NO_ERROR)
5637  {
5638  return S_ERROR;
5639  }
5640  }
5641  }
5642 
5643  return S_SUCCESS;
5644  }
5645  else
5646  {
5647  /* Class attribute scans are always single row scan. */
5648  return S_END;
5649  }
5650 }
5651 
5652 /*
5653  * scan_next_index_scan () - The scan is moved to the next index scan item.
5654  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
5655  * scan_id(in/out): Scan identifier
5656  *
5657  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
5658  */
5659 static SCAN_CODE
5661 {
5662  INDX_SCAN_ID *isidp;
5663  FILTER_INFO data_filter;
5664  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
5665  SCAN_CODE lookup_status;
5666  TRAN_ISOLATION isolation;
5667 
5668  TSC_TICKS start_tick, end_tick;
5669  TSCTIMEVAL tv_diff;
5670 
5671  isidp = &scan_id->s.isid;
5672 
5673  assert (!OID_ISNULL (&isidp->cls_oid));
5674 
5675  /* multi range optimization safe guard : fall-back to normal output (OID list or covering index instead of "on the
5676  * fly" lists), if sorting column is not yet set at this stage; also 'grouped' is not supported */
5677  if (isidp->multi_range_opt.use && (isidp->multi_range_opt.sort_att_idx == NULL || scan_id->grouped))
5678  {
5679  isidp->multi_range_opt.use = false;
5680  scan_id->scan_stats.multi_range_opt = false;
5681  }
5682 
5683  /* set data filter information */
5684  scan_init_filter_info (&data_filter, &isidp->scan_pred, &isidp->pred_attrs, scan_id->val_list, scan_id->vd,
5685  &isidp->cls_oid, 0, NULL, NULL, NULL);
5686 
5687  /* Due to the length of time that we hold onto the oid list, it is possible at lower isolation levels (UNCOMMITTED
5688  * INSTANCES) that the index/heap may have changed since the oid list was read from the btree. In particular, some
5689  * of the instances that we are reading may have been deleted by the time we go to fetch them via heap_get_visible_version ().
5690  * According to the semantics of UNCOMMITTED, it is ok if they are deleted out from under us and we can ignore the
5691  * SCAN_DOESNT_EXIST error. */
5692 
5693  isolation = logtb_find_current_isolation (thread_p);
5694 
5695  while (1)
5696  {
5697  /* get next object from OID list */
5698  if (scan_id->grouped)
5699  {
5700  assert (isidp->oid_list != NULL);
5701  /* grouped scan */
5702  if (scan_id->direction == S_FORWARD)
5703  {
5704  /* move forward (to the next object) */
5705  if (isidp->curr_oidno == -1)
5706  {
5707  isidp->curr_oidno = 0; /* first oid number */
5708  isidp->curr_oidp = isidp->oid_list->oidp;
5709  }
5710  else if (isidp->curr_oidno < isidp->oids_count - 1)
5711  {
5712  isidp->curr_oidno++;
5713  isidp->curr_oidp++;
5714  }
5715  else
5716  {
5717  return S_END;
5718  }
5719  }
5720  else
5721  {
5722  /* move backward (to the previous object */
5723  if (isidp->curr_oidno == isidp->oids_count)
5724  {
5725  isidp->curr_oidno = isidp->oids_count - 1;
5726  isidp->curr_oidp = GET_NTH_OID (isidp->oid_list->oidp, isidp->curr_oidno);
5727  }
5728  else if (isidp->curr_oidno > 0)
5729  {
5730  isidp->curr_oidno--;
5731  isidp->curr_oidp = GET_NTH_OID (isidp->oid_list->oidp, isidp->curr_oidno);
5732  }
5733  else
5734  {
5735  return S_END;
5736  }
5737  }
5738  }
5739  else
5740  {
5741  /* non-grouped, regular index scan */
5742  if (scan_id->position == S_BEFORE)
5743  {
5744  SCAN_CODE ret;
5745 
5746  /* Either we are not using ISS, or we are using it, and in this case, we are supposed to be here for the
5747  * first time */
5748  assert_release (!isidp->iss.use || isidp->iss.current_op == ISS_OP_NONE);
5749 
5750  ret = call_get_next_index_oidset (thread_p, scan_id, isidp, true);
5751  if (ret != S_SUCCESS)
5752  {
5753  return ret;
5754  }
5755 
5756  if (isidp->need_count_only == true)
5757  {
5758  /* no more scan is needed. just return */
5759  return S_SUCCESS;
5760  }
5761 
5762  scan_id->position = S_ON;
5763  isidp->curr_oidno = 0; /* first oid number */
5764 
5765  if (SCAN_IS_INDEX_COVERED (isidp))
5766  {
5767  qfile_close_list (thread_p, isidp->indx_cov.list_id);
5768  if (qfile_open_list_scan (isidp->indx_cov.list_id, isidp->indx_cov.lsid) != NO_ERROR)
5769  {
5770  return S_ERROR;
5771  }
5772  }
5773  else
5774  {
5775  if (isidp->multi_range_opt.use)
5776  {
5777  assert (isidp->curr_oidno < isidp->multi_range_opt.cnt);
5778  assert (isidp->multi_range_opt.top_n_items[isidp->curr_oidno] != NULL);
5779 
5780  isidp->curr_oidp = &(isidp->multi_range_opt.top_n_items[isidp->curr_oidno]->inst_oid);
5781  }
5782  else
5783  {
5784  assert (isidp->oid_list != NULL);
5785  isidp->curr_oidp = GET_NTH_OID (isidp->oid_list->oidp, isidp->curr_oidno);
5786  }
5787  assert (HEAP_ISVALID_OID (thread_p, isidp->curr_oidp) != DISK_INVALID);
5788  }
5789  }
5790  else if (scan_id->position == S_ON)
5791  {
5792  int oids_cnt;
5793  /* we are in the S_ON case */
5794 
5795  oids_cnt = isidp->multi_range_opt.use ? isidp->multi_range_opt.cnt : isidp->oids_count;
5796 
5797  /* if there are OIDs left */
5798  if (isidp->curr_oidno < oids_cnt - 1)
5799  {
5800  isidp->curr_oidno++;
5801  if (!SCAN_IS_INDEX_COVERED (isidp))
5802  {
5803  if (isidp->multi_range_opt.use)
5804  {
5805  assert (isidp->curr_oidno < isidp->multi_range_opt.cnt);
5806  assert (isidp->multi_range_opt.top_n_items[isidp->curr_oidno] != NULL);
5807 
5808  isidp->curr_oidp = &(isidp->multi_range_opt.top_n_items[isidp->curr_oidno]->inst_oid);
5809  }
5810  else
5811  {
5812  assert (isidp->oid_list != NULL);
5813  isidp->curr_oidp = GET_NTH_OID (isidp->oid_list->oidp, isidp->curr_oidno);
5814  }
5815  assert (HEAP_ISVALID_OID (thread_p, isidp->curr_oidp) != DISK_INVALID);
5816  }
5817  else
5818  {
5819  /* TODO: Index covering case keeps OID's in isidp->indx_cov.list_id and not in isidp->oid_list.
5820  * Fall through. */
5821  }
5822  }
5823  else
5824  {
5825  /* there are no more OIDs left. Decide what to do */
5826 
5827  /* We can ignore the END OF SCAN signal if we're certain there can be more results, for instance if
5828  * we have a multiple range scan, or if we have the "index skip scan" optimization on */
5829  if (BTREE_END_OF_SCAN (&isidp->bt_scan) && isidp->indx_info->range_type != R_RANGELIST
5830  && isidp->indx_info->range_type != R_KEYLIST && !isidp->iss.use)
5831  {
5832  return S_END;
5833  }
5834  else
5835  {
5836  SCAN_CODE ret;
5837  bool go_to_next_iss_value;
5838 
5839  /* a list in a range is exhausted */
5840  if (isidp->multi_range_opt.use)
5841  {
5842  /* for "on the fly" case (multi range opt), all ranges are exhausted from first shoot, force
5843  * exit */
5844  isidp->oids_count = 0;
5845  return S_END;
5846  }
5847 
5848  if (SCAN_IS_INDEX_COVERED (isidp))
5849  {
5850  /* close current list and start a new one */
5851  qfile_close_scan (thread_p, isidp->indx_cov.lsid);
5852  qfile_destroy_list (thread_p, isidp->indx_cov.list_id);
5854  isidp->indx_cov.list_id =
5855  qfile_open_list (thread_p, isidp->indx_cov.type_list, NULL, isidp->indx_cov.query_id, 0);
5856  if (isidp->indx_cov.list_id == NULL)
5857  {
5858  return S_ERROR;
5859  }
5860  }
5861  /* if this the current scan is not done (i.e. the buffer was full and we need to fetch more rows,
5862  * do not go to the next value */
5863  go_to_next_iss_value = BTREE_END_OF_SCAN (&isidp->bt_scan)
5864  && (isidp->indx_info->range_type == R_KEY || isidp->indx_info->range_type == R_RANGE);
5865  ret = call_get_next_index_oidset (thread_p, scan_id, isidp, go_to_next_iss_value);
5866  if (ret != S_SUCCESS)
5867  {
5868  return ret;
5869  }
5870 
5871  if (isidp->need_count_only == true)
5872  {
5873  /* no more scan is needed. just return */
5874  return S_SUCCESS;
5875  }
5876 
5877  isidp->curr_oidno = 0; /* first oid number */
5878  if (SCAN_IS_INDEX_COVERED (isidp))
5879  {
5880  qfile_close_list (thread_p, isidp->indx_cov.list_id);
5881  if (qfile_open_list_scan (isidp->indx_cov.list_id, isidp->indx_cov.lsid) != NO_ERROR)
5882  {
5883  return S_ERROR;
5884  }
5885  }
5886  else
5887  {
5888  assert (isidp->oid_list != NULL);
5889  isidp->curr_oidp = isidp->oid_list->oidp;
5890  assert (HEAP_ISVALID_OID (thread_p, isidp->curr_oidp) != DISK_INVALID);
5891  }
5892  }
5893  }
5894  }
5895  else if (scan_id->position == S_AFTER)
5896  {
5897  return S_END;
5898  }
5899  else
5900  {
5902  return S_ERROR;
5903  }
5904  }
5905 
5906  assert (scan_id->position == S_ON);
5907 
5908  scan_id->scan_stats.key_qualified_rows++;
5909 
5910  /* get pages for read */
5911  if (!SCAN_IS_INDEX_COVERED (isidp))
5912  {
5914 
5915  assert (isidp->curr_oidno >= 0);
5916  assert (isidp->curr_oidp != NULL);
5917  assert (HEAP_ISVALID_OID (thread_p, isidp->curr_oidp) != DISK_INVALID);
5918 
5919  if (thread_is_on_trace (thread_p))
5920  {
5921  tsc_getticks (&start_tick);
5922  }
5923 
5924  lookup_status = scan_next_index_lookup_heap (thread_p, scan_id, isidp, &data_filter, isolation);
5925 
5926  if (thread_is_on_trace (thread_p))
5927  {
5928  tsc_getticks (&end_tick);
5929  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
5930  TSC_ADD_TIMEVAL (scan_id->scan_stats.elapsed_lookup, tv_diff);
5931  }
5932 
5933  if (lookup_status == S_SUCCESS)
5934  {
5935  scan_id->scan_stats.data_qualified_rows++;
5936  }
5937  else if (lookup_status == S_DOESNT_EXIST)
5938  {
5939  if (scan_id->mvcc_select_lock_needed && isidp->key_limit_upper != -1)
5940  {
5941  isidp->key_limit_upper++;
5942  }
5943  /* not qualified, continue to the next tuple */
5944  continue;
5945  }
5946  else
5947  {
5948  /* S_ERROR, S_END */
5949  return lookup_status;
5950  }
5951  }
5952  else
5953  {
5954  /* TO DO - in MVCC when mvcc_select_lock_needed is true index coverage must be disabled */
5955  if (isidp->multi_range_opt.use)
5956  {
5957  assert (isidp->curr_oidno < isidp->multi_range_opt.cnt);
5958  assert (isidp->multi_range_opt.top_n_items[isidp->curr_oidno] != NULL);
5959 
5960  if (scan_dump_key_into_tuple (thread_p, isidp,
5962  isidp->curr_oidp, &isidp->multi_range_opt.tplrec) != NO_ERROR)
5963  {
5964  return S_ERROR;
5965  }
5966  tplrec.tpl = isidp->multi_range_opt.tplrec.tpl;
5967  tplrec.size = isidp->multi_range_opt.tplrec.size;
5968  }
5969  else
5970  {
5971  if (qfile_scan_list_next (thread_p, isidp->indx_cov.lsid, &tplrec, PEEK) != S_SUCCESS)
5972  {
5973  return S_ERROR;
5974  }
5975  }
5976 
5978 
5979  if (scan_id->val_list)
5980  {
5981  if (fetch_val_list (thread_p, isidp->indx_cov.regu_val_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
5982  NO_ERROR)
5983  {
5984  return S_ERROR;
5985  }
5986  }
5987  }
5988 
5989  return S_SUCCESS;
5990  }
5991 }
5992 
5993 /*
5994  * scan_next_index_lookup_heap () - fetch heap record and evaluate data filter
5995  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR, S_DOESNT_EXIST)
5996  * scan_id(in/out): Scan identifier
5997  * isidp(in/out): Index scan identifier
5998  * data_filter(in): data filter information
5999  * isolation(in): transaction isolation level
6000  *
6001  * Note: If the tuple is not qualified for data filter, S_DOESNT_EXIST is returned.
6002  */
6003 static SCAN_CODE
6005  FILTER_INFO * data_filter, TRAN_ISOLATION isolation)
6006 {
6007  SCAN_CODE sp_scan;
6008  DB_LOGICAL ev_res;
6010  indx_info *indx_infop;
6011  BTID *btid;
6012  char *indx_name_p;
6013  char *class_name_p;
6014  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
6015 
6016  assert (scan_id != NULL);
6017  assert (isidp != NULL);
6018  assert (isidp->curr_oidp != NULL && !OID_ISNULL (isidp->curr_oidp));
6019 
6020  if (scan_id->fixed == false)
6021  {
6022  recdes.data = NULL;
6023  }
6024 
6025  sp_scan = heap_get_visible_version (thread_p, isidp->curr_oidp, NULL, &recdes, &isidp->scan_cache, scan_id->fixed,
6026  NULL_CHN);
6027  if (sp_scan == S_SNAPSHOT_NOT_SATISFIED)
6028  {
6029  if (SCAN_IS_INDEX_COVERED (isidp))
6030  {
6031  /* goto the next tuple */
6032  if (!isidp->multi_range_opt.use)
6033  {
6034  if (qfile_scan_list_next (thread_p, isidp->indx_cov.lsid, &tplrec, PEEK) != S_SUCCESS)
6035  {
6036  return S_ERROR;
6037  }
6038  }
6039  }
6040 
6041  return S_DOESNT_EXIST; /* not qualified, continue to the next tuple */
6042  }
6043  else if (sp_scan == S_ERROR)
6044  {
6045  ASSERT_ERROR ();
6046  return sp_scan;
6047  }
6048  else
6049  {
6050  assert (sp_scan == S_SUCCESS || sp_scan == S_SUCCESS_CHN_UPTODATE);
6051  }
6052 
6053  /* evaluate the predicates to see if the object qualifies */
6054  ev_res = eval_data_filter (thread_p, isidp->curr_oidp, &recdes, &isidp->scan_cache, data_filter);
6055 
6056  // no key filter evaluation is required here.
6057 
6058  ev_res = update_logical_result (thread_p, ev_res, (int *) &scan_id->qualification);
6059  if (ev_res == V_ERROR)
6060  {
6061  return S_ERROR;
6062  }
6063  else if (ev_res != V_TRUE)
6064  {
6065  return S_DOESNT_EXIST;
6066  }
6067 
6068  if (scan_id->mvcc_select_lock_needed)
6069  {
6070  UPDDEL_MVCC_COND_REEVAL upd_reev;
6071  MVCC_SCAN_REEV_DATA mvcc_sel_reev_data;
6072  MVCC_REEV_DATA mvcc_reev_data;
6073 
6074  upd_reev.init (*scan_id);
6075  mvcc_sel_reev_data.set_filters (upd_reev);
6076  mvcc_sel_reev_data.qualification = &scan_id->qualification;
6077  mvcc_reev_data.set_scan_reevaluation (mvcc_sel_reev_data);
6078 
6079  sp_scan = locator_lock_and_get_object_with_evaluation (thread_p, isidp->curr_oidp, NULL, &recdes,
6080  &isidp->scan_cache, scan_id->fixed, NULL_CHN,
6081  &mvcc_reev_data, LOG_WARNING_IF_DELETED);
6082  if (sp_scan == S_SUCCESS)
6083  {
6084  switch (mvcc_reev_data.filter_result)
6085  {
6086  case V_ERROR:
6087  return S_ERROR;
6088  case V_FALSE:
6089  return S_DOESNT_EXIST;
6090  default:
6091  break;
6092  }
6093  }
6094  }
6095 
6096  if (sp_scan == S_DOESNT_EXIST || er_errid () == ER_HEAP_UNKNOWN_OBJECT)
6097  {
6098  er_clear ();
6099  if (SCAN_IS_INDEX_COVERED (isidp))
6100  {
6101  /* goto the next tuple */
6102  if (!isidp->multi_range_opt.use)
6103  {
6104  if (qfile_scan_list_next (thread_p, isidp->indx_cov.lsid, &tplrec, PEEK) != S_SUCCESS)
6105  {
6106  return S_ERROR;
6107  }
6108  }
6109  }
6110 
6111  return S_DOESNT_EXIST; /* not qualified, continue to the next tuple */
6112  }
6113 
6114  if (sp_scan != S_SUCCESS && sp_scan != S_SNAPSHOT_NOT_SATISFIED)
6115  {
6116  /* check end of scan */
6117  if (sp_scan == S_END)
6118  {
6119  assert (false); /* is impossible case */
6120  return S_END;
6121  }
6122 
6123  indx_infop = isidp->indx_info;
6124  btid = &indx_infop->btid;
6125  indx_name_p = NULL;
6126  class_name_p = NULL;
6127 
6128  /* check scan error */
6129  if (er_errid () == NO_ERROR)
6130  {
6131  (void) heap_get_indexinfo_of_btid (thread_p, &isidp->cls_oid, btid, NULL, NULL, NULL, NULL, &indx_name_p,
6132  NULL);
6133 
6134  if (heap_get_class_name (thread_p, &isidp->cls_oid, &class_name_p) != NO_ERROR)
6135  {
6136  /* ignore */
6137  er_clear ();
6138  }
6139 
6141  (indx_name_p) ? indx_name_p : "*UNKNOWN-INDEX*", (class_name_p) ? class_name_p : "*UNKNOWN-CLASS*",
6142  isidp->cls_oid.volid, isidp->cls_oid.pageid, isidp->cls_oid.slotid, isidp->curr_oidp->volid,
6143  isidp->curr_oidp->pageid, isidp->curr_oidp->slotid, btid->vfid.volid, btid->vfid.fileid,
6144  btid->root_pageid);
6145 
6146  if (class_name_p)
6147  {
6148  free_and_init (class_name_p);
6149  }
6150 
6151  if (indx_name_p)
6152  {
6153  free_and_init (indx_name_p);
6154  }
6155  }
6156 
6157  return S_ERROR;
6158  }
6159 
6160  if (!scan_id->mvcc_select_lock_needed && mvcc_is_mvcc_disabled_class (&isidp->cls_oid))
6161  {
6162  /* Data filter passed. If object should be locked and is not locked yet, lock it. */
6163  LOCK lock = NULL_LOCK;
6164  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
6165  TRAN_ISOLATION tran_isolation = logtb_find_isolation (tran_index);
6166 
6167  if (scan_id->scan_op_type == S_DELETE || scan_id->scan_op_type == S_UPDATE)
6168  {
6169  lock = X_LOCK;
6170  }
6171  else if (oid_is_serial (&isidp->cls_oid))
6172  {
6173  /* S_SELECT is currently handled only for serial, but may be extended to the other non-MVCC classes if
6174  * needed */
6175  lock = S_LOCK;
6176  }
6177 
6178  if (lock != NULL_LOCK)
6179  {
6180  if (tran_isolation == TRAN_READ_COMMITTED && lock == S_LOCK)
6181  {
6182  if (lock_hold_object_instant (thread_p, isidp->curr_oidp, &isidp->cls_oid, lock) == LK_GRANTED)
6183  {
6184  lock = NULL_LOCK;
6185  }
6186  }
6187  else
6188  {
6189  if (lock_object (thread_p, isidp->curr_oidp, &isidp->cls_oid, lock, LK_COND_LOCK) == LK_GRANTED)
6190  {
6191  /* successfully locked */
6192  lock = NULL_LOCK;
6193  }
6194  }
6195  }
6196 
6197  if (lock != NULL_LOCK)
6198  {
6199  if (isidp->scan_cache.page_watcher.pgptr != NULL)
6200  {
6201  pgbuf_ordered_unfix (thread_p, &isidp->scan_cache.page_watcher);
6202  }
6203 
6204  if (lock_object (thread_p, isidp->curr_oidp, &isidp->cls_oid, lock, LK_UNCOND_LOCK) != LK_GRANTED)
6205  {
6206  return S_ERROR;
6207  }
6208 
6209  if (!heap_does_exist (thread_p, NULL, isidp->curr_oidp))
6210  {
6211  /* not qualified, continue to the next tuple */
6212  lock_unlock_object_donot_move_to_non2pl (thread_p, isidp->curr_oidp, &isidp->cls_oid, lock);
6213  return S_DOESNT_EXIST;
6214  }
6215 
6216  if (tran_isolation == TRAN_READ_COMMITTED && lock == S_LOCK)
6217  {
6218  /* release acquired lock in RC */
6219  lock_unlock_object_donot_move_to_non2pl (thread_p, isidp->curr_oidp, &isidp->cls_oid, lock);
6220  }
6221  }
6222  }
6223 
6224  if (isidp->rest_regu_list)
6225  {
6226  /* read the rest of the values from the heap into the attribute cache */
6227  if (heap_attrinfo_read_dbvalues (thread_p, isidp->curr_oidp, &recdes, &isidp->scan_cache,
6228  isidp->rest_attrs.attr_cache) != NO_ERROR)
6229  {
6230  return S_ERROR;
6231  }
6232 
6233  /* fetch the rest of the values from the object instance */
6234  if (scan_id->val_list)
6235  {
6236  if (fetch_val_list (thread_p, isidp->rest_regu_list, scan_id->vd, &isidp->cls_oid, isidp->curr_oidp, NULL,
6237  PEEK) != NO_ERROR)
6238  {
6239  return S_ERROR;
6240  }
6241  }
6242  }
6243 
6244  return S_SUCCESS;
6245 }
6246 
6247 /*
6248  * scan_next_index_key_info_scan () - Scans each key in index and obtains
6249  * information about that key.
6250  *
6251  * return : Scan code.
6252  * thread_p (in) : Thread entry.
6253  * scan_id (in) : Scan data.
6254  */
6255 static SCAN_CODE
6257 {
6258  INDX_SCAN_ID *isidp = NULL;
6259  FILTER_INFO data_filter;
6260  SCAN_CODE sp_scan;
6261  DB_LOGICAL ev_res;
6262 
6263  isidp = &scan_id->s.isid;
6264 
6265  scan_init_filter_info (&data_filter, &isidp->scan_pred, NULL, scan_id->val_list, scan_id->vd, &isidp->cls_oid, 0,
6266  NULL, NULL, NULL);
6267 
6268  while (true)
6269  {
6270  sp_scan =
6271  btree_get_next_key_info (thread_p, &isidp->indx_info->btid, &isidp->bt_scan, 1, &isidp->cls_oid,
6272  isidp, isidp->key_info_values);
6273  if (sp_scan != S_SUCCESS)
6274  {
6275  return (sp_scan == S_END) ? S_END : S_ERROR;
6276  }
6277 
6278  ev_res = eval_data_filter (thread_p, NULL, NULL, NULL, &data_filter);
6279  if (ev_res == V_ERROR)
6280  {
6281  return S_ERROR;
6282  }
6283  else if (ev_res != V_TRUE)
6284  {
6285  /* V_FALSE || V_UNKNOWN */
6286  continue;
6287  }
6288 
6289  if (isidp->key_info_regu_list != NULL && scan_id->val_list != NULL)
6290  {
6291  if (fetch_val_list (thread_p, isidp->key_info_regu_list, scan_id->vd, &isidp->cls_oid, NULL, NULL, PEEK) !=
6292  NO_ERROR)
6293  {
6294  return S_ERROR;
6295  }
6296  }
6297 
6298  return S_SUCCESS;
6299  }
6300 }
6301 
6302 /*
6303  * scan_next_index_node_info_scan () - Scans for nodes in b-tree and obtains
6304  * information about the nodes.
6305  *
6306  * return : Scan code.
6307  * thread_p (in) : Thread entry.
6308  * scan_id (in) : Scan data.
6309  */
6310 static SCAN_CODE
6312 {
6313  INDEX_NODE_SCAN_ID *insidp = NULL;
6314  FILTER_INFO data_filter;
6315  SCAN_CODE sp_scan;
6316  DB_LOGICAL ev_res;
6317 
6318  insidp = &scan_id->s.insid;
6319 
6320  scan_init_filter_info (&data_filter, &insidp->scan_pred, NULL, scan_id->val_list, scan_id->vd, NULL, 0, NULL, NULL,
6321  NULL);
6322 
6323  while (true)
6324  {
6325  sp_scan = btree_get_next_node_info (thread_p, &insidp->indx_info->btid, &insidp->btns, insidp->node_info_values);
6326  if (sp_scan != S_SUCCESS)
6327  {
6328  return (sp_scan == S_END) ? S_END : S_ERROR;
6329  }
6330 
6331  ev_res = eval_data_filter (thread_p, NULL, NULL, NULL, &data_filter);
6332  if (ev_res == V_ERROR)
6333  {
6334  return S_ERROR;
6335  }
6336  else if (ev_res != V_TRUE)
6337  {
6338  /* V_FALSE || V_UNKNOWN */
6339  continue;
6340  }
6341 
6342  if (insidp->node_info_regu_list != NULL && scan_id->val_list != NULL)
6343  {
6344  if (fetch_val_list (thread_p, insidp->node_info_regu_list, scan_id->vd, NULL, NULL, NULL, PEEK) != NO_ERROR)
6345  {
6346  return S_ERROR;
6347  }
6348  }
6349 
6350  return S_SUCCESS;
6351  }
6352 }
6353 
6354 /*
6355  * scan_next_list_scan () - The scan is moved to the next list scan item.
6356  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6357  * scan_id(in/out): Scan identifier
6358  *
6359  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
6360  */
6361 static SCAN_CODE
6363 {
6364  LLIST_SCAN_ID *llsidp;
6365  SCAN_CODE qp_scan;
6366  DB_LOGICAL ev_res;
6367  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
6368 
6369  llsidp = &scan_id->s.llsid;
6370 
6371  tplrec.size = 0;
6372  tplrec.tpl = (QFILE_TUPLE) NULL;
6373 
6374  resolve_domains_on_list_scan (llsidp, scan_id->val_list);
6375 
6376  while ((qp_scan = qfile_scan_list_next (thread_p, &llsidp->lsid, &tplrec, PEEK)) == S_SUCCESS)
6377  {
6378 
6379  /* fetch the values for the predicate from the tuple */
6380  if (scan_id->val_list)
6381  {
6382  if (fetch_val_list (thread_p, llsidp->scan_pred.regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
6383  NO_ERROR)
6384  {
6385  return S_ERROR;
6386  }
6387  }
6388 
6389  scan_id->scan_stats.read_rows++;
6390 
6391  /* evaluate the predicate to see if the tuple qualifies */
6392  ev_res = V_TRUE;
6393  if (llsidp->scan_pred.pr_eval_fnc && llsidp->scan_pred.pred_expr)
6394  {
6395  ev_res = (*llsidp->scan_pred.pr_eval_fnc) (thread_p, llsidp->scan_pred.pred_expr, scan_id->vd, NULL);
6396  if (ev_res == V_ERROR)
6397  {
6398  return S_ERROR;
6399  }
6400  }
6401 
6402  if (scan_id->qualification == QPROC_QUALIFIED)
6403  {
6404  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
6405  {
6406  continue; /* not qualified, continue to the next tuple */
6407  }
6408  }
6409  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
6410  {
6411  if (ev_res != V_FALSE) /* V_TRUE || V_UNKNOWN */
6412  {
6413  continue; /* qualified, continue to the next tuple */
6414  }
6415  }
6416  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
6417  {
6418  if (ev_res == V_TRUE)
6419  {
6420  scan_id->qualification = QPROC_QUALIFIED;
6421  }
6422  else if (ev_res == V_FALSE)
6423  {
6425  }
6426  else /* V_UNKNOWN */
6427  {
6428  /* nop */
6429  ;
6430  }
6431  }
6432  else
6433  { /* invalid value; the same as QPROC_QUALIFIED */
6434  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
6435  {
6436  continue; /* not qualified, continue to the next tuple */
6437  }
6438  }
6439 
6440  scan_id->scan_stats.qualified_rows++;
6441 
6442  /* fetch the rest of the values from the tuple */
6443  if (scan_id->val_list)
6444  {
6445  if (fetch_val_list (thread_p, llsidp->rest_regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) != NO_ERROR)
6446  {
6447  return S_ERROR;
6448  }
6449  }
6450 
6451  if (llsidp->tplrecp)
6452  {
6453  llsidp->tplrecp->size = tplrec.size;
6454  llsidp->tplrecp->tpl = tplrec.tpl;
6455  }
6456 
6457  return S_SUCCESS;
6458  }
6459 
6460  return qp_scan;
6461 }
6462 
6463 /*
6464  * scan_next_value_scan () - The scan is moved to the next value scan item.
6465  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6466  * scan_id(in/out): Scan identifier
6467  *
6468  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
6469  */
6470 static SCAN_CODE
6472 {
6473  REGU_VALUES_SCAN_ID *rvsidp;
6474  regu_variable_list_node *list_node;
6476  int i;
6477 
6478  rvsidp = &scan_id->s.rvsid;
6479  if (scan_id->position == S_BEFORE)
6480  {
6481  scan_id->position = S_ON;
6482  }
6483  else if (scan_id->position == S_ON)
6484  {
6485  for (i = 0, list_node = rvsidp->regu_list; list_node; ++i, list_node = list_node->next)
6486  {
6487  regu_value_list = list_node->value.value.reguval_list;
6488  if (regu_value_list == NULL)
6489  {
6491  return S_ERROR;
6492  }
6493 
6494  assert (regu_value_list->current_value != NULL);
6495 
6496  regu_value_list->current_value = regu_value_list->current_value->next;
6497 
6498  if (regu_value_list->current_value == NULL)
6499  {
6500  scan_id->position = S_AFTER;
6501 
6502  if (i == 0)
6503  {
6504  return S_END;
6505  }
6506  else
6507  {
6509  return S_ERROR;
6510  }
6511  }
6512  }
6513  }
6514  else if (scan_id->position == S_AFTER)
6515  {
6516  return S_END;
6517  }
6518  else
6519  {
6521  return S_ERROR;
6522  }
6523 
6524  return S_SUCCESS;
6525 }
6526 
6527 /*
6528  * scan_next_showstmt_scan () - The scan is moved to the next value scan item.
6529  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6530  * scan_id(in/out): Scan identifier
6531  *
6532  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
6533  */
6534 static SCAN_CODE
6536 {
6537  SHOWSTMT_SCAN_ID *stsidp;
6538  SCAN_CODE qp_scan;
6539  DB_LOGICAL ev_res;
6540 
6541  stsidp = &scan_id->s.stsid;
6542 
6543  if (scan_id->position == S_BEFORE)
6544  {
6545  scan_id->position = S_ON;
6546  }
6547 
6548  if (scan_id->position == S_ON)
6549  {
6550  while ((qp_scan = showstmt_next_scan (thread_p, scan_id)) == S_SUCCESS)
6551  {
6552  /* evaluate the predicate to see if the tuple qualifies */
6553  ev_res = V_TRUE;
6554  if (stsidp->scan_pred.pr_eval_fnc && stsidp->scan_pred.pred_expr)
6555  {
6556  ev_res = (*stsidp->scan_pred.pr_eval_fnc) (thread_p, stsidp->scan_pred.pred_expr, scan_id->vd, NULL);
6557  if (ev_res == V_ERROR)
6558  {
6559  return S_ERROR;
6560  }
6561  }
6562 
6563  if (scan_id->qualification == QPROC_QUALIFIED)
6564  {
6565  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
6566  {
6567  continue; /* not qualified, continue to the next tuple */
6568  }
6569  }
6570  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
6571  {
6572  if (ev_res != V_FALSE) /* V_TRUE || V_UNKNOWN */
6573  {
6574  continue; /* qualified, continue to the next tuple */
6575  }
6576  }
6577  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
6578  {
6579  if (ev_res == V_TRUE)
6580  {
6581  scan_id->qualification = QPROC_QUALIFIED;
6582  }
6583  else if (ev_res == V_FALSE)
6584  {
6586  }
6587  else /* V_UNKNOWN */
6588  {
6589  /* nop */
6590  ;
6591  }
6592  }
6593  else
6594  { /* invalid value; the same as QPROC_QUALIFIED */
6595  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
6596  {
6597  continue; /* not qualified, continue to the next tuple */
6598  }
6599  }
6600 
6601  return S_SUCCESS;
6602  }
6603 
6604  }
6605  else if (scan_id->position == S_AFTER)
6606  {
6607  return S_END;
6608  }
6609  else
6610  {
6612  return S_ERROR;
6613  }
6614 
6615  return qp_scan;
6616 }
6617 
6618 /*
6619  * scan_next_set_scan () - The scan is moved to the next set scan item.
6620  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6621  * scan_id(in/out): Scan identifier
6622  *
6623  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
6624  */
6625 static SCAN_CODE
6626 scan_next_set_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id)
6627 {
6628  SET_SCAN_ID *ssidp;
6629  SCAN_CODE qp_scan;
6630  DB_LOGICAL ev_res;
6631  REGU_VARIABLE *func;
6633  int size;
6634 
6635  ssidp = &scan_id->s.ssid;
6636 
6637  /* if we are in the before position, fetch the set */
6638  if (scan_id->position == S_BEFORE)
6639  {
6640  func = ssidp->set_ptr;
6641  if (func->type == TYPE_FUNC && func->value.funcp->ftype == F_SEQUENCE)
6642  {
6643  size = 0;
6644  for (ptr = func->value.funcp->operand; ptr; ptr = ptr->next)
6645  {
6646  size++;
6647  }
6648  ssidp->operand = func->value.funcp->operand;
6649  ssidp->set_card = size;
6650  }
6651  else
6652  {
6653  pr_clear_value (&ssidp->set);
6654  if (fetch_copy_dbval (thread_p, ssidp->set_ptr, scan_id->vd, NULL, NULL, NULL, &ssidp->set) != NO_ERROR)
6655  {
6656  return S_ERROR;
6657  }
6658  }
6659  }
6660 
6661  /* evaluate set expression and put resultant set in DB_VALUE */
6662  while ((qp_scan = qproc_next_set_scan (thread_p, scan_id)) == S_SUCCESS)
6663  {
6664  assert (scan_id->val_list != NULL);
6665  assert (scan_id->val_list->val_cnt == 1);
6666 
6667  ev_res = V_TRUE;
6668  if (ssidp->scan_pred.pr_eval_fnc && ssidp->scan_pred.pred_expr)
6669  {
6670  ev_res = (*ssidp->scan_pred.pr_eval_fnc) (thread_p, ssidp->scan_pred.pred_expr, scan_id->vd, NULL);
6671  if (ev_res == V_ERROR)
6672  {
6673  return S_ERROR;
6674  }
6675  }
6676 
6677  if (scan_id->qualification == QPROC_QUALIFIED)
6678  {
6679  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
6680  {
6681  continue; /* not qualified, continue to the next tuple */
6682  }
6683  }
6684  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
6685  {
6686  if (ev_res != V_FALSE) /* V_TRUE || V_UNKNOWN */
6687  {
6688  continue; /* qualified, continue to the next tuple */
6689  }
6690  }
6691  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
6692  {
6693  if (ev_res == V_TRUE)
6694  {
6695  scan_id->qualification = QPROC_QUALIFIED;
6696  }
6697  else if (ev_res == V_FALSE)
6698  {
6700  }
6701  else /* V_UNKNOWN */
6702  {
6703  /* nop */
6704  ;
6705  }
6706  }
6707  else
6708  { /* invalid value; the same as QPROC_QUALIFIED */
6709  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
6710  {
6711  continue; /* not qualified, continue to the next tuple */
6712  }
6713  }
6714 
6715  return S_SUCCESS;
6716  } /* while ((qp_scan = ) == S_SUCCESS) */
6717 
6718  return qp_scan;
6719 }
6720 
6721 /*
6722  * scan_next_json_table_scan () - The scan is moved to the next json_table scan item.
6723  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6724  * scan_id(in/out): Scan identifier
6725  *
6726  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
6727  */
6728 static SCAN_CODE
6730 {
6731  int error_code = NO_ERROR;
6732  SCAN_CODE sc;
6733 
6734  // the status of the scan will be put in scan_id->status
6735  error_code = scan_id->s.jtid.next_scan (thread_p, *scan_id, sc);
6736  if (error_code != NO_ERROR)
6737  {
6738  ASSERT_ERROR ();
6739  return S_ERROR;
6740  }
6741 
6742  return sc;
6743 }
6744 
6745 /*
6746  * scan_next_method_scan () - The scan is moved to the next method scan item.
6747  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6748  * scan_id(in/out): Scan identifier
6749  *
6750  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
6751  */
6752 static SCAN_CODE
6754 {
6755  VA_SCAN_ID *vaidp;
6756  SCAN_CODE qp_scan;
6757  val_list_node vl;
6758  QPROC_DB_VALUE_LIST src_valp;
6759  QPROC_DB_VALUE_LIST dest_valp;
6760 
6761  vaidp = &scan_id->s.vaid;
6762 
6763  /* execute method scan */
6764  qp_scan = method_scan_next (thread_p, &vaidp->scan_buf, &vl);
6765  if (qp_scan != S_SUCCESS)
6766  {
6767  /* scan error or end of scan */
6768  if (qp_scan == S_END)
6769  {
6770  scan_id->position = S_AFTER;
6771  return S_END;
6772  }
6773  else
6774  {
6775  return S_ERROR;
6776  }
6777  }
6778 
6779  /* copy the result into the value list of the scan ID */
6780  for (src_valp = vl.valp, dest_valp = scan_id->val_list->valp; src_valp && dest_valp;
6781  src_valp = src_valp->next, dest_valp = dest_valp->next)
6782  {
6783  if (DB_IS_NULL (src_valp->val))
6784  {
6785  pr_clear_value (dest_valp->val);
6786  }
6787  else if (DB_VALUE_DOMAIN_TYPE (src_valp->val) != DB_VALUE_DOMAIN_TYPE (dest_valp->val))
6788  {
6790  pr_clear_value (src_valp->val);
6791  free_and_init (src_valp->val);
6792  return S_ERROR;
6793  }
6794  else if (!qdata_copy_db_value (dest_valp->val, src_valp->val))
6795  {
6796  return S_ERROR;
6797  }
6798 
6799  pr_clear_value (src_valp->val);
6800  free_and_init (src_valp->val);
6801  }
6802 
6803  return S_SUCCESS;
6804 }
6805 
6806 /*
6807  * scan_handle_single_scan () -
6808  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6809  * scan_id(in/out): Scan identifier
6810  *
6811  * Note: This second order function applies the given next-scan function,
6812  * then enforces the single_fetch , null_fetch semantics.
6813  * Note that when "single_fetch", "null_fetch" is asserted, at least one
6814  * qualified scan item, the NULL row, is returned.
6815  */
6816 static SCAN_CODE
6818 {
6819  SCAN_CODE result = S_ERROR;
6820 
6821  if (s_id->scan_immediately_stop == true)
6822  {
6823  result = S_END;
6824  goto end;
6825  }
6826 
6827  switch (s_id->single_fetch)
6828  {
6829  case QPROC_NO_SINGLE_INNER:
6830  result = (*next_scan) (thread_p, s_id);
6831 
6832  if (result == S_ERROR)
6833  {
6834  goto exit_on_error;
6835  }
6836  break;
6837 
6838  case QPROC_SINGLE_OUTER:
6839  /* already returned a row? */
6840  /* if scan works in a single_fetch mode and first qualified scan item has already been fetched, return
6841  * end_of_scan. */
6842  if (s_id->single_fetched)
6843  {
6844  result = S_END;
6845  }
6846  else
6847  /* if it is known that scan has no qualified items, return the NULL row, without searching. */
6848  if (s_id->join_dbval && DB_IS_NULL (s_id->join_dbval))
6849  {
6851  s_id->single_fetched = true;
6852  result = S_SUCCESS;
6853  }
6854  else
6855  {
6856  result = (*next_scan) (thread_p, s_id);
6857 
6858  if (result == S_ERROR)
6859  {
6860  goto exit_on_error;
6861  }
6862 
6863  if (result == S_END)
6864  {
6866  result = S_SUCCESS;
6867  }
6868 
6869  s_id->single_fetched = true;
6870  }
6871  break;
6872 
6873  case QPROC_SINGLE_INNER: /* currently, not used */
6874  /* already returned a row? */
6875  /* if scan works in a single_fetch mode and first qualified scan item has already been fetched, return
6876  * end_of_scan. */
6877  if (s_id->single_fetched)
6878  {
6879  result = S_END;
6880  }
6881  /* if it is known that scan has no qualified items, return the NULL row, without searching. */
6882  else if (s_id->join_dbval && DB_IS_NULL (s_id->join_dbval))
6883  {
6884  result = S_END;
6885  }
6886  else
6887  {
6888  result = (*next_scan) (thread_p, s_id);
6889 
6890  if (result == S_ERROR)
6891  {
6892  goto exit_on_error;
6893  }
6894 
6895  if (result == S_SUCCESS)
6896  {
6897  s_id->single_fetched = true;
6898  }
6899  }
6900  break;
6901 
6902  case QPROC_NO_SINGLE_OUTER:
6903  /* already returned a NULL row? if scan works in a left outer join mode and a NULL row has already fetched,
6904  * return end_of_scan. */
6905  if (s_id->null_fetched)
6906  {
6907  result = S_END;
6908  }
6909  else
6910  {
6911  result = (*next_scan) (thread_p, s_id);
6912 
6913  if (result == S_ERROR)
6914  {
6915  goto exit_on_error;
6916  }
6917 
6918  if (result == S_END)
6919  {
6920  if (!s_id->single_fetched)
6921  {
6922  /* no qualified items, return a NULL row */
6924  s_id->null_fetched = true;
6925  result = S_SUCCESS;
6926  }
6927  }
6928 
6929  if (result == S_SUCCESS)
6930  {
6931  s_id->single_fetched = true;
6932  }
6933  }
6934  break;
6935  }
6936 
6937 end:
6938  /* maintain what is apparently supposed to be an invariant-- S_END implies position is "after" the scan */
6939  if (result == S_END)
6940  {
6941  if (s_id->direction != S_BACKWARD)
6942  {
6943  s_id->position = S_AFTER;
6944  }
6945  else
6946  {
6947  s_id->position = S_BEFORE;
6948  }
6949  }
6950 
6951  return result;
6952 
6953 exit_on_error:
6954 
6955  return S_ERROR;
6956 }
6957 
6958 /*
6959  * scan_next_scan () -
6960  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6961  * scan_id(in/out): Scan identifier
6962  */
6963 SCAN_CODE
6965 {
6966  return scan_handle_single_scan (thread_p, s_id, scan_next_scan_local);
6967 }
6968 
6969 /*
6970  * scan_prev_scan_local () - The scan is moved to the previous scan item.
6971  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
6972  * scan_id(in/out): Scan identifier
6973  *
6974  * Note: If there are no more scan items, S_END is returned.
6975  * If an error occurs, S_ERROR is returned. This routine currently supports only LIST FILE scans.
6976  */
6977 static SCAN_CODE
6979 {
6980  LLIST_SCAN_ID *llsidp;
6981  SCAN_CODE qp_scan;
6982  DB_LOGICAL ev_res;
6983  QFILE_TUPLE_RECORD tplrec;
6984 
6985  switch (scan_id->type)
6986  {
6987  case S_LIST_SCAN:
6988  llsidp = &scan_id->s.llsid;
6989 
6990  tplrec.size = 0;
6991  tplrec.tpl = (QFILE_TUPLE) NULL;
6992 
6993  while ((qp_scan = qfile_scan_list_prev (thread_p, &llsidp->lsid, &tplrec, PEEK)) == S_SUCCESS)
6994  {
6995  /* fetch the values for the predicate from the tuple */
6996  if (scan_id->val_list)
6997  {
6998  if (fetch_val_list (thread_p, llsidp->scan_pred.regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
6999  NO_ERROR)
7000  {
7001  return S_ERROR;
7002  }
7003  }
7004 
7005  /* evaluate the predicate to see if the tuple qualifies */
7006  ev_res = V_TRUE;
7007  if (llsidp->scan_pred.pr_eval_fnc && llsidp->scan_pred.pred_expr)
7008  {
7009  ev_res = (*llsidp->scan_pred.pr_eval_fnc) (thread_p, llsidp->scan_pred.pred_expr, scan_id->vd, NULL);
7010  if (ev_res == V_ERROR)
7011  {
7012  return S_ERROR;
7013  }
7014  }
7015 
7016  if (scan_id->qualification == QPROC_QUALIFIED)
7017  {
7018  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
7019  {
7020  continue; /* not qualified, continue to the next tuple */
7021  }
7022  }
7023  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
7024  {
7025  if (ev_res != V_FALSE) /* V_TRUE || V_UNKNOWN */
7026  {
7027  continue; /* qualified, continue to the next tuple */
7028  }
7029  }
7030  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
7031  {
7032  if (ev_res == V_TRUE)
7033  {
7034  scan_id->qualification = QPROC_QUALIFIED;
7035  }
7036  else if (ev_res == V_FALSE)
7037  {
7039  }
7040  else /* V_UNKNOWN */
7041  {
7042  /* nop */
7043  ;
7044  }
7045  }
7046  else
7047  { /* invalid value; the same as QPROC_QUALIFIED */
7048  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
7049  {
7050  continue; /* not qualified, continue to the next tuple */
7051  }
7052  }
7053 
7054  /* fetch the rest of the values from the tuple */
7055  if (scan_id->val_list)
7056  {
7057  if (fetch_val_list (thread_p, llsidp->rest_regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
7058  NO_ERROR)
7059  {
7060  return S_ERROR;
7061  }
7062  }
7063 
7064  if (llsidp->tplrecp)
7065  {
7066  llsidp->tplrecp->size = tplrec.size;
7067  llsidp->tplrecp->tpl = tplrec.tpl;
7068  }
7069 
7070  return S_SUCCESS;
7071  }
7072 
7073  if (qp_scan == S_END)
7074  {
7075  scan_id->position = S_BEFORE;
7076  }
7077 
7078  return qp_scan;
7079 
7080  default:
7082  return S_ERROR;
7083  } /* switch (scan_id->type) */
7084 }
7085 
7086 /*
7087  * scan_prev_scan () - The scan is moved to the previous scan item.
7088  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7089  * scan_id(in/out): Scan identifier
7090  *
7091  * Note: If there are no more scan items, S_END is returned.
7092  * If an error occurs, S_ERROR is returned. This routine currently supports only LIST FILE scans.
7093  */
7094 SCAN_CODE
7096 {
7097  return scan_handle_single_scan (thread_p, s_id, scan_prev_scan_local);
7098 }
7099 
7100 /*
7101  * scan_save_scan_pos () - Save current scan position information.
7102  * return:
7103  * scan_id(in/out): Scan identifier
7104  * scan_pos(in/out): Set to contain current scan position
7105  *
7106  * Note: This routine currently assumes only LIST FILE scans.
7107  */
7108 void
7110 {
7111  scan_pos->status = s_id->status;
7112  scan_pos->position = s_id->position;
7114 }
7115 
7116 /*
7117  * scan_jump_scan_pos () - Jump to the given scan position and move the scan
7118  * from that point on in the forward direction.
7119  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7120  * scan_id(in/out): Scan identifier
7121  * scan_pos(in/out): Set to contain current scan position
7122  *
7123  * Note: This routine currently assumes only LIST FILE scans.
7124  */
7125 SCAN_CODE
7127 {
7128  LLIST_SCAN_ID *llsidp;
7129  DB_LOGICAL ev_res;
7130  QFILE_TUPLE_RECORD tplrec;
7131  SCAN_CODE qp_scan;
7132 
7133  llsidp = &s_id->s.llsid;
7134 
7135  /* put back saved scan position */
7136  s_id->status = scan_pos->status;
7137  s_id->position = scan_pos->position;
7138 
7139  /* jump to the previouslt saved scan position and continue from that point on forward */
7140  tplrec.size = 0;
7141  tplrec.tpl = (QFILE_TUPLE) NULL;
7142 
7143  qp_scan = qfile_jump_scan_tuple_position (thread_p, &llsidp->lsid, &scan_pos->ls_tplpos, &tplrec, PEEK);
7144  if (qp_scan != S_SUCCESS)
7145  {
7146  if (qp_scan == S_END)
7147  {
7148  s_id->position = S_AFTER;
7149  }
7150  return qp_scan;
7151  }
7152 
7153  do
7154  {
7155  /* fetch the value for the predicate from the tuple */
7156  if (s_id->val_list)
7157  {
7158  if (fetch_val_list (thread_p, llsidp->scan_pred.regu_list, s_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
7159  NO_ERROR)
7160  {
7161  return S_ERROR;
7162  }
7163  }
7164 
7165  /* evaluate the predicate to see if the tuple qualifies */
7166  ev_res = V_TRUE;
7167  if (llsidp->scan_pred.pr_eval_fnc && llsidp->scan_pred.pred_expr)
7168  {
7169  ev_res = (*llsidp->scan_pred.pr_eval_fnc) (thread_p, llsidp->scan_pred.pred_expr, s_id->vd, NULL);
7170  if (ev_res == V_ERROR)
7171  {
7172  return S_ERROR;
7173  }
7174  }
7175 
7176  if (s_id->qualification == QPROC_QUALIFIED)
7177  {
7178  if (ev_res == V_TRUE)
7179  {
7180  /* nop */ ;
7181  }
7182  /* qualified, return it */
7183  }
7184  else if (s_id->qualification == QPROC_NOT_QUALIFIED)
7185  {
7186  if (ev_res == V_FALSE)
7187  {
7188  ev_res = V_TRUE; /* not qualified, return it */
7189  }
7190  }
7191  else if (s_id->qualification == QPROC_QUALIFIED_OR_NOT)
7192  {
7193  if (ev_res == V_TRUE)
7194  {
7196  }
7197  else if (ev_res == V_FALSE)
7198  {
7200  }
7201  else /* V_UNKNOWN */
7202  {
7203  /* nop */
7204  ;
7205  }
7206  ev_res = V_TRUE; /* return it */
7207  }
7208  else
7209  { /* invalid value; the same as QPROC_QUALIFIED */
7210  if (ev_res == V_TRUE)
7211  {
7212  /* nop */ ;
7213  }
7214  /* qualified, return it */
7215  }
7216 
7217  if (ev_res == V_TRUE)
7218  {
7219  /* fetch the rest of the values from the tuple */
7220  if (s_id->val_list)
7221  {
7222  if (fetch_val_list (thread_p, llsidp->rest_regu_list, s_id->vd, NULL, NULL, tplrec.tpl, PEEK) != NO_ERROR)
7223  {
7224  return S_ERROR;
7225  }
7226  }
7227 
7228  if (llsidp->tplrecp)
7229  {
7230  llsidp->tplrecp->size = tplrec.size;
7231  llsidp->tplrecp->tpl = tplrec.tpl;
7232  }
7233  return S_SUCCESS;
7234  }
7235 
7236  }
7237  while ((qp_scan = qfile_scan_list_next (thread_p, &llsidp->lsid, &tplrec, PEEK)) == S_SUCCESS);
7238 
7239  if (qp_scan == S_END)
7240  {
7241  s_id->position = S_AFTER;
7242  }
7243  return qp_scan;
7244 }
7245 
7246 /*
7247  * scan_initialize () - initialize scan management routine
7248  * return: NO_ERROR if all OK, ER status otherwise
7249  */
7250 int
7252 {
7253  BTREE_ISCAN_OID_LIST *new_oid_list = NULL;
7254  int error_code = NO_ERROR;
7255  int i = 0;
7256 
7257  /* Initialize */
7258  scan_Iscan_oid_buf_list = NULL;
7259  scan_Iscan_oid_buf_list_count = 0;
7260 
7261  /* Allocate oid buffer list. */
7262  for (i = 0; i < SCAN_ISCAN_OID_BUF_LIST_DEFAULT_SIZE; i++)
7263  {
7264  /* Allocate new entry. */
7265  new_oid_list = NULL;
7266  error_code = scan_alloc_oid_list (&new_oid_list);
7267  if (error_code != NO_ERROR)
7268  {
7269  ASSERT_ERROR ();
7270  /* Free what was already allocated. */
7271  scan_finalize ();
7272 
7273  /* Return error. */
7274  return error_code;
7275  }
7276  /* Safe guard. */
7277  assert (new_oid_list->oidp != NULL);
7278  assert (new_oid_list->capacity > 0);
7279 
7280  /* Save new buffer to buffer list. */
7281  new_oid_list->next_list = scan_Iscan_oid_buf_list;
7282  scan_Iscan_oid_buf_list = new_oid_list;
7283  scan_Iscan_oid_buf_list_count++;
7284  }
7285  /* Success. */
7286  return NO_ERROR;
7287 }
7288 
7289 /*
7290  * scan_finalize () - finalize scan management routine
7291  * return:
7292  */
7293 void
7295 {
7296  BTREE_ISCAN_OID_LIST *oid_list_p;
7297 
7298  while (scan_Iscan_oid_buf_list != NULL)
7299  {
7300  /* Save current. */
7301  oid_list_p = scan_Iscan_oid_buf_list;
7302 
7303  /* Advance to next. */
7304  scan_Iscan_oid_buf_list = oid_list_p->next_list;
7305 
7306  /* Free current. */
7307  scan_free_oid_list (oid_list_p);
7308  }
7309 
7310  /* Reset count. */
7311  scan_Iscan_oid_buf_list_count = 0;
7312 }
7313 
7314 /*
7315  * reverse_key_list () - reverses the key list
7316  * return: number of keys, -1 for error
7317  * key_vals (in): pointer to array of KEY_VAL_RANGE structure
7318  * key_cnt (in): number of keys; size of key_vals
7319  */
7320 static int
7322 {
7323  int i, j;
7324  KEY_VAL_RANGE temp;
7325 
7326  for (i = 0, j = key_cnt - 1; i < j; i++, j--)
7327  {
7328  temp = key_vals[i];
7329  key_vals[i] = key_vals[j];
7330  key_vals[j] = temp;
7331  }
7332 
7333  return key_cnt;
7334 }
7335 
7336 /*
7337  * resolve_domains_on_list_scan () - scans the structures in a list scan id
7338  * and resolves the domains in sub-components like regu variables from scan
7339  * predicates;
7340  *
7341  * llsidp (in/out): pointer to list scan id structure
7342  * ref_val_list (in): list of DB_VALUEs (val_list_node) used as reference
7343  *
7344  * Note : this function is used in context of HV late binding
7345  */
7346 static void
7348 {
7349  regu_variable_list_node *scan_regu = NULL;
7350 
7351  assert (llsidp != NULL);
7352 
7353  if (llsidp->list_id == NULL || ref_val_list == NULL)
7354  {
7355  return;
7356  }
7357 
7358  /* resolve domains on regu_list of scan predicate */
7359  for (scan_regu = llsidp->scan_pred.regu_list; scan_regu != NULL; scan_regu = scan_regu->next)
7360  {
7361  if ((TP_DOMAIN_TYPE (scan_regu->value.domain) == DB_TYPE_VARIABLE
7362  || TP_DOMAIN_COLLATION_FLAG (scan_regu->value.domain)) && scan_regu->value.type == TYPE_POSITION)
7363  {
7364  int pos = scan_regu->value.value.pos_descr.pos_no;
7365  TP_DOMAIN *new_dom = NULL;
7366 
7367  assert (pos < llsidp->list_id->type_list.type_cnt);
7368  new_dom = llsidp->list_id->type_list.domp[pos];
7369 
7370  if (TP_DOMAIN_TYPE (new_dom) == DB_TYPE_VARIABLE
7372  {
7373  continue;
7374  }
7375 
7376  scan_regu->value.value.pos_descr.dom = new_dom;
7377  scan_regu->value.domain = new_dom;
7378  }
7379  }
7380 
7381  /* resolve domains on rest_regu_list of scan predicate */
7382  for (scan_regu = llsidp->rest_regu_list; scan_regu != NULL; scan_regu = scan_regu->next)
7383  {
7384  if ((TP_DOMAIN_TYPE (scan_regu->value.domain) == DB_TYPE_VARIABLE
7385  || TP_DOMAIN_COLLATION_FLAG (scan_regu->value.domain) != TP_DOMAIN_COLL_NORMAL)
7386  && scan_regu->value.type == TYPE_POSITION)
7387  {
7388  int pos = scan_regu->value.value.pos_descr.pos_no;
7389  TP_DOMAIN *new_dom = NULL;
7390 
7391  assert (pos < llsidp->list_id->type_list.type_cnt);
7392  new_dom = llsidp->list_id->type_list.domp[pos];
7393 
7394  if (TP_DOMAIN_TYPE (new_dom) == DB_TYPE_VARIABLE
7396  {
7397  continue;
7398  }
7399  scan_regu->value.value.pos_descr.dom = new_dom;
7400  scan_regu->value.domain = new_dom;
7401  }
7402  }
7403 
7404  /* resolve domains on predicate expression of scan predicate */
7405  if (llsidp->scan_pred.pred_expr == NULL)
7406  {
7407  return;
7408  }
7409 
7410  if (llsidp->scan_pred.pred_expr->type == T_EVAL_TERM)
7411  {
7412  EVAL_TERM ev_t = llsidp->scan_pred.pred_expr->pe.m_eval_term;
7413 
7414  if (ev_t.et_type == T_COMP_EVAL_TERM)
7415  {
7416  if (ev_t.et.et_comp.lhs != NULL
7419  {
7420  resolve_domain_on_regu_operand (ev_t.et.et_comp.lhs, ref_val_list, &(llsidp->list_id->type_list));
7421  }
7422  if (ev_t.et.et_comp.rhs != NULL
7425  {
7426  resolve_domain_on_regu_operand (ev_t.et.et_comp.rhs, ref_val_list, &(llsidp->list_id->type_list));
7427  }
7428  }
7429  }
7430 }
7431 
7432 /*
7433  * resolve_domain_on_regu_operand () - resolves a domain on a regu variable
7434  * from a scan list; helper functions for 'resolve_domains_on_list_scan'
7435  *
7436  * regu_var (in/out): regulator variable with unresolved domain
7437  * ref_val_list (in): list of DB_VALUEs (val_list_node) used for cross-checking
7438  * p_type_list (in): list of domains used as reference
7439  *
7440  * Note : this function is used in context of HV late binding
7441  */
7442 static void
7444  QFILE_TUPLE_VALUE_TYPE_LIST * p_type_list)
7445 {
7446  assert (regu_var != NULL);
7447  assert (ref_val_list != NULL);
7448 
7449  if (regu_var->type == TYPE_CONSTANT)
7450  {
7451  QPROC_DB_VALUE_LIST value_list;
7452  int pos = 0;
7453  bool found = false;
7454 
7455  /* search in ref_val_list for the corresponding DB_VALUE */
7456  for (value_list = ref_val_list->valp; value_list != NULL; value_list = value_list->next, pos++)
7457  {
7458  if (regu_var->value.dbvalptr == ref_val_list->valp->val)
7459  {
7460  found = true;
7461  break;
7462  }
7463  }
7464 
7465  if (found)
7466  {
7467  assert (pos < p_type_list->type_cnt);
7468  regu_var->domain = p_type_list->domp[pos];
7469  }
7470  }
7471 }
7472 
7473 /*
7474  * scan_init_multi_range_optimization () - initialize structure for multiple range optimization
7475  *
7476  * return: error code
7477  *
7478  * multi_range_opt(in): multiple range optimization structure
7479  * use_range_opt(in): to use or not optimization
7480  * max_size(in): size of arrays for the top N values
7481  */
7482 static int
7484  int max_size)
7485 {
7486  int err = NO_ERROR;
7487 
7488  if (multi_range_opt == NULL)
7489  {
7490  return ER_FAILED;
7491  }
7492 
7493  memset ((void *) (multi_range_opt), 0, sizeof (MULTI_RANGE_OPT));
7494  multi_range_opt->use = use_range_opt;
7495  multi_range_opt->cnt = 0;
7496 
7497  if (use_range_opt)
7498  {
7499  multi_range_opt->size = max_size;
7500  /* we don't have sort information here, just set an invalid value */
7501  multi_range_opt->sort_att_idx = NULL;
7502  multi_range_opt->is_desc_order = NULL;
7503  multi_range_opt->num_attrs = 0;
7504 
7505  multi_range_opt->top_n_items =
7506  (RANGE_OPT_ITEM **) db_private_alloc (thread_p, max_size * sizeof (RANGE_OPT_ITEM *));
7507  if (multi_range_opt->top_n_items == NULL)
7508  {
7510  goto exit_on_error;
7511  }
7512  multi_range_opt->buffer = (RANGE_OPT_ITEM **) db_private_alloc (thread_p, max_size * sizeof (RANGE_OPT_ITEM *));
7513  if (multi_range_opt->buffer == NULL)
7514  {
7516  goto exit_on_error;
7517  }
7518  memset (multi_range_opt->top_n_items, 0, max_size * sizeof (RANGE_OPT_ITEM *));
7519 
7520  multi_range_opt->tplrec.size = 0;
7521  multi_range_opt->tplrec.tpl = NULL;
7522 
7524  }
7525 
7526  return err;
7527 
7528 exit_on_error:
7529 
7530  if (multi_range_opt->top_n_items != NULL)
7531  {
7532  db_private_free_and_init (thread_p, multi_range_opt->top_n_items);
7533  }
7534  if (multi_range_opt->buffer != NULL)
7535  {
7536  db_private_free_and_init (thread_p, multi_range_opt->buffer);
7537  }
7538 
7539  return err;
7540 }
7541 
7542 /*
7543  * scan_dump_key_into_tuple () - outputs the value stored in 'key' into the tuple 'tplrec'
7544  *
7545  * return: error code
7546  * iscan_id(in):
7547  * key(in): MIDXKEY key (as it is retreived from index)
7548  * oid(in): oid (required if objects are stored in 'key')
7549  * tplrec(out):
7550  *
7551  * Note : this function is used by multiple range search optimization;
7552  * although not required here, the key should be a MIDXKEY value,
7553  * when multiple range search optimization is enabled.
7554  */
7555 static int
7556 scan_dump_key_into_tuple (THREAD_ENTRY * thread_p, INDX_SCAN_ID * iscan_id, DB_VALUE * key, OID * oid,
7557  QFILE_TUPLE_RECORD * tplrec)
7558 {
7559  int error;
7561 
7562  if (iscan_id == NULL || iscan_id->indx_cov.val_descr == NULL || iscan_id->indx_cov.output_val_list == NULL
7563  || iscan_id->rest_attrs.attr_cache == NULL)
7564  {
7565  return ER_FAILED;
7566  }
7567 
7568  error = btree_attrinfo_read_dbvalues (thread_p, key, iscan_id->bt_attr_ids, iscan_id->bt_num_attrs,
7569  iscan_id->rest_attrs.attr_cache, -1);
7570  if (error != NO_ERROR)
7571  {
7572  return error;
7573  }
7574 
7575  for (p = iscan_id->rest_regu_list; p; p = p->next)
7576  {
7577  pr_clear_value (p->value.vfetch_to);
7578  }
7579 
7580  error = fetch_val_list (thread_p, iscan_id->rest_regu_list, iscan_id->indx_cov.val_descr, NULL, oid, NULL, PEEK);
7581  if (error != NO_ERROR)
7582  {
7583  return error;
7584  }
7585 
7586  error = qdata_copy_valptr_list_to_tuple (thread_p, iscan_id->indx_cov.output_val_list, iscan_id->indx_cov.val_descr,
7587  tplrec);
7588  if (error != NO_ERROR)
7589  {
7590  return error;
7591  }
7592 
7593  return NO_ERROR;
7594 }
7595 
7596 
7597 #if defined (SERVER_MODE)
7598 /*
7599  * scan_print_stats_json () -
7600  * return:
7601  * scan_id(in):
7602  */
7603 void
7604 scan_print_stats_json (SCAN_ID * scan_id, json_t * scan_stats)
7605 {
7606  json_t *scan, *lookup;
7607 
7608  if (scan_id == NULL || scan_stats == NULL)
7609  {
7610  return;
7611  }
7612 
7613  scan = json_pack ("{s:i, s:I, s:I}", "time", TO_MSEC (scan_id->scan_stats.elapsed_scan), "fetch",
7614  scan_id->scan_stats.num_fetches, "ioread", scan_id->scan_stats.num_ioreads);
7615 
7616  switch (scan_id->type)
7617  {
7618  case S_HEAP_SCAN:
7619  case S_LIST_SCAN:
7620  json_object_set_new (scan, "readrows", json_integer (scan_id->scan_stats.read_rows));
7621  json_object_set_new (scan, "rows", json_integer (scan_id->scan_stats.qualified_rows));
7622 
7623  if (scan_id->type == S_HEAP_SCAN)
7624  {
7625  json_object_set_new (scan_stats, "heap", scan);
7626  }
7627  else
7628  {
7629  json_object_set_new (scan_stats, "temp", scan);
7630  }
7631  break;
7632 
7633  case S_INDX_SCAN:
7634  json_object_set_new (scan, "readkeys", json_integer (scan_id->scan_stats.read_keys));
7635  json_object_set_new (scan, "filteredkeys", json_integer (scan_id->scan_stats.qualified_keys));
7636  json_object_set_new (scan, "rows", json_integer (scan_id->scan_stats.key_qualified_rows));
7637  json_object_set_new (scan_stats, "btree", scan);
7638 
7639  if (scan_id->scan_stats.covered_index == true)
7640  {
7641  json_object_set_new (scan_stats, "covered", json_true ());
7642  }
7643  else
7644  {
7645  lookup = json_pack ("{s:i, s:i}", "time", TO_MSEC (scan_id->scan_stats.elapsed_lookup), "rows",
7646  scan_id->scan_stats.data_qualified_rows);
7647 
7648  json_object_set_new (scan_stats, "lookup", lookup);
7649  }
7650 
7651  if (scan_id->scan_stats.multi_range_opt == true)
7652  {
7653  json_object_set_new (scan_stats, "mro", json_true ());
7654  }
7655 
7656  if (scan_id->scan_stats.index_skip_scan == true)
7657  {
7658  json_object_set_new (scan_stats, "iss", json_true ());
7659  }
7660 
7661  if (scan_id->scan_stats.loose_index_scan == true)
7662  {
7663  json_object_set_new (scan_stats, "loose", json_true ());
7664  }
7665  break;
7666 
7667  case S_SHOWSTMT_SCAN:
7668  json_object_set_new (scan_stats, "show", scan);
7669  break;
7670 
7671  case S_SET_SCAN:
7672  json_object_set_new (scan_stats, "set", scan);
7673  break;
7674 
7675  case S_METHOD_SCAN:
7676  json_object_set_new (scan_stats, "method", scan);
7677  break;
7678 
7679  case S_CLASS_ATTR_SCAN:
7680  json_object_set_new (scan_stats, "class_attr", scan);
7681  break;
7682 
7683  default:
7684  json_object_set_new (scan_stats, "noscan", scan);
7685  break;
7686  }
7687 }
7688 
7689 /*
7690  * scan_print_stats_text () -
7691  * return:
7692  * scan_id(in):
7693  */
7694 void
7695 scan_print_stats_text (FILE * fp, SCAN_ID * scan_id)
7696 {
7697  if (scan_id == NULL)
7698  {
7699  return;
7700  }
7701 
7702  switch (scan_id->type)
7703  {
7704  case S_HEAP_SCAN:
7705  fprintf (fp, "(heap");
7706  break;
7707 
7708  case S_INDX_SCAN:
7709  fprintf (fp, "(btree");
7710  break;
7711 
7712  case S_LIST_SCAN:
7714  {
7715  fprintf (fp, "(hash temp, build time: %d,", TO_MSEC (scan_id->scan_stats.elapsed_hash_build));
7716  }
7717  else if (scan_id->s.llsid.hlsid.hash_list_scan_yn == HASH_METH_HYBRID)
7718  {
7719  fprintf (fp, "(hash temp(h), build time: %d,", TO_MSEC (scan_id->scan_stats.elapsed_hash_build));
7720  }
7721  else
7722  {
7723  fprintf (fp, "(temp");
7724  }
7725  break;
7726 
7727  case S_SHOWSTMT_SCAN:
7728  fprintf (fp, "(show");
7729  break;
7730 
7731  case S_SET_SCAN:
7732  fprintf (fp, "(set");
7733  break;
7734 
7735  case S_METHOD_SCAN:
7736  fprintf (fp, "(method");
7737  break;
7738 
7739  case S_CLASS_ATTR_SCAN:
7740  fprintf (fp, "(class_attr");
7741  break;
7742 
7743  default:
7744  fprintf (fp, "(noscan");
7745  break;
7746  }
7747 
7748  fprintf (fp, " time: %d, fetch: %lld, ioread: %lld", TO_MSEC (scan_id->scan_stats.elapsed_scan),
7749  (long long int) scan_id->scan_stats.num_fetches, (long long int) scan_id->scan_stats.num_ioreads);
7750 
7751  switch (scan_id->type)
7752  {
7753  case S_HEAP_SCAN:
7754  case S_LIST_SCAN:
7755  fprintf (fp, ", readrows: %d, rows: %d)", scan_id->scan_stats.read_rows, scan_id->scan_stats.qualified_rows);
7756  break;
7757 
7758  case S_INDX_SCAN:
7759  fprintf (fp, ", readkeys: %d, filteredkeys: %d, rows: %d", scan_id->scan_stats.read_keys,
7761 
7762  if (scan_id->scan_stats.covered_index == true)
7763  {
7764  fprintf (fp, ", covered: true");
7765  }
7766 
7767  if (scan_id->scan_stats.multi_range_opt == true)
7768  {
7769  fprintf (fp, ", mro: true");
7770  }
7771 
7772  if (scan_id->scan_stats.index_skip_scan == true)
7773  {
7774  fprintf (fp, ", iss: true");
7775  }
7776 
7777  if (scan_id->scan_stats.loose_index_scan == true)
7778  {
7779  fprintf (fp, ", loose: true");
7780  }
7781  fprintf (fp, ")");
7782 
7783  if (scan_id->scan_stats.covered_index == false)
7784  {
7785  fprintf (fp, " (lookup time: %d, rows: %d)", TO_MSEC (scan_id->scan_stats.elapsed_lookup),
7786  scan_id->scan_stats.data_qualified_rows);
7787  }
7788  break;
7789 
7790  default:
7791  fprintf (fp, ")");
7792  break;
7793  }
7794 }
7795 #endif
7796 
7797 /*
7798  * scan_build_hash_list_scan () - build hash table from list
7799  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7800  * scan_id(in/out): Scan identifier
7801  *
7802  * Note: If an error occurs, S_ERROR is returned.
7803  */
7804 static SCAN_CODE
7806 {
7807  LLIST_SCAN_ID *llsidp;
7808  SCAN_CODE qp_scan;
7809  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
7810  HASH_SCAN_KEY *key, *new_key;
7811  HASH_SCAN_VALUE *new_value;
7812 
7813  llsidp = &scan_id->s.llsid;
7814  key = llsidp->hlsid.temp_key;
7815  new_key = llsidp->hlsid.temp_new_key;
7816 
7817  tplrec.size = 0;
7818  tplrec.tpl = (QFILE_TUPLE) NULL;
7819 
7820  resolve_domains_on_list_scan (llsidp, scan_id->val_list);
7821 
7822  while ((qp_scan = qfile_scan_list_next (thread_p, &llsidp->lsid, &tplrec, PEEK)) == S_SUCCESS)
7823  {
7824  /* fetch the values for the predicate from the tuple */
7825  if (scan_id->val_list)
7826  {
7827  if (fetch_val_list (thread_p, llsidp->scan_pred.regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
7828  NO_ERROR)
7829  {
7830  return S_ERROR;
7831  }
7832  }
7833 
7834  scan_id->scan_stats.read_rows++;
7835 
7836  /* build key */
7837  if (qdata_build_hscan_key (thread_p, scan_id->vd, llsidp->hlsid.build_regu_list, key) != NO_ERROR)
7838  {
7839  return S_ERROR;
7840  }
7841  /* create new key */
7842  if (llsidp->hlsid.need_coerce_type)
7843  {
7844  new_key = qdata_copy_hscan_key_without_alloc (thread_p, key, llsidp->hlsid.probe_regu_list, new_key);
7845  if (new_key == NULL)
7846  {
7847  return S_ERROR;
7848  }
7849  }
7850  else
7851  {
7852  new_key = key;
7853  }
7854 
7855  /* create new value */
7856  if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_IN_MEM)
7857  {
7858  new_value = qdata_alloc_hscan_value (thread_p, tplrec.tpl);
7859  }
7860  else if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_HYBRID)
7861  {
7862  new_value = qdata_alloc_hscan_value_OID (thread_p, &llsidp->lsid);
7863  }
7864  else
7865  {
7866  return S_ERROR;
7867  }
7868 
7869  if (new_value == NULL)
7870  {
7871  return S_ERROR;
7872  }
7873  /* add to hash table */
7874  if (mht_put_hls (llsidp->hlsid.hash_table, (void *) new_key, (void *) new_value) == NULL)
7875  {
7876  return S_ERROR;
7877  }
7878  }
7879 
7880  return qp_scan;
7881 }
7882 
7883 /*
7884  * scan_next_hash_list_scan () - The scan is moved to the next hash list scan item.
7885  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7886  * scan_id(in/out): Scan identifier
7887  *
7888  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
7889  */
7890 static SCAN_CODE
7892 {
7893  LLIST_SCAN_ID *llsidp;
7894  SCAN_CODE qp_scan;
7895  DB_LOGICAL ev_res;
7896  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
7897 
7898  tplrec.size = 0;
7899  tplrec.tpl = (QFILE_TUPLE) NULL;
7900 
7901  llsidp = &scan_id->s.llsid;
7902 
7903  while ((qp_scan = scan_hash_probe_next (thread_p, scan_id, &tplrec.tpl)) == S_SUCCESS)
7904  {
7905 
7906  /* fetch the values for the predicate from the tuple */
7907  if (scan_id->val_list)
7908  {
7909  if (fetch_val_list (thread_p, llsidp->scan_pred.regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) !=
7910  NO_ERROR)
7911  {
7912  return S_ERROR;
7913  }
7914  }
7915 
7916  scan_id->scan_stats.read_rows++;
7917 
7918  /* evaluate the predicate to see if the tuple qualifies */
7919  ev_res = V_TRUE;
7920  if (llsidp->scan_pred.pr_eval_fnc && llsidp->scan_pred.pred_expr)
7921  {
7922  ev_res = (*llsidp->scan_pred.pr_eval_fnc) (thread_p, llsidp->scan_pred.pred_expr, scan_id->vd, NULL);
7923  if (ev_res == V_ERROR)
7924  {
7925  return S_ERROR;
7926  }
7927  }
7928 
7929  if (scan_id->qualification == QPROC_QUALIFIED)
7930  {
7931  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
7932  {
7933  continue; /* not qualified, continue to the next tuple */
7934  }
7935  }
7936  else if (scan_id->qualification == QPROC_NOT_QUALIFIED)
7937  {
7938  if (ev_res != V_FALSE) /* V_TRUE || V_UNKNOWN */
7939  {
7940  continue; /* qualified, continue to the next tuple */
7941  }
7942  }
7943  else if (scan_id->qualification == QPROC_QUALIFIED_OR_NOT)
7944  {
7945  if (ev_res == V_TRUE)
7946  {
7947  scan_id->qualification = QPROC_QUALIFIED;
7948  }
7949  else if (ev_res == V_FALSE)
7950  {
7952  }
7953  else /* V_UNKNOWN */
7954  {
7955  /* nop */
7956  ;
7957  }
7958  }
7959  else
7960  { /* invalid value; the same as QPROC_QUALIFIED */
7961  if (ev_res != V_TRUE) /* V_FALSE || V_UNKNOWN */
7962  {
7963  continue; /* not qualified, continue to the next tuple */
7964  }
7965  }
7966 
7967  scan_id->scan_stats.qualified_rows++;
7968 
7969  /* fetch the rest of the values from the tuple */
7970  if (scan_id->val_list)
7971  {
7972  if (fetch_val_list (thread_p, llsidp->rest_regu_list, scan_id->vd, NULL, NULL, tplrec.tpl, PEEK) != NO_ERROR)
7973  {
7974  return S_ERROR;
7975  }
7976  }
7977  return S_SUCCESS;
7978  }
7979 
7980  return qp_scan;
7981 }
7982 
7983 /*
7984  * scan_next_hash_list_scan () - The scan is moved to the next hash list scan item.
7985  * return: SCAN_CODE (S_SUCCESS, S_END, S_ERROR)
7986  * scan_id(in/out): Scan identifier
7987  *
7988  * Note: If there are no more scan items, S_END is returned. If an error occurs, S_ERROR is returned.
7989  */
7990 static SCAN_CODE
7991 scan_hash_probe_next (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, QFILE_TUPLE * tuple)
7992 {
7993  LLIST_SCAN_ID *llsidp;
7994  SCAN_CODE qp_scan;
7995  HASH_SCAN_KEY *key;
7996  HASH_SCAN_VALUE *hvalue;
7997  QFILE_LIST_SCAN_ID *scan_id_p;
7998  QFILE_TUPLE_POSITION tuple_pos;
7999  QFILE_TUPLE_SIMPLE_POS *simple_pos;
8000  QFILE_TUPLE_RECORD tplrec = { NULL, 0 };
8001 
8002  llsidp = &scan_id->s.llsid;
8003  key = llsidp->hlsid.temp_key;
8004  scan_id_p = &llsidp->lsid;
8005 
8006  if (scan_id_p->position == S_BEFORE)
8007  {
8008  if (llsidp->hlsid.hash_table->nentries > 0)
8009  {
8010  /* init curr_hash_entry */
8011  llsidp->hlsid.curr_hash_entry = NULL;
8012  /* build key */
8013  if (qdata_build_hscan_key (thread_p, scan_id->vd, llsidp->hlsid.probe_regu_list, key) != NO_ERROR)
8014  {
8015  return S_ERROR;
8016  }
8017 
8018  /* get value from hash table */
8019  hvalue =
8020  (HASH_SCAN_VALUE *) mht_get_hls (llsidp->hlsid.hash_table, key, (void **) &llsidp->hlsid.curr_hash_entry);
8021  if (hvalue == NULL)
8022  {
8023  return S_END;
8024  }
8025  if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_IN_MEM)
8026  {
8027  *tuple = hvalue->tuple;
8028  }
8029  else if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_HYBRID)
8030  {
8031  MAKE_TUPLE_POSTION (tuple_pos, hvalue->pos, scan_id_p);
8032  if (qfile_jump_scan_tuple_position (thread_p, scan_id_p, &tuple_pos, &tplrec, PEEK) != S_SUCCESS)
8033  {
8034  return S_ERROR;
8035  }
8036  *tuple = tplrec.tpl;
8037  }
8038  else
8039  {
8040  return S_ERROR;
8041  }
8042  scan_id_p->position = S_ON;
8043  return S_SUCCESS;
8044  }
8045  else
8046  {
8047  return S_END;
8048  }
8049  }
8050  else if (scan_id_p->position == S_ON)
8051  {
8052  if (llsidp->hlsid.curr_hash_entry->next)
8053  {
8054  llsidp->hlsid.curr_hash_entry = llsidp->hlsid.curr_hash_entry->next;
8055  if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_IN_MEM)
8056  {
8057  *tuple = ((HASH_SCAN_VALUE *) llsidp->hlsid.curr_hash_entry->data)->tuple;
8058  }
8059  else if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_HYBRID)
8060  {
8061  simple_pos = ((HASH_SCAN_VALUE *) llsidp->hlsid.curr_hash_entry->data)->pos;
8062  MAKE_TUPLE_POSTION (tuple_pos, simple_pos, scan_id_p);
8063 
8064  if (qfile_jump_scan_tuple_position (thread_p, scan_id_p, &tuple_pos, &tplrec, PEEK) != S_SUCCESS)
8065  {
8066  return S_ERROR;
8067  }
8068  *tuple = tplrec.tpl;
8069  }
8070  else
8071  {
8072  return S_ERROR;
8073  }
8074  return S_SUCCESS;
8075  }
8076  else
8077  {
8078  if (llsidp->hlsid.hash_list_scan_yn == HASH_METH_HYBRID)
8079  {
8080  qmgr_free_old_page_and_init (thread_p, scan_id_p->curr_pgptr, scan_id_p->list_id.tfile_vfid);
8081  }
8082  scan_id_p->position = S_AFTER;
8083  return S_END;
8084  }
8085  }
8086  else if (scan_id_p->position == S_AFTER)
8087  {
8088  return S_END;
8089  }
8090  else
8091  {
8093  return S_ERROR;
8094  }
8095 
8096  return qp_scan;
8097 }
8098 
8099 /*
8100  * check_hash_list_scan () - Check if hash list scan is possible
8101  * return: int 1: in-memory 2: hybrid in-memory
8102  * llsidp (in): list scan id pointer
8103  * node :
8104  * 1. count of tuple of list file > 0
8105  * 2. list file size check
8106  * 3. regu_list_build, regu_list_probe is not null
8107  * 4. The number of probe regu_var and build regu match
8108  * 5. type of regu var is not oid && vobj
8109  * 6. list file from dptr is not allowed
8110 */
8111 static HASH_METHOD
8112 check_hash_list_scan (LLIST_SCAN_ID * llsidp, int *val_cnt, int hash_list_scan_yn)
8113 {
8114  int build_cnt;
8115  regu_variable_list_node *build, *probe;
8116  DB_TYPE vtype1, vtype2;
8118 
8119  /* no_hash_list_scan sql hint check */
8120  if (hash_list_scan_yn == 0)
8121  {
8122  return HASH_METH_NOT_USE;
8123  }
8124 
8125  /* count of tuple of list file > 0 */
8126  if (llsidp->list_id->tuple_cnt <= 0)
8127  {
8128  return HASH_METH_NOT_USE;
8129  }
8130  /* regu_list_build, regu_list_probe is not null */
8131  if (llsidp->hlsid.build_regu_list == NULL || llsidp->hlsid.probe_regu_list == NULL)
8132  {
8133  return HASH_METH_NOT_USE;
8134  }
8135 
8136  build = llsidp->hlsid.build_regu_list;
8137  probe = llsidp->hlsid.probe_regu_list;
8138 
8139  for (build_cnt = 0; build && probe; build_cnt++)
8140  {
8141  /* type of regu var is not oid && vobj */
8142  /* This is the case when type coercion is impossible. so use list scan */
8143  /* In the list scan, Vobj is converted to oid for comparison at tp_value_compare_with_error(). */
8144  vtype1 = REGU_VARIABLE_GET_TYPE (&probe->value);
8145  vtype2 = REGU_VARIABLE_GET_TYPE (&build->value);
8146 
8147  if (((vtype1 == DB_TYPE_OBJECT || vtype1 == DB_TYPE_VOBJ) && vtype2 == DB_TYPE_OID) ||
8148  ((vtype2 == DB_TYPE_OBJECT || vtype2 == DB_TYPE_VOBJ) && vtype1 == DB_TYPE_OID))
8149  {
8150  return HASH_METH_NOT_USE;
8151  }
8152  if (vtype1 != vtype2)
8153  {
8154  llsidp->hlsid.need_coerce_type = true;
8155  }
8156  build = build->next;
8157  probe = probe->next;
8158  }
8159  /* The number of probe regu_var and build regu match */
8160  if (build != NULL || probe != NULL)
8161  {
8162  return HASH_METH_NOT_USE;
8163  }
8164  *val_cnt = build_cnt;
8165 
8166  /* 6. list file from dptr is not allowed */
8167  /* Since dptr is searched after scan_open_scan, it is checked when llsidp->list_id->tuple_cnt <= 0 */
8168 
8169  /* list file size check */
8170  if ((UINT64) llsidp->list_id->page_cnt * DB_PAGESIZE <= mem_limit)
8171  {
8172  return HASH_METH_IN_MEM;
8173  }
8174  else if ((UINT64) llsidp->list_id->tuple_cnt * (sizeof (HENTRY_HLS) + sizeof (QFILE_TUPLE_SIMPLE_POS)) <= mem_limit)
8175  {
8176  /* bytes of 1 row = sizeof(HENTRY_HLS) + sizeof(QFILE_TUPLE_SIMPLE_POS) = 36 bytes (64bit) */
8177  /* HENTRY_HLS = pointer(8bytes) * 3 = 24 bytes */
8178  /* SIMPLE_POS = pageid(4bytes) + voldid(2bytes) + padding(2bytes) + offset(4bytes) = 12 bytes */
8179  return HASH_METH_HYBRID;
8180  }
8181  else
8182  {
8183  return HASH_METH_NOT_USE;
8184  }
8185 
8186  return HASH_METH_NOT_USE;
8187 }
static void scan_init_scan_attrs(SCAN_ATTRS *scan_attrs_p, int num_attrs, ATTR_ID *attr_ids, HEAP_CACHE_ATTRINFO *attr_cache)
Definition: scan_manager.c:646
QPROC_QUALIFICATION qualification
Definition: scan_manager.h:346
regu_variable_node * set_ptr
Definition: scan_manager.h:280
REGU_VALUES_SCAN_ID rvsid
Definition: scan_manager.h:360
int scan_initialize(void)
regu_variable_node * key1
Definition: access_spec.hpp:67
int btree_coerce_key(DB_VALUE *keyp, int keysize, TP_DOMAIN *btree_domainp, int key_minmax)
Definition: btree.c:14798
unsigned int qdata_hash_scan_key(const void *key, unsigned int ht_size)
char * PAGE_PTR
MIN_MAX_COLUMN_INFO min_max_val
Definition: dbtype_def.h:867
val_descr * vd
Definition: scan_manager.h:350
SCAN_CODE(* QP_SCAN_FUNC)(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
Definition: scan_manager.c:92
int func_index_col_id
Definition: scan_manager.h:135
static int eliminate_duplicated_keys(KEY_VAL_RANGE *key_vals, int key_cnt)
int scan_open_list_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, QFILE_LIST_ID *list_id, regu_variable_list_node *regu_list_pred, PRED_EXPR *pr, regu_variable_list_node *regu_list_rest, regu_variable_list_node *regu_list_build, regu_variable_list_node *regu_list_probe, int hash_list_scan_yn)
int qdata_get_valptr_type_list(THREAD_ENTRY *thread_p, valptr_list_node *valptr_list_p, qfile_tuple_value_type_list *type_list_p)
#define pthread_mutex_lock(a)
Definition: scan_manager.c:56
void mht_destroy_hls(MHT_HLS_TABLE *ht)
Definition: memory_hash.c:1160
bool multi_range_opt
Definition: scan_manager.h:321
HASH_SCAN_VALUE * qdata_alloc_hscan_value(cubthread::entry *thread_p, QFILE_TUPLE tpl)
bool check_not_vacuumed
Definition: scan_manager.h:229
SCAN_CODE heap_scanrange_next(THREAD_ENTRY *thread_p, OID *next_oid, RECDES *recdes, HEAP_SCANRANGE *scan_range, int ispeeking)
Definition: heap_file.c:8481
TP_DOMAIN_STATUS tp_value_coerce(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain)
void * mht_get_hls(const MHT_HLS_TABLE *ht, const void *key, void **last)
Definition: memory_hash.c:1550
static SCAN_CODE scan_next_value_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
SCAN_PRED scan_pred
Definition: scan_manager.h:118
REGU_VALUE_ITEM * regu_list
Definition: regu_var.hpp:105
DB_TYPE REGU_VARIABLE_GET_TYPE(const regu_variable_node *regu)
Definition: regu_var.hpp:271
#define NO_ERROR
Definition: error_code.h:46
RANGE_TYPE range_type
Definition: scan_manager.c:87
SCAN_CODE method_scan_next(THREAD_ENTRY *thread_p, METHOD_SCAN_BUFFER *scan_buffer_p, val_list_node *value_list_p)
Definition: method_scan.c:237
bool caches_inited
Definition: scan_manager.h:219
bool is_btid_int_valid
Definition: btree.h:242
ATTR_ID * btree_attr_ids
MVCC_SNAPSHOT * logtb_get_mvcc_snapshot(THREAD_ENTRY *thread_p)
regu_variable_list_node * rest_regu_list
Definition: scan_manager.h:252
#define pgbuf_ordered_fix(thread_p, req_vpid, fetch_mode, requestmode, req_watcher)
Definition: page_buffer.h:261
DB_VALUE ** key_info_values
Definition: scan_manager.h:227
void scan_init_filter_info(FILTER_INFO *filter_info_p, SCAN_PRED *scan_pred, SCAN_ATTRS *scan_attrs, val_list_node *val_list, VAL_DESCR *val_descr, OID *class_oid, int btree_num_attrs, ATTR_ID *btree_attr_ids, int *num_vstr_ptr, ATTR_ID *vstr_ids)
Definition: scan_manager.c:660
METHOD_SCAN_BUFFER scan_buf
Definition: scan_manager.h:291
static SCAN_CODE scan_next_index_lookup_heap(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, INDX_SCAN_ID *isidp, FILTER_INFO *data_filter, TRAN_ISOLATION isolation)
HASH_SCAN_KEY * qdata_alloc_hscan_key(cubthread::entry *thread_p, int val_cnt, bool alloc_vals)
QFILE_TUPLE_POSITION ls_tplpos
Definition: scan_manager.h:300
key_range * key_ranges
Definition: access_spec.hpp:75
REGU_VARIABLE_LIST operand
Definition: regu_var.hpp:143
DB_MIDXKEY * db_get_midxkey(const DB_VALUE *value)
BTREE_ISCAN_OID_LIST * next_list
Definition: btree.h:343
#define IO_PAGESIZE
LLIST_SCAN_ID llsid
Definition: scan_manager.h:353
SHOWSTMT_SCAN_ID stsid
Definition: scan_manager.h:361
SCAN_OPERATION_TYPE scan_op_type
Definition: scan_manager.h:337
DB_VALUE_COMPARE_RESULT tp_value_compare(const DB_VALUE *value1, const DB_VALUE *value2, int allow_coercion, int total_order)
struct qmgr_temp_file * tfile_vfid
Definition: query_list.h:440
bool use_desc_index
Definition: btree.h:198
regu_variable_node * key_limit_u
Definition: access_spec.hpp:81
BTID * sys_btid
Definition: btree.h:121
#define ASSERT_ERROR()
SCAN_CODE
SCAN_ATTRS pred_attrs
Definition: scan_manager.h:102
SCAN_CODE heap_scanrange_to_prior(THREAD_ENTRY *thread_p, HEAP_SCANRANGE *scan_range, OID *last_oid)
Definition: heap_file.c:8375
static void scan_free_oid_list(BTREE_ISCAN_OID_LIST *oid_list_p)
Definition: scan_manager.c:985
#define IDX_COV_DEFAULT_TUPLES
Definition: scan_manager.h:73
QFILE_TUPLE_VALUE_TYPE_LIST type_list
Definition: query_list.h:428
bool caches_inited
Definition: scan_manager.h:105
void end(cubthread::entry *thread_p)
DB_BIGINT key_limit_lower
Definition: scan_manager.h:222
REGU_DATATYPE type
Definition: regu_var.hpp:172
ATTR_ID * attr_ids
RANGE_TYPE
QFILE_LIST_ID * list_id
Definition: scan_manager.h:249
#define ISCAN_OID_BUFFER_COUNT
#define QFILE_FREE_AND_INIT_LIST_ID(list_id)
Definition: list_file.h:56
valptr_list_node * output_val_list
Definition: scan_manager.h:131
static int scan_save_range_details(INDX_SCAN_ID *isidp_src, ISS_RANGE_DETAILS *rdp_dest)
Definition: scan_manager.c:312
SCAN_TYPE type
Definition: scan_manager.h:332
HASH_SCAN_KEY * qdata_copy_hscan_key_without_alloc(cubthread::entry *thread_p, HASH_SCAN_KEY *key, REGU_VARIABLE_LIST probe_regu_list, HASH_SCAN_KEY *new_key)
void LSA_COPY(log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:139
QFILE_TUPLE_VALUE_TYPE_LIST * type_list
Definition: scan_manager.h:127
SCAN_CODE heap_get_visible_version(THREAD_ENTRY *thread_p, const OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, int old_chn)
Definition: heap_file.c:24272
DB_VALUE ** cache_page_info
Definition: scan_manager.h:119
SCAN_PRED * scan_pred
HASH_SCAN_VALUE * qdata_alloc_hscan_value_OID(cubthread::entry *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
VA_SCAN_ID vaid
Definition: scan_manager.h:359
QFILE_TUPLE_SIMPLE_POS * pos
int val_cnt
Definition: xasl.h:208
KEY_RANGE * key_ranges
Definition: scan_manager.c:85
int ils_prefix_len
QPROC_SINGLE_FETCH
Definition: query_list.h:326
void qdata_free_hscan_key(cubthread::entry *thread_p, HASH_SCAN_KEY *key, int val_count)
DB_TYPE
Definition: dbtype_def.h:670
int scan_open_heap_page_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, val_list_node *val_list, VAL_DESCR *vd, OID *cls_oid, HFID *hfid, PRED_EXPR *pr, SCAN_TYPE scan_type, DB_VALUE **cache_page_info, regu_variable_list_node *regu_list_page_info)
#define ER_FAILED
Definition: error_code.h:47
TYPE_EVAL_TERM et_type
BTREE_ROOT_HEADER * btree_get_root_header(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr)
Definition: btree_load.c:309
REGU_VARIABLE_LIST next
Definition: regu_var.hpp:221
bool mvcc_is_mvcc_disabled_class(const OID *class_oid)
Definition: mvcc.c:616
int data_qualified_rows
Definition: scan_manager.h:318
struct tp_domain * setdomain
Definition: object_domain.h:82
SCAN_CODE qfile_scan_list_next(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_RECORD *tuple_record_p, int peek)
Definition: list_file.c:4724
#define SCAN_IS_INDEX_COVERED(iscan_id_p)
Definition: scan_manager.h:369
UINT64 num_fetches
Definition: scan_manager.h:307
void set_filters(upddel_mvcc_cond_reeval &ureev)
bool * is_desc_order
Definition: scan_manager.h:156
int orderby_desc
Definition: access_spec.hpp:92
#define OR_BUF_INIT(buf, data, size)
MULTI_RANGE_OPT multi_range_opt
Definition: scan_manager.h:225
#define ER_QPROC_INVALID_XASLNODE
Definition: error_code.h:532
SCAN_ATTRS range_attrs
Definition: scan_manager.h:212
static int check_key_vals(KEY_VAL_RANGE *key_vals, int key_cnt, QPROC_KEY_VAL_FU *chk_fn)
int qualified_rows
Definition: scan_manager.h:312
int btree_glean_root_header_info(THREAD_ENTRY *thread_p, BTREE_ROOT_HEADER *root_header, BTID_INT *btid)
Definition: btree.c:5797
int btree_attrinfo_read_dbvalues(THREAD_ENTRY *thread_p, DB_VALUE *curr_key, int *btree_att_ids, int btree_num_att, HEAP_CACHE_ATTRINFO *attr_info, int func_index_col_id)
Definition: btree.c:15938
void set_value_descriptor(val_descr *vd)
#define assert_release(e)
Definition: error_manager.h:96
bool covered_index
Definition: scan_manager.h:320
void scan_init_index_scan(INDX_SCAN_ID *isidp, struct btree_iscan_oid_list *oid_list, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: scan_manager.c:283
int fetch_copy_dbval(THREAD_ENTRY *thread_p, REGU_VARIABLE *regu_var, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, DB_VALUE *dbval)
Definition: fetch.c:4466
DB_BIGINT key_limit_upper
Definition: scan_manager.h:223
union regu_variable_node::regu_data_value value
bool index_skip_scan
Definition: scan_manager.h:322
int lock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, int cond_flag)
SCAN_CODE locator_lock_and_get_object_with_evaluation(THREAD_ENTRY *thread_p, OID *oid, OID *class_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, int old_chn, MVCC_REEV_DATA *mvcc_reev_data, NON_EXISTENT_HANDLING non_ex_handling_type)
Definition: locator_sr.c:13034
#define ER_LC_INCONSISTENT_BTREE_ENTRY_TYPE2
Definition: error_code.h:639
QFILE_TUPLE_RECORD * tplrec
Definition: scan_manager.h:128
int qualified_keys
Definition: scan_manager.h:316
void set_scan_reevaluation(mvcc_scan_reev_data &scan)
bool oid_is_serial(const OID *oid)
Definition: oid.c:159
struct timeval TSCTIMEVAL
Definition: tsc_timer.h:40
#define OID_SET_NULL(oidp)
Definition: oid.h:85
int tp_value_coerce_strict(const DB_VALUE *src, DB_VALUE *dest, const TP_DOMAIN *desired_domain)
#define GET_NTH_OID(oid_setp, n)
Definition: scan_manager.c:73
DB_LOGICAL(* PR_EVAL_FNC)(THREAD_ENTRY *thread_p, const PRED_EXPR *, val_descr *, OID *)
DISK_ISVALID not_vacuumed_res
Definition: scan_manager.h:231
SCAN_CODE qproc_next_set_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
Definition: set_scan.c:44
TP_DOMAIN * tp_domain_resolve_value(const DB_VALUE *val, TP_DOMAIN *dbuf)
DB_VALUE ** cache_recordinfo
Definition: scan_manager.h:108
char * data
int groupby_desc
Definition: access_spec.hpp:93
static SCAN_CODE scan_next_json_table_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
static SCAN_CODE scan_hash_probe_next(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, QFILE_TUPLE *tuple)
#define TP_IS_STRING_TYPE(typeid)
void tsc_elapsed_time_usec(TSCTIMEVAL *tv, TSC_TICKS end_tick, TSC_TICKS start_tick)
Definition: tsc_timer.c:101
static int scan_alloc_oid_list(BTREE_ISCAN_OID_LIST **oid_list_p)
Definition: scan_manager.c:946
TP_DOMAIN * tp_domain_copy(const TP_DOMAIN *domain, bool check_cache)
int32_t pageid
Definition: dbtype_def.h:879
INT32 root_pageid
int mht_dump_hls(THREAD_ENTRY *thread_p, FILE *out_fp, const MHT_HLS_TABLE *ht, const int print_id_opt, int(*print_func)(THREAD_ENTRY *thread_p, FILE *fp, const void *data, void *args), void *func_args)
Definition: memory_hash.c:1369
#define MAX_NTRANS
BTID_INT btid_int
Definition: btree.h:391
int er_errid(void)
int qdata_copy_valptr_list_to_tuple(THREAD_ENTRY *thread_p, valptr_list_node *valptr_list_p, val_descr *val_desc_p, qfile_tuple_record *tuple_record_p)
Definition: query_opfunc.c:434
void qdata_set_value_list_to_null(val_list_node *val_list_p)
Definition: query_opfunc.c:280
#define OR_MULTI_BOUND_BIT_BYTES(count)
static int scan_dbvals_to_midxkey(THREAD_ENTRY *thread_p, DB_VALUE *retval, bool *indexal, TP_DOMAIN *btree_domainp, int num_term, REGU_VARIABLE *func, VAL_DESCR *vd, int key_minmax, bool is_iss, DB_VALUE *fetched_values)
void scan_end_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
int qdata_free_hscan_entry(const void *key, void *data, void *args)
static void resolve_domain_on_regu_operand(REGU_VARIABLE *regu_var, val_list_node *ref_val_list, QFILE_TUPLE_VALUE_TYPE_LIST *p_type_list)
RANGE_OPT_ITEM ** buffer
Definition: scan_manager.h:161
SHOWSTMT_TYPE
static SCAN_CODE scan_next_class_attr_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
void lock_unlock_object_donot_move_to_non2pl(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock)
int QPROC_KEY_VAL_FU(KEY_VAL_RANGE *key_vals, int key_cnt)
Definition: scan_manager.c:91
TRAN_ISOLATION logtb_find_isolation(int tran_index)
static int scan_init_index_key_limit(THREAD_ENTRY *thread_p, INDX_SCAN_ID *isidp, KEY_INFO *key_infop, VAL_DESCR *vd)
Definition: scan_manager.c:818
bool thread_is_on_trace(cubthread::entry *thread_p)
enum tp_domain_status TP_DOMAIN_STATUS
static void rop_to_range(RANGE *range, ROP_TYPE left, ROP_TYPE right)
bool heap_does_exist(THREAD_ENTRY *thread_p, OID *class_oid, const OID *oid)
Definition: heap_file.c:8714
key_val_range * key_vals
Definition: scan_manager.h:215
static void resolve_domains_on_list_scan(LLIST_SCAN_ID *llsidp, val_list_node *ref_val_list)
int heap_scancache_end(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7195
regu_variable_node * lhs
bool mvcc_select_lock_needed
Definition: scan_manager.h:336
INDX_COV indx_cov
Definition: scan_manager.h:224
ATTR_ID * vstr_ids
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
#define DBVAL_BUFSIZE
Definition: btree.h:449
int btree_range_scan_select_visible_oids(THREAD_ENTRY *thread_p, BTREE_SCAN *bts)
Definition: btree.c:25122
SCAN_ATTRS key_attrs
Definition: scan_manager.h:208
int scan_open_index_key_info_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, val_list_node *val_list, VAL_DESCR *vd, indx_info *indx_info, OID *cls_oid, HFID *hfid, PRED_EXPR *pr, valptr_list_node *output_val_list, bool iscan_oid_order, QUERY_ID query_id, DB_VALUE **key_info_values, regu_variable_list_node *key_info_regu_list)
SCAN_CODE heap_next_record_info(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *next_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, DB_VALUE **cache_recordinfo)
Definition: heap_file.c:18648
void THREAD_ENTRY
mht_hls_table * hash_table
#define pgbuf_unfix_and_init(thread_p, pgptr)
Definition: page_buffer.h:63
static SCAN_CODE scan_next_heap_page_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
DB_VALUE * val
Definition: xasl.h:196
static void scan_init_scan_id(SCAN_ID *scan_id, bool force_select_lock, SCAN_OPERATION_TYPE scan_op_type, int fixed, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd)
int ATTR_ID
int read_keys
Definition: btree.h:204
#define ER_QPROC_INVALID_CRSPOS
Definition: error_code.h:520
LOCK
RANGE range
Definition: access_spec.hpp:69
MIN_MAX_COLUMN_TYPE type
Definition: dbtype_def.h:857
KEY_INFO key_info
Definition: access_spec.hpp:91
int heap_scancache_start(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid, const OID *class_oid, int cache_last_fix_page, int is_indexscan, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: heap_file.c:6833
regu_variable_list_node * regu_list
Definition: scan_manager.h:273
#define MAKE_TUPLE_POSTION(tuple_pos, simple_pos, scan_id_p)
UINT64 prm_get_bigint_value(PARAM_ID prm_id)
#define BTREE_NODE_SCAN_INIT(bns)
Definition: btree.h:401
DB_DATA data
Definition: dbtype_def.h:1083
BTREE_TYPE bt_type
Definition: scan_manager.h:189
enum hash_method HASH_METHOD
void qfile_end_scan_fix(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4752
static int scan_dump_key_into_tuple(THREAD_ENTRY *thread_p, INDX_SCAN_ID *iscan_id, DB_VALUE *key, OID *oid, QFILE_TUPLE_RECORD *tplrec)
int heap_attrinfo_start(THREAD_ENTRY *thread_p, const OID *class_oid, int requested_num_attrs, const ATTR_ID *attrids, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9427
static SCAN_CODE scan_next_index_key_info_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
#define RECDES_INITIALIZER
int qmgr_get_temp_file_membuf_pages(QMGR_TEMP_FILE *temp_file_p)
TP_DOMAIN * tp_domain_resolve_default(DB_TYPE type)
SCAN_POSITION position
Definition: query_list.h:499
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
SCAN_CODE scan_reset_scan_block(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
INDEX_NODE_SCAN_ID insid
Definition: scan_manager.h:357
int part_key_desc
Definition: btree.h:123
QPROC_QUALIFICATION * qualification
KEY_RANGE iss_range
Definition: access_spec.hpp:99
ATTR_ID * bt_attr_ids
Definition: scan_manager.h:191
#define ER_QPROC_INVALID_PARAMETER
Definition: error_code.h:963
#define TO_MSEC(elapsed)
SCAN_CODE qfile_scan_list_prev(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_RECORD *tuple_record_p, int peek)
Definition: list_file.c:4738
static int scan_regu_key_to_index_key(THREAD_ENTRY *thread_p, KEY_RANGE *key_ranges, KEY_VAL_RANGE *key_val_range, INDX_SCAN_ID *iscan_id, TP_DOMAIN *btree_domainp, VAL_DESCR *vd)
#define assert(x)
int qdata_print_hash_scan_entry(THREAD_ENTRY *thread_p, FILE *fp, const void *data, void *args)
BTREE_SCAN bt_scan
Definition: scan_manager.h:195
SCAN_CODE heap_page_prev(THREAD_ENTRY *thread_p, const OID *class_oid, const HFID *hfid, VPID *prev_vpid, DB_VALUE **cache_pageinfo)
Definition: heap_file.c:18372
#define DB_NEED_CLEAR(v)
Definition: dbtype.h:83
HEAP_SCANCACHE scan_cache
Definition: scan_manager.h:99
BTREE_NODE_HEADER node
Definition: btree_load.h:207
int scan_open_showstmt_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, PRED_EXPR *pr, SHOWSTMT_TYPE show_type, regu_variable_list_node *arg_list)
char * copy_buf
Definition: scan_manager.h:200
SCAN_ATTRS pred_attrs
Definition: scan_manager.h:210
int32_t fileid
Definition: dbtype_def.h:886
bool pgbuf_check_page_ptype(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, PAGE_TYPE ptype)
#define OR_ENABLE_BOUND_BIT(bitptr, element)
key_range * skipped_range
Definition: scan_manager.h:182
regu_variable_list_node * key_info_regu_list
Definition: scan_manager.h:228
HENTRY_HLS_PTR curr_hash_entry
#define ER_GENERIC_ERROR
Definition: error_code.h:49
int heap_scanrange_start(THREAD_ENTRY *thread_p, HEAP_SCANRANGE *scan_range, const HFID *hfid, const OID *class_oid, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: heap_file.c:8203
#define SCAN_ISCAN_OID_BUF_LIST_DEFAULT_SIZE
Definition: scan_manager.c:139
#define OID_IS_ROOTOID(oidp)
Definition: oid.h:82
LOG_LSA * pgbuf_get_lsa(PAGE_PTR pgptr)
Definition: page_buffer.c:4318
bool scan_immediately_stop
Definition: scan_manager.h:366
#define pthread_mutex_unlock(a)
Definition: scan_manager.c:57
int tp_domain_status_er_set(TP_DOMAIN_STATUS status, const char *file_name, const int line_no, const DB_VALUE *src, const TP_DOMAIN *domain)
static SCAN_CODE scan_next_scan_local(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
OBJECT_GET_STATUS
int scan_open_method_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, QFILE_LIST_ID *list_id, method_sig_list *meth_sig_list)
void scan_save_scan_pos(SCAN_ID *s_id, SCAN_POS *scan_pos)
void qfile_destroy_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:2163
static int scan_Iscan_oid_buf_list_count
Definition: scan_manager.c:137
regu_variable_list_node * regu_list
comp_eval_term et_comp
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
PAGE_PTR curr_pgptr
Definition: query_list.h:501
REGU_VARIABLE value
Definition: regu_var.hpp:222
QFILE_LIST_SCAN_ID lsid
Definition: scan_manager.h:250
BTID_INT btid_int
Definition: btree.h:165
DB_VALUE * join_dbval
Definition: scan_manager.h:347
hash_scan_key * temp_new_key
SCAN_STATUS status
Definition: scan_manager.h:298
#define UT_CAST_TO_NULL_HEAP_OID(hfidp, oidp)
Definition: scan_manager.c:64
TRAN_ISOLATION logtb_find_current_isolation(THREAD_ENTRY *thread_p)
unsigned is_desc
union cubxasl::pred_expr::@185 pe
int fetch_peek_dbval(THREAD_ENTRY *thread_p, REGU_VARIABLE *regu_var, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, DB_VALUE **peek_dbval)
Definition: fetch.c:3773
RANGE_OPT_ITEM ** top_n_items
Definition: scan_manager.h:160
SCAN_PRED key_pred
Definition: scan_manager.c:86
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
#define DB_INT32_MAX
Definition: dbtype_def.h:633
int orderby_skip
Definition: access_spec.hpp:95
int scan_open_set_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, REGU_VARIABLE *set_ptr, regu_variable_list_node *regu_list_pred, PRED_EXPR *pr)
PRED_EXPR * pred_expr
struct function_node * funcp
Definition: regu_var.hpp:190
void qfile_save_current_scan_tuple_position(QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_POSITION *tuple_position_p)
Definition: list_file.c:4478
SCAN_PRED scan_pred
Definition: scan_manager.h:267
DB_TRAN_ISOLATION
Definition: dbtran_def.h:26
BTREE_NODE_SCAN btns
Definition: scan_manager.h:240
regu_variable_list_node * regu_val_list
Definition: scan_manager.h:132
int lock_hold_object_instant(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock)
struct timeval elapsed_hash_build
Definition: scan_manager.h:326
int n_oids_read_last_iteration
Definition: btree.h:232
int scan_open_class_attr_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, OID *cls_oid, HFID *hfid, regu_variable_list_node *regu_list_pred, PRED_EXPR *pr, regu_variable_list_node *regu_list_rest, int num_attrs_pred, ATTR_ID *attrids_pred, HEAP_CACHE_ATTRINFO *cache_pred, int num_attrs_rest, ATTR_ID *attrids_rest, HEAP_CACHE_ATTRINFO *cache_rest)
short volid
Definition: dbtype_def.h:880
bool scancache_inited
Definition: scan_manager.h:220
struct rop_range_struct rop_range_table[]
REGU_VALUE_ITEM * next
Definition: regu_var.hpp:97
SCAN_CODE scan_next_scan_block(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
int heap_attrinfo_read_dbvalues(THREAD_ENTRY *thread_p, const OID *inst_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10337
#define TP_DOMAIN_TYPE(dom)
static void range_to_rop(ROP_TYPE *left, ROP_TYPE *rightk, RANGE range)
SCAN_CODE qfile_jump_scan_tuple_position(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p, QFILE_TUPLE_POSITION *tuple_position_p, QFILE_TUPLE_RECORD *tuple_record_p, int peek)
Definition: list_file.c:4552
hash_scan_key * temp_key
#define BTREE_RESET_SCAN(bts)
Definition: btree.h:299
SCAN_CODE btree_get_next_node_info(THREAD_ENTRY *thread_p, BTID *btid, BTREE_NODE_SCAN *btns, DB_VALUE **node_info)
Definition: btree.c:20162
HEAP_SCAN_ID hsid
Definition: scan_manager.h:354
int scan_open_values_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, valptr_list_node *valptr_list)
VAL_DESCR * val_descr
Definition: scan_manager.h:130
#define NULL
Definition: freelistheap.h:34
int db_string_truncate(DB_VALUE *value, const int precision)
Definition: db_macro.c:962
int groupby_skip
Definition: access_spec.hpp:96
#define ER_QPROC_UNKNOWN_CRSPOS
Definition: error_code.h:522
FUNC_TYPE ftype
Definition: regu_var.hpp:144
struct pr_type * type
Definition: object_domain.h:76
DB_CHAR ch
Definition: dbtype_def.h:1070
SCAN_ATTRS * scan_attrs
HEAP_SCANCACHE scan_cache
Definition: scan_manager.h:206
int scan_init_iss(INDX_SCAN_ID *isidp)
Definition: scan_manager.c:214
void tsc_getticks(TSC_TICKS *tck)
Definition: tsc_timer.c:81
static SCAN_CODE scan_next_method_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
regu_variable_node * rhs
VFID vfid
static int scan_init_indx_coverage(THREAD_ENTRY *thread_p, int coverage_enabled, valptr_list_node *output_val_list, regu_variable_list_node *regu_val_list, VAL_DESCR *vd, QUERY_ID query_id, int max_key_len, int func_index_col_id, INDX_COV *indx_cov)
Definition: scan_manager.c:691
TP_DOMAIN * tp_domain_cache(TP_DOMAIN *transient)
#define err(fd,...)
Definition: porting.h:431
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
HENTRY_HLS_PTR next
Definition: memory_hash.h:141
void PRIM_SET_NULL(DB_VALUE *value)
const void * mht_put_hls(MHT_HLS_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1730
int scan_open_index_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, bool mvcc_select_lock_needed, SCAN_OPERATION_TYPE scan_op_type, int fixed, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, indx_info *indx_info, OID *cls_oid, HFID *hfid, regu_variable_list_node *regu_list_key, PRED_EXPR *pr_key, regu_variable_list_node *regu_list_pred, PRED_EXPR *pr, regu_variable_list_node *regu_list_rest, PRED_EXPR *pr_range, regu_variable_list_node *regu_list_range, valptr_list_node *output_val_list, regu_variable_list_node *regu_val_list, int num_attrs_key, ATTR_ID *attrids_key, HEAP_CACHE_ATTRINFO *cache_key, int num_attrs_pred, ATTR_ID *attrids_pred, HEAP_CACHE_ATTRINFO *cache_pred, int num_attrs_rest, ATTR_ID *attrids_rest, HEAP_CACHE_ATTRINFO *cache_rest, int num_attrs_range, ATTR_ID *attrids_range, HEAP_CACHE_ATTRINFO *cache_range, bool iscan_oid_order, QUERY_ID query_id)
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
#define ISCAN_OID_BUFFER_CAPACITY
unsigned char is_max_string
Definition: dbtype_def.h:981
SCAN_POSITION position
Definition: scan_manager.h:334
DB_VALUE set
Definition: scan_manager.h:282
int btree_prepare_bts(THREAD_ENTRY *thread_p, BTREE_SCAN *bts, BTID *btid, INDX_SCAN_ID *index_scan_id_p, key_val_range *kv_range, FILTER_INFO *filter, const OID *match_class_oid, DB_BIGINT *key_limit_upper, DB_BIGINT *key_limit_lower, bool need_to_check_null, void *bts_other)
Definition: btree.c:15049
bool loose_index_scan
Definition: scan_manager.h:323
SCAN_OPERATION_TYPE
SCAN_STATUS status
Definition: scan_manager.h:333
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
PGBUF_WATCHER page_watcher
Definition: heap_file.h:149
SCAN_CODE scan_jump_scan_pos(THREAD_ENTRY *thread_p, SCAN_ID *s_id, SCAN_POS *scan_pos)
int func_idx_col_id
Definition: access_spec.hpp:98
int pr_midxkey_get_element_nocopy(const DB_MIDXKEY *midxkey, int index, DB_VALUE *value, int *prev_indexp, char **prev_ptrp)
QFILE_LIST_SCAN_ID * lsid
Definition: scan_manager.h:129
INDX_INFO * indx_info
Definition: scan_manager.h:188
need_clear_type need_clear
Definition: dbtype_def.h:1084
REGU_VALUE_ITEM * current_value
Definition: regu_var.hpp:106
val_list_node * val_list
void btree_scan_clear_key(BTREE_SCAN *btree_scan)
Definition: btree.c:6035
SCAN_DIRECTION direction
Definition: scan_manager.h:335
SHOWSTMT_TYPE show_type
Definition: scan_manager.h:260
TP_DOMAIN ** sort_col_dom
Definition: scan_manager.h:159
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
int max_tuples
Definition: scan_manager.h:134
int pr_clear_value(DB_VALUE *value)
int qfile_open_list_scan(QFILE_LIST_ID *list_id_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4658
void heap_scanrange_end(THREAD_ENTRY *thread_p, HEAP_SCANRANGE *scan_range)
Definition: heap_file.c:8238
SCAN_CODE heap_scanrange_to_following(THREAD_ENTRY *thread_p, HEAP_SCANRANGE *scan_range, OID *start_oid)
Definition: heap_file.c:8265
DB_BIGINT db_get_bigint(const DB_VALUE *value)
QFILE_TUPLE_RECORD tplrec
Definition: scan_manager.h:158
void pgbuf_get_vpid(PAGE_PTR pgptr, VPID *vpid)
Definition: page_buffer.c:4579
SCAN_PRED scan_pred
Definition: scan_manager.h:285
DB_LOGICAL update_logical_result(THREAD_ENTRY *thread_p, DB_LOGICAL ev_res, int *qualification)
int scan_open_json_table_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, PRED_EXPR *pr)
int64_t DB_BIGINT
Definition: dbtype_def.h:751
UINT64 num_ioreads
Definition: scan_manager.h:308
bool scancache_inited
Definition: scan_manager.h:106
#define OR_CLEAR_BOUND_BIT(bitptr, element)
regu_variable_list_node * operand
Definition: scan_manager.h:281
bool scanrange_inited
Definition: scan_manager.h:107
#define CAST_BUFLEN
Definition: porting.h:471
int ncolumns
Definition: dbtype_def.h:864
HASH_LIST_SCAN hlsid
Definition: scan_manager.h:254
#define TP_IS_CHAR_TYPE(typeid)
DB_VALUE index_value
Definition: scan_manager.h:144
regu_variable_list_node * rest_regu_list
Definition: scan_manager.h:213
int showstmt_start_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
Definition: show_scan.c:283
int fetch_val_list(THREAD_ENTRY *thread_p, regu_variable_list_node *regu_list, val_descr *vd, OID *class_oid, OID *obj_oid, QFILE_TUPLE tpl, int peek)
Definition: fetch.c:4526
static void error(const char *msg)
Definition: gencat.c:331
static int rv
Definition: scan_manager.c:58
INDX_INFO * indx_info
Definition: scan_manager.h:238
void scan_close_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
static int rc
Definition: serial.c:50
STATIC_INLINE void perfmon_inc_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid) __attribute__((ALWAYS_INLINE))
static int scan_alloc_iscan_oid_buf_list(BTREE_ISCAN_OID_LIST **oid_list)
SCAN_PRED scan_pred
Definition: scan_manager.h:209
static SCAN_CODE scan_next_hash_list_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
static void scan_init_scan_pred(SCAN_PRED *scan_pred_p, regu_variable_list_node *regu_list, PRED_EXPR *pred_expr, PR_EVAL_FNC pr_eval_fnc)
Definition: scan_manager.c:631
TP_DOMAIN * tp_domain_construct(DB_TYPE domain_type, DB_OBJECT *class_obj, int precision, int scale, TP_DOMAIN *setdomain)
void qfile_close_scan(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4774
int db_make_midxkey(DB_VALUE *value, DB_MIDXKEY *midxkey)
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
val_list_node * val_list
Definition: scan_manager.h:349
#define ARG_FILE_LINE
Definition: error_manager.h:44
#define TSC_ADD_TIMEVAL(total, diff)
Definition: tsc_timer.h:31
QFILE_TUPLE_RECORD * tplrecp
Definition: scan_manager.h:253
QFILE_LIST_ID list_id
Definition: query_list.h:507
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
static const bool COPY
PR_EVAL_FNC eval_fnc(THREAD_ENTRY *thread_p, const PRED_EXPR *pr, DB_TYPE *single_node_type)
static SCAN_CODE scan_next_index_node_info_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
unsigned int nentries
Definition: memory_hash.h:155
PR_EVAL_FNC pr_eval_fnc
regu_variable_node * key2
Definition: access_spec.hpp:68
int key_qualified_rows
Definition: scan_manager.h:317
static SCAN_CODE scan_prev_scan_local(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
int qfile_start_scan_fix(THREAD_ENTRY *thread_p, QFILE_LIST_SCAN_ID *scan_id_p)
Definition: list_file.c:4628
bool key_limit_reset
Definition: access_spec.hpp:78
DB_VALUE * fetched_values
Definition: scan_manager.h:232
void * data
Definition: memory_hash.h:142
MVCC_SNAPSHOT * mvcc_snapshot
Definition: heap_file.h:154
regu_variable_list_node * recordinfo_regu_list
Definition: scan_manager.h:109
SCAN_PRED range_pred
Definition: scan_manager.h:211
int btree_range_scan(THREAD_ENTRY *thread_p, BTREE_SCAN *bts, BTREE_RANGE_SCAN_PROCESS_KEY_FUNC *key_func)
Definition: btree.c:24922
RANGE_TYPE range_type
Definition: access_spec.hpp:90
#define free_and_init(ptr)
Definition: memory_alloc.h:147
bool is_user_given_keylimit
Definition: access_spec.hpp:79
static SCAN_CODE scan_next_index_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
static void scan_free_iscan_oid_buf_list(BTREE_ISCAN_OID_LIST *oid_list)
int oid_compare(const void *a, const void *b)
Definition: oid.c:243
SCAN_CODE scan_prev_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
SCAN_ATTRS rest_attrs
Definition: scan_manager.h:214
int * bt_attrs_prefix_length
Definition: scan_manager.h:192
int mht_clear_hls(MHT_HLS_TABLE *ht, int(*rem_func)(const void *key, void *data, void *args), void *func_args)
Definition: memory_hash.c:1238
DB_DOMAIN * domain
Definition: dbtype_def.h:865
SCAN_STATS scan_stats
Definition: scan_manager.h:365
int scan_open_index_node_info_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, val_list_node *val_list, VAL_DESCR *vd, indx_info *indx_info, PRED_EXPR *pr, DB_VALUE **node_info_values, regu_variable_list_node *node_info_regu_list)
#define DB_PAGESIZE
SCAN_STATUS status
Definition: query_list.h:498
INDEX_SKIP_SCAN iss
Definition: scan_manager.h:226
HEAP_PAGE_SCAN_ID hpsid
Definition: scan_manager.h:355
#define ER_HEAP_UNKNOWN_OBJECT
Definition: error_code.h:102
QPROC_DB_VALUE_LIST valp
Definition: xasl.h:207
regu_variable_list_node * page_info_regu_list
Definition: scan_manager.h:120
#define BTREE_END_OF_SCAN(bts)
Definition: btree.h:317
char * QFILE_TUPLE
Definition: query_list.h:281
regu_variable_list_node * rest_regu_list
Definition: scan_manager.h:103
DB_LOGICAL
Definition: dbtype_def.h:1218
bool prm_get_bool_value(PARAM_ID prm_id)
int showstmt_end_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
Definition: show_scan.c:309
#define QSTR_IS_ANY_CHAR_OR_BIT(s)
Definition: string_opfunc.h:47
int pgbuf_page_has_changed(PAGE_PTR pgptr, LOG_LSA *ref_lsa)
Definition: page_buffer.c:4342
class regu_variable_node REGU_VARIABLE
Definition: regu_var.hpp:64
SCAN_CODE heap_prev(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *next_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking)
Definition: heap_file.c:18671
regu_variable_list_node * probe_regu_list
union scan_id_struct::@153 s
SCAN_TYPE
Definition: scan_manager.h:75
void er_clear(void)
static ROP_TYPE compare_val_op(DB_VALUE *val1, ROP_TYPE op1, DB_VALUE *val2, ROP_TYPE op2, int num_index_term)
static BTREE_ISCAN_OID_LIST * scan_Iscan_oid_buf_list
Definition: scan_manager.c:136
bool iscan_oid_order
Definition: scan_manager.h:217
int scan_start_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
int next_scan(cubthread::entry *thread_p, scan_id_struct &sid, SCAN_CODE &sc)
MHT_HLS_TABLE * mht_create_hls(const char *name, int est_size, unsigned int(*hash_func)(const void *key, unsigned int ht_size), int(*cmp_func)(const void *key1, const void *key2))
Definition: memory_hash.c:982
int qdata_hscan_key_eq(const void *key1, const void *key2)
void scan_finalize(void)
QFILE_LIST_ID * qfile_open_list(THREAD_ENTRY *thread_p, QFILE_TUPLE_VALUE_TYPE_LIST *type_list_p, SORT_LIST *sort_list_p, QUERY_ID query_id, int flag)
Definition: list_file.c:1142
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
int i
Definition: dynamic_load.c:954
bool need_count_only
Definition: scan_manager.h:218
int db_make_null(DB_VALUE *value)
int qualified_keys
Definition: btree.h:205
void qfile_close_list(THREAD_ENTRY *thread_p, QFILE_LIST_ID *list_id_p)
Definition: list_file.c:1263
static int reverse_key_list(KEY_VAL_RANGE *key_vals, int key_cnt)
#define DB_IS_NULL(value)
Definition: dbtype.h:63
SCAN_PRED scan_pred
Definition: scan_manager.h:101
static const int rop_range_table_size
Definition: scan_manager.c:130
DB_LOGICAL eval_data_filter(THREAD_ENTRY *thread_p, OID *oid, RECDES *recdesp, HEAP_SCANCACHE *scan_cache, FILTER_INFO *filterp)
struct tp_domain * next
Definition: object_domain.h:74
QPROC_DB_VALUE_LIST next
Definition: xasl.h:195
regu_variable_list_node * build_regu_list
bool qdata_copy_db_value(DB_VALUE *dest_p, const DB_VALUE *src_p)
Definition: query_opfunc.c:310
heap_cache_attrinfo * attr_cache
TYPE_PRED_EXPR type
DB_VALUE ** node_info_values
Definition: scan_manager.h:242
SCAN_PRED key_pred
Definition: scan_manager.h:207
HEAP_SCANRANGE scan_range
Definition: scan_manager.h:100
struct timeval elapsed_lookup
Definition: scan_manager.h:319
static int scan_get_index_oidset(THREAD_ENTRY *thread_p, SCAN_ID *s_id, DB_BIGINT *key_limit_upper, DB_BIGINT *key_limit_lower)
SCAN_POSITION position
Definition: scan_manager.h:299
static SCAN_CODE scan_next_heap_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
DB_VALUE key1
Definition: access_spec.hpp:58
DB_MIDXKEY midxkey
Definition: dbtype_def.h:1065
int db_get_string_length(const DB_VALUE *value)
void heap_attrinfo_end(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9979
QPROC_SINGLE_FETCH single_fetch
Definition: scan_manager.h:343
short volid
Definition: dbtype_def.h:887
int method_close_scan(THREAD_ENTRY *thread_p, METHOD_SCAN_BUFFER *scan_buffer_p)
Definition: method_scan.c:202
static int merge_key_ranges(KEY_VAL_RANGE *key_vals, int key_cnt)
static int scan_key_compare(DB_VALUE *val1, DB_VALUE *val2, int num_index_term)
SCAN_CODE scan_next_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
DB_VALUE ** arg_values
Definition: scan_manager.h:261
static SCAN_CODE call_get_next_index_oidset(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, INDX_SCAN_ID *isidp, bool should_go_to_next_value)
union cubxasl::eval_term::@184 et
#define OID_ISNULL(oidp)
Definition: oid.h:81
JSON_TABLE_SCAN_ID jtid
Definition: scan_manager.h:362
static SCAN_CODE scan_next_list_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
SCAN_CODE heap_next(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *next_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking)
Definition: heap_file.c:18622
int tp_domain_match_ignore_order(const TP_DOMAIN *dom1, const TP_DOMAIN *dom2, TP_MATCH exact)
INDX_SCAN_ID isid
Definition: scan_manager.h:356
SET_SCAN_ID ssid
Definition: scan_manager.h:358
int heap_get_indexinfo_of_btid(THREAD_ENTRY *thread_p, const OID *class_oid, const BTID *btid, BTREE_TYPE *type, int *num_attrs, ATTR_ID **attr_ids, int **attrs_prefix_length, char **btnamepp, int *func_index_col_id)
Definition: heap_file.c:13134
#define ER_QPROC_INVALID_DATATYPE
Definition: error_code.h:534
PAGE_PTR pgptr
Definition: page_buffer.h:222
ISS_OP_TYPE current_op
Definition: scan_manager.h:181
static int key_val_compare(const void *p1, const void *p2)
ATTR_ID * vstr_ids
Definition: scan_manager.h:193
#define pgbuf_ordered_unfix(thread_p, watcher_object)
Definition: page_buffer.h:280
QUERY_ID query_id
Definition: scan_manager.h:133
static SCAN_CODE scan_handle_single_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id, QP_SCAN_FUNC next_scan)
TP_DOMAIN * key_type
Definition: btree.h:124
BTREE_ISCAN_OID_LIST * oid_list
Definition: scan_manager.h:201
SCAN_CODE btree_get_next_key_info(THREAD_ENTRY *thread_p, BTID *btid, BTREE_SCAN *bts, int num_classes, OID *class_oids_ptr, INDX_SCAN_ID *index_scan_id_p, DB_VALUE **key_info)
Definition: btree.c:16115
RANGE
Definition: access_spec.hpp:32
#define TP_IS_BIT_TYPE(typeid)
int heap_get_class_name(THREAD_ENTRY *thread_p, const OID *class_oid, char **class_name)
Definition: heap_file.c:9328
#define PEEK
Definition: file_io.h:74
SCAN_CODE showstmt_next_scan(THREAD_ENTRY *thread_p, SCAN_ID *s_id)
Definition: show_scan.c:250
TP_DOMAIN * domain
Definition: regu_var.hpp:175
DB_VALUE key2
Definition: access_spec.hpp:59
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
int qdata_build_hscan_key(THREAD_ENTRY *thread_p, val_descr *vd, REGU_VARIABLE_LIST regu_list, HASH_SCAN_KEY *key)
REGU_VARIABLE_LIST valptrp
Definition: regu_var.hpp:116
static SCAN_CODE scan_next_showstmt_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
char * buf
Definition: dbtype_def.h:866
static int scan_restore_range_details(ISS_RANGE_DETAILS *rdp_src, INDX_SCAN_ID *isidp_dest)
Definition: scan_manager.c:341
int scan_open_heap_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, bool mvcc_select_lock_needed, SCAN_OPERATION_TYPE scan_op_type, int fixed, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE *join_dbval, val_list_node *val_list, VAL_DESCR *vd, OID *cls_oid, HFID *hfid, regu_variable_list_node *regu_list_pred, PRED_EXPR *pr, regu_variable_list_node *regu_list_rest, int num_attrs_pred, ATTR_ID *attrids_pred, HEAP_CACHE_ATTRINFO *cache_pred, int num_attrs_rest, ATTR_ID *attrids_rest, HEAP_CACHE_ATTRINFO *cache_rest, SCAN_TYPE scan_type, DB_VALUE **cache_recordinfo, regu_variable_list_node *regu_list_recordinfo)
ROP_TYPE
Definition: scan_manager.c:94
regu_variable_list_node * node_info_regu_list
Definition: scan_manager.h:243
DB_VALUE ** out_values
Definition: scan_manager.h:263
static SCAN_CODE scan_build_hash_list_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
static SCAN_CODE scan_next_set_scan(THREAD_ENTRY *thread_p, SCAN_ID *scan_id)
#define qmgr_free_old_page_and_init(thread_p, page_p, tfile_vfidp)
Definition: query_manager.h:42
SCAN_ATTRS rest_attrs
Definition: scan_manager.h:104
const char ** p
Definition: dynamic_load.c:945
QFILE_LIST_ID * list_id
Definition: scan_manager.h:126
struct timeval elapsed_scan
Definition: scan_manager.h:306
void tp_domain_free(TP_DOMAIN *dom)
static SCAN_CODE scan_get_next_iss_value(THREAD_ENTRY *thread_p, SCAN_ID *scan_id, INDX_SCAN_ID *isidp)
Definition: scan_manager.c:384
static int scan_init_multi_range_optimization(THREAD_ENTRY *thread_p, MULTI_RANGE_OPT *multi_range_opt, bool use_range_opt, int max_size)
int method_open_scan(THREAD_ENTRY *thread_p, METHOD_SCAN_BUFFER *scan_buffer_p, qfile_list_id *list_id_p, method_sig_list *method_sig_list_p)
Definition: method_scan.c:169
struct db_char::@54 medium
VAL_DESCR * val_descr
DB_VALUE_COMPARE_RESULT pr_midxkey_compare(DB_MIDXKEY *mul1, DB_MIDXKEY *mul2, int do_coercion, int total_order, int num_index_term, int *start_colp, int *result_size1, int *result_size2, int *diff_column, bool *dom_is_desc, bool *next_dom_is_desc)
#define HEAP_ISVALID_OID(thread_p, oid)
Definition: heap_file.h:77
#define BTREE_INIT_SCAN(bts)
Definition: btree.h:253
static HASH_METHOD check_hash_list_scan(LLIST_SCAN_ID *llsidp, int *val_cnt, int hash_list_scan_yn)
#define TP_DOMAIN_COLLATION_FLAG(dom)
SCAN_CODE heap_prev_record_info(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *next_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking, DB_VALUE **cache_recordinfo)
Definition: heap_file.c:18697
SCAN_CODE heap_page_next(THREAD_ENTRY *thread_p, const OID *class_oid, const HFID *hfid, VPID *next_vpid, DB_VALUE **cache_pageinfo)
Definition: heap_file.c:18305
SCAN_PRED scan_pred
Definition: scan_manager.h:251
QFILE_TUPLE tuple
regu_variable_node * key_limit_l
Definition: access_spec.hpp:80